From 5469ba1d49df7c8371022b11eb7f08f217638943 Mon Sep 17 00:00:00 2001
From: Vincent Dupont <vincent@otakeys.com>
Date: Wed, 23 Nov 2016 19:02:02 +0100
Subject: [PATCH] can: add CAN stack

The CAN stack support only raw CAN at this time.
It contains a device interface (drivers/include/can/candev.h) and the data link
layer, build around can/device.c can/pkt.c and can/router.c. can/dll.c contains
the upper level and lower level interface to send and receive CAN frames.
Upper layer interface is located in include/can/raw.h
---
 Makefile.dep                   |  10 +-
 drivers/include/can/candev.h   | 182 +++++++++++
 makefiles/pseudomodules.inc.mk |   3 +
 sys/can/Makefile               |   1 +
 sys/can/device.c               | 563 +++++++++++++++++++++++++++++++++
 sys/can/dll.c                  | 504 +++++++++++++++++++++++++++++
 sys/can/pkt.c                  | 163 ++++++++++
 sys/can/router.c               | 400 +++++++++++++++++++++++
 sys/include/can/can.h          | 149 +++++++++
 sys/include/can/common.h       | 162 ++++++++++
 sys/include/can/device.h       | 113 +++++++
 sys/include/can/dll.h          | 110 +++++++
 sys/include/can/doc.txt        |  23 ++
 sys/include/can/pkt.h          | 152 +++++++++
 sys/include/can/raw.h          | 261 +++++++++++++++
 sys/include/can/router.h       | 116 +++++++
 16 files changed, 2911 insertions(+), 1 deletion(-)
 create mode 100644 drivers/include/can/candev.h
 create mode 100644 sys/can/Makefile
 create mode 100644 sys/can/device.c
 create mode 100644 sys/can/dll.c
 create mode 100644 sys/can/pkt.c
 create mode 100644 sys/can/router.c
 create mode 100644 sys/include/can/can.h
 create mode 100644 sys/include/can/common.h
 create mode 100644 sys/include/can/device.h
 create mode 100644 sys/include/can/dll.h
 create mode 100644 sys/include/can/doc.txt
 create mode 100644 sys/include/can/pkt.h
 create mode 100644 sys/include/can/raw.h
 create mode 100644 sys/include/can/router.h

diff --git a/Makefile.dep b/Makefile.dep
index 949924ec72..a49ef30358 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -56,7 +56,7 @@ ifneq (,$(filter nordic_softdevice_ble,$(USEPKG)))
   USEMODULE += gnrc_ipv6_netif
 endif
 
-ifneq (,$(filter gnrc_%,$(filter-out gnrc_netapi gnrc_netreg gnrc_netif% gnrc_pktbuf,$(USEMODULE))))
+ifneq (,$(filter gnrc_%,$(filter-out gnrc_netapi gnrc_netreg gnrc_netif% gnrc_pkt%,$(USEMODULE))))
   USEMODULE += gnrc
 endif
 
@@ -566,6 +566,14 @@ ifneq (,$(filter evtimer,$(USEMODULE)))
   USEMODULE += xtimer
 endif
 
+ifneq (,$(filter can,$(USEMODULE)))
+  USEMODULE += can_raw
+  ifneq (,$(filter can_mbox,$(USEMODULE)))
+    USEMODULE += core_mbox
+  endif
+  USEMODULE += gnrc_pktbuf_static
+endif
+
 ifneq (,$(filter random,$(USEMODULE)))
   # select default prng
   ifeq (,$(filter prng_%,$(USEMODULE)))
diff --git a/drivers/include/can/candev.h b/drivers/include/can/candev.h
new file mode 100644
index 0000000000..5b6b66775c
--- /dev/null
+++ b/drivers/include/can/candev.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2016 OTA keys S.A.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for
+ * more details.
+ */
+
+/**
+ * @ingroup     can
+ * @ingroup     drivers
+ * @defgroup    drivers_can CAN drivers
+ * @{
+ *
+ * This is the CAN controller driver interface
+ *
+ * @file
+ * @brief       Definitions low-level CAN driver interface
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ * @author      Toon Stegen <toon.stegen@altran.com>
+ */
+
+#ifndef CAN_CANDEV_H
+#define CAN_CANDEV_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "can/can.h"
+#include "can/common.h"
+#include "mutex.h"
+
+
+/**
+ * @brief   Possible event types that are send from the device driver to the
+ *          upper layer
+ */
+typedef enum {
+    CANDEV_EVENT_NOEVENT,          /**< no event, used internally */
+    CANDEV_EVENT_ISR,              /**< driver needs it's ISR handled */
+    CANDEV_EVENT_WAKE_UP,          /**< driver has been woken up by bus */
+    CANDEV_EVENT_TX_CONFIRMATION,  /**< a packet has been sent */
+    CANDEV_EVENT_TIMEOUT_TX_CONF,  /**< tx conf timeout received */
+    CANDEV_EVENT_RX_INDICATION,    /**< a packet has been received */
+    CANDEV_EVENT_TX_ERROR,         /**< there was an error when transmitting */
+    CANDEV_EVENT_RX_ERROR,         /**< there was an error when receiving */
+    CANDEV_EVENT_BUS_OFF,          /**< bus-off detected */
+    CANDEV_EVENT_ERROR_PASSIVE,    /**< driver switched in error passive */
+    CANDEV_EVENT_ERROR_WARNING,    /**< driver reached error warning */
+    /* expand this list if needed */
+} candev_event_t;
+
+/**
+ * @brief   Forward declaration for candev struct
+ */
+typedef struct candev candev_t;
+
+/**
+ * @brief   Event callback for signaling event to upper layers
+ *
+ * @param[in] dev           CAN device descriptor
+ * @param[in] type          type of the event
+ * @param[in] arg           event argument
+ */
+typedef void (*candev_event_cb_t)(candev_t *dev, candev_event_t event, void *arg);
+
+/**
+ * @brief Structure to hold driver state
+ *
+ * Supposed to be extended by driver implementations.
+ * The extended structure should contain all variable driver state.
+ */
+struct candev {
+    const struct candev_driver *driver;    /**< ptr to that driver's interface. */
+    candev_event_cb_t event_callback;      /**< callback for device events */
+    void *isr_arg;                         /**< argument to pass on isr event */
+    struct can_bittiming bittiming;        /**< device bittimings */
+    enum can_state state;                  /**< device state */
+};
+
+/**
+ * @brief Structure to hold driver interface -> function mapping
+ */
+typedef struct candev_driver {
+    /**
+     * @brief Send packet
+     *
+     * @param[in] dev       CAN device descriptor
+     * @param[in] frame     CAN frame to send
+     *
+     * @return < 0 on error
+     * @return mailbox id >= 0 if OK
+     */
+    int (*send)(candev_t *dev, const struct can_frame *frame);
+
+    /**
+     * @brief Abort a packet sending
+     *
+     * @param[in] dev       CAN device descriptor
+     * @param[in] frame     CAN frame to abort
+     *
+     * @return < 0 on error
+     * @return 0 on OK
+     */
+    int (*abort)(candev_t *dev, const struct can_frame *frame);
+
+    /**
+     * @brief the driver's initialization function
+     *
+     * @param[in] dev       CAN device descriptor
+     *
+     * @return < 0 on error, 0 on success
+     */
+    int (*init)(candev_t *dev);
+
+    /**
+     * @brief a driver's user-space ISR handler
+     *
+     * @param[in] dev       CAN device descriptor
+     */
+    void (*isr)(candev_t *dev);
+
+    /**
+     * @brief   Get an option value from a given CAN device
+     *
+     * @param[in]   dev     CAN device descriptor
+     * @param[in]   opt     option type
+     * @param[out]  value   pointer to store the option's value in
+     * @param[in]   max_len maximal amount of byte that fit into @p value
+     *
+     * @return              number of bytes written to @p value
+     * @return              <0 on error
+     */
+    int (*get)(candev_t *dev, canopt_t opt, void *value, size_t max_len);
+
+    /**
+     * @brief   Set an option value for a given CAN device
+     *
+     * @param[in] dev       CAN device descriptor
+     * @param[in] opt       option type
+     * @param[in] value     value to set
+     * @param[in] value_len the length of @p value
+     *
+     * @return              number of bytes used from @p value
+     * @return              <0 on error
+     */
+    int (*set)(candev_t *dev, canopt_t opt, void *value, size_t value_len);
+
+    /**
+     * @brief   Set a receive @p filter
+     *
+     * @param[in] dev       CAN device descriptor
+     * @param[in] filter    filter to set
+     *
+     * @return              a positive filter number
+     * @return              <0 on error
+     */
+    int (*set_filter)(candev_t *dev, const struct can_filter *filter);
+
+    /**
+     * @brief  Remove a @p filter
+     *
+     * @param[in] dev       CAN device descriptor
+     * @param[in] filter    filter to remove
+     *
+     * @return              0 on success
+     * @return              <0 on error
+     */
+    int (*remove_filter)(candev_t *dev, const struct can_filter *filter);
+} candev_driver_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CAN_CANDEV_H */
+/** @} */
diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk
index 29cad6e389..003fad8198 100644
--- a/makefiles/pseudomodules.inc.mk
+++ b/makefiles/pseudomodules.inc.mk
@@ -1,4 +1,7 @@
 PSEUDOMODULES += auto_init_gnrc_rpl
+PSEUDOMODULES += can_mbox
+PSEUDOMODULES += can_pm
+PSEUDOMODULES += can_raw
 PSEUDOMODULES += core_%
 PSEUDOMODULES += emb6_router
 PSEUDOMODULES += gnrc_ipv6_default
diff --git a/sys/can/Makefile b/sys/can/Makefile
new file mode 100644
index 0000000000..48422e909a
--- /dev/null
+++ b/sys/can/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/can/device.c b/sys/can/device.c
new file mode 100644
index 0000000000..eab6b7a056
--- /dev/null
+++ b/sys/can/device.c
@@ -0,0 +1,563 @@
+/*
+ * Copyright (C) 2016 OTA keys S.A.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @file
+ * @brief       CAN device interface
+ *
+ * @author      Toon Stegen <toon.stegen@altran.com>
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ * @author      Aurelien Gonce <aurelien.gonce@altran.com>
+ */
+
+#include <errno.h>
+
+#include "thread.h"
+#include "can/device.h"
+#include "can/common.h"
+#include "can/pkt.h"
+#include "can/dll.h"
+
+#define ENABLE_DEBUG    (0)
+#include "debug.h"
+
+#ifndef CAN_DEVICE_MSG_QUEUE_SIZE
+#define CAN_DEVICE_MSG_QUEUE_SIZE 64
+#endif
+
+#ifdef MODULE_CAN_PM
+#define CAN_DEVICE_PM_DEFAULT_RX_TIMEOUT (10 * US_PER_SEC)
+#define CAN_DEVICE_PM_DEFAULT_TX_TIMEOUT (2 * US_PER_SEC)
+#endif
+
+static int power_up(candev_dev_t *candev_dev);
+static int power_down(candev_dev_t *candev_dev);
+#ifdef MODULE_CAN_PM
+static void pm_cb(void *arg);
+static void pm_reset(candev_dev_t *candev_dev, uint32_t value);
+#endif
+
+static inline enum can_msg _can_event_error_to_msg(candev_event_t error)
+{
+    switch (error) {
+    case CANDEV_EVENT_TX_ERROR:
+        return CAN_MSG_TX_ERROR;
+    case CANDEV_EVENT_RX_ERROR:
+        return CAN_MSG_RX_ERROR;
+    case CANDEV_EVENT_BUS_OFF:
+        return CAN_MSG_BUS_OFF;
+    case CANDEV_EVENT_ERROR_PASSIVE:
+        return CAN_MSG_ERROR_PASSIVE;
+    case CANDEV_EVENT_ERROR_WARNING:
+        return CAN_MSG_ERROR_WARNING;
+    default:
+        return 0;
+    }
+}
+
+static void _can_event(candev_t *dev, candev_event_t event, void *arg)
+{
+    msg_t msg;
+    struct can_frame *frame;
+    can_pkt_t *pkt;
+    candev_dev_t *candev_dev = dev->isr_arg;
+
+    DEBUG("_can_event: dev=%p, params=%p\n", (void*)dev, (void*)candev_dev);
+    DEBUG("_can_event: params->ifnum=%d, params->pid=%" PRIkernel_pid ", params->dev=%p\n",
+          candev_dev->ifnum, candev_dev->pid, (void*)candev_dev->dev);
+
+    switch (event) {
+    case CANDEV_EVENT_ISR:
+        DEBUG("_can_event: CANDEV_EVENT_ISR\n");
+        msg.type = CAN_MSG_EVENT;
+        if (msg_send(&msg, candev_dev->pid) <= 0) {
+            DEBUG("can device: isr lost\n");
+        }
+        break;
+    case CANDEV_EVENT_WAKE_UP:
+        DEBUG("_can_event: CANDEV_EVENT_WAKE_UP\n");
+        power_up(candev_dev);
+#ifdef MODULE_CAN_PM
+        pm_reset(candev_dev, candev_dev->rx_inactivity_timeout);
+#endif
+        break;
+    case CANDEV_EVENT_TX_CONFIRMATION:
+        DEBUG("_can_event: CANDEV_EVENT_TX_CONFIRMATION\n");
+        /* frame pointer in arg */
+        pkt = container_of((struct can_frame *)arg, can_pkt_t, frame);
+        can_dll_dispatch_tx_conf(pkt);
+        break;
+    case CANDEV_EVENT_TX_ERROR:
+        DEBUG("_can_event: CANDEV_EVENT_TX_ERROR\n");
+        /* frame pointer in arg */
+        pkt = container_of((struct can_frame *)arg, can_pkt_t, frame);
+        can_dll_dispatch_tx_error(pkt);
+        break;
+    case CANDEV_EVENT_RX_INDICATION:
+        DEBUG("_can_event: CANDEV_EVENT_RX_INDICATION\n");
+#ifdef MODULE_CAN_PM
+        pm_reset(candev_dev, candev_dev->rx_inactivity_timeout);
+#endif
+        /* received frame in arg */
+        frame = (struct can_frame *) arg;
+        can_dll_dispatch_rx_frame(frame, candev_dev->pid);
+        break;
+    case CANDEV_EVENT_RX_ERROR:
+        DEBUG("_can_event: CANDEV_EVENT_RX_ERROR\n");
+        break;
+    case CANDEV_EVENT_BUS_OFF:
+        dev->state = CAN_STATE_BUS_OFF;
+        break;
+    case CANDEV_EVENT_ERROR_PASSIVE:
+        dev->state = CAN_STATE_ERROR_PASSIVE;
+        break;
+    case CANDEV_EVENT_ERROR_WARNING:
+        dev->state = CAN_STATE_ERROR_WARNING;
+        break;
+    default:
+        DEBUG("_can_event: unknown event\n");
+        break;
+    }
+}
+
+static int power_up(candev_dev_t *candev_dev)
+{
+    candev_t *dev = candev_dev->dev;
+
+    DEBUG("candev: power up\n");
+
+    canopt_state_t state = CANOPT_STATE_ON;
+    int res = dev->driver->set(dev, CANOPT_STATE, &state, sizeof(state));
+    dev->state = CAN_STATE_ERROR_ACTIVE;
+
+    return res;
+}
+
+static int power_down(candev_dev_t *candev_dev)
+{
+    candev_t *dev = candev_dev->dev;
+
+    DEBUG("candev: power down\n");
+
+    canopt_state_t state = CANOPT_STATE_SLEEP;
+    int res = dev->driver->set(dev, CANOPT_STATE, &state, sizeof(state));
+    dev->state = CAN_STATE_SLEEPING;
+
+#ifdef MODULE_CAN_PM
+    xtimer_remove(&candev_dev->pm_timer);
+    candev_dev->last_pm_update = 0;
+#endif
+
+    return res;
+}
+
+#ifdef MODULE_CAN_PM
+static void pm_cb(void *arg)
+{
+    candev_dev_t *dev = arg;
+    msg_t msg;
+    msg.type = CAN_MSG_PM;
+
+    msg_send(&msg, dev->pid);
+}
+
+static void pm_reset(candev_dev_t *candev_dev, uint32_t value)
+{
+    DEBUG("pm_reset: dev=%p, value=%" PRIu32 ", last_pm_value=%" PRIu32
+          ", last_pm_update=%" PRIu32 "\n", (void *)candev_dev, value,
+          candev_dev->last_pm_value, candev_dev->last_pm_update);
+
+    if (value == 0) {
+        candev_dev->last_pm_value = 0;
+        xtimer_remove(&candev_dev->pm_timer);
+        return;
+    }
+
+    if (candev_dev->last_pm_update == 0 ||
+            value > (candev_dev->last_pm_value - (xtimer_now_usec() - candev_dev->last_pm_update))) {
+        candev_dev->last_pm_value = value;
+        candev_dev->last_pm_update = xtimer_now_usec();
+        xtimer_set(&candev_dev->pm_timer, value);
+    }
+}
+#endif
+
+static void *_can_device_thread(void *args)
+{
+    candev_dev_t *candev_dev = (candev_dev_t *) args;
+    candev_t *dev = candev_dev->dev;
+
+    DEBUG("_can_device_thread: starting thread for ifnum=%d, pid=%" PRIkernel_pid "\n",
+          candev_dev->ifnum, thread_getpid());
+    DEBUG("_cand_device_thread: dev=%p, params=%p\n", (void*)dev, (void*)candev_dev);
+
+    candev_dev->pid = thread_getpid();
+
+#ifdef MODULE_CAN_PM
+    if (candev_dev->rx_inactivity_timeout == 0) {
+        candev_dev->rx_inactivity_timeout = CAN_DEVICE_PM_DEFAULT_RX_TIMEOUT;
+    }
+    if (candev_dev->tx_wakeup_timeout == 0) {
+        candev_dev->tx_wakeup_timeout = CAN_DEVICE_PM_DEFAULT_TX_TIMEOUT;
+    }
+    candev_dev->pm_timer.callback = pm_cb;
+    candev_dev->pm_timer.arg = candev_dev;
+    pm_reset(candev_dev, candev_dev->rx_inactivity_timeout);
+#endif
+
+    int res;
+    can_pkt_t *pkt;
+    can_opt_t *opt;
+    msg_t msg, reply, msg_queue[CAN_DEVICE_MSG_QUEUE_SIZE];
+
+    /* setup the device layers message queue */
+    msg_init_queue(msg_queue, CAN_DEVICE_MSG_QUEUE_SIZE);
+
+    dev->event_callback = _can_event;
+    dev->isr_arg = candev_dev;
+
+    candev_dev->ifnum = can_dll_register_candev(candev_dev);
+
+    dev->driver->init(dev);
+    dev->state = CAN_STATE_ERROR_ACTIVE;
+
+    while (1) {
+        msg_receive(&msg);
+        switch (msg.type) {
+        case CAN_MSG_EVENT:
+            DEBUG("can device: CAN_MSG_EVENT received\n");
+            dev->driver->isr(dev);
+            break;
+        case CAN_MSG_ABORT_FRAME:
+            DEBUG("can device: CAN_MSG_ABORT_FRAME received\n");
+            pkt = (can_pkt_t *) msg.content.ptr;
+            dev->driver->abort(dev, &pkt->frame);
+            reply.type = CAN_MSG_ACK;
+            reply.content.value = 0;
+            msg_reply(&msg, &reply);
+            break;
+        case CAN_MSG_SEND_FRAME:
+            DEBUG("can device: CAN_MSG_SEND_FRAME received\n");
+            pkt = (can_pkt_t *) msg.content.ptr;
+            if (dev->state == CAN_STATE_BUS_OFF || dev->state == CAN_STATE_SLEEPING) {
+                DEBUG("can device: waking up driver\n");
+                power_up(candev_dev);
+            }
+#ifdef MODULE_CAN_PM
+            pm_reset(candev_dev, candev_dev->tx_wakeup_timeout);
+#endif
+            dev->driver->send(dev, &pkt->frame);
+            break;
+        case CAN_MSG_SET:
+            DEBUG("can device: CAN_MSG_SET received\n");
+            /* read incoming options */
+            opt = (can_opt_t *)msg.content.ptr;
+            /* set option for device driver */
+            res = dev->driver->set(dev, opt->opt, opt->data, opt->data_len);
+            /* send reply to calling thread */
+            reply.type = CAN_MSG_ACK;
+            reply.content.value = (uint32_t)res;
+            msg_reply(&msg, &reply);
+            break;
+        case CAN_MSG_GET:
+            DEBUG("can device: CAN_MSG_GET received\n");
+            /* read incoming options */
+            opt = (can_opt_t *)msg.content.ptr;
+            /* get option for device driver */
+            res = dev->driver->get(dev, opt->opt, opt->data, opt->data_len);
+            /* send reply to calling thread */
+            reply.type = CAN_MSG_ACK;
+            reply.content.value = (uint32_t)res;
+            msg_reply(&msg, &reply);
+            break;
+        case CAN_MSG_SET_FILTER:
+            DEBUG("can device: CAN_MSG_SET_FILTER received\n");
+            /* set filter for device driver */
+            res = dev->driver->set_filter(dev, msg.content.ptr);
+            /* send reply to calling thread */
+            reply.type = CAN_MSG_ACK;
+            reply.content.value = (uint32_t)res;
+            msg_reply(&msg, &reply);
+            break;
+        case CAN_MSG_REMOVE_FILTER:
+            DEBUG("can device: CAN_MSG_REMOVE_FILTER received\n");
+            /* set filter for device driver */
+            res = dev->driver->remove_filter(dev, msg.content.ptr);
+            /* send reply to calling thread */
+            reply.type = CAN_MSG_ACK;
+            reply.content.value = (uint32_t)res;
+            msg_reply(&msg, &reply);
+            break;
+        case CAN_MSG_POWER_UP:
+            DEBUG("can device: CAN_MSG_POWER_UP received\n");
+            res = power_up(candev_dev);
+#ifdef MODULE_CAN_PM
+            pm_reset(candev_dev, 0);
+#endif
+            /* send reply to calling thread */
+            reply.type = CAN_MSG_ACK;
+            reply.content.value = (uint32_t)res;
+            msg_reply(&msg, &reply);
+            break;
+        case CAN_MSG_POWER_DOWN:
+            DEBUG("can device: CAN_MSG_POWER_DOWN received\n");
+            res = power_down(candev_dev);
+            /* send reply to calling thread */
+            reply.type = CAN_MSG_ACK;
+            reply.content.value = (uint32_t)res;
+            msg_reply(&msg, &reply);
+            break;
+#ifdef MODULE_CAN_PM
+        case CAN_MSG_PM:
+            DEBUG("can device: pm power down\n");
+            power_down(candev_dev);
+            break;
+#endif
+        default:
+            break;
+        }
+    }
+
+    return NULL;
+}
+
+kernel_pid_t can_device_init(char *stack, int stacksize, char priority,
+                             const char *name, candev_dev_t *params)
+{
+    kernel_pid_t res;
+
+    /* check if given device is defined and the driver is set */
+    if (params == NULL || params->dev == NULL || params->dev->driver == NULL) {
+        return -ENODEV;
+    }
+
+    /* create new can device thread */
+    res = thread_create(stack, stacksize, priority, THREAD_CREATE_STACKTEST,
+                         _can_device_thread, (void *)params, name);
+    if (res <= 0) {
+        return -EINVAL;
+    }
+
+    return res;
+}
+
+
+#define SJW 2
+#define CAN_SYNC_SEG 1
+
+static inline uint32_t min(uint32_t x, uint32_t y)
+{
+    return x < y ? x : y;
+}
+
+static inline uint32_t max(uint32_t x, uint32_t y)
+{
+    return x > y ? x : y;
+}
+
+static inline uint32_t clamp(uint32_t val, uint32_t lo, uint32_t hi)
+{
+    return min(max(val, lo), hi);
+}
+
+/**
+ * @brief Compute tseg1 and tseg2 and returns the sample point
+ *
+ * tseg1 and tseg2 are calculated from the nominal sample point and tseg
+ *
+ * @param[in] btc          the bittiming const
+ * @param[in] spt_nominal  the nominal sample point
+ * @param[in] tseg         number of tq in the nbt minus the SYNC_SEG
+ * @param[out] p_tseg1     number of tq in tseg1 (PHASE_SEG_1 + PROP_SEG)
+ * @param[out] p_tseg2     number of tq in tseg2 (PHASE_SEG_2)
+ * @param[out] p_spt_error (optional) the sample point difference between @p spt_nominal
+ *                          and computed sample point from @p tseg1 and @p tseg2
+ *
+ * @return the computed sample point from @p tseg1 and @p tseg2
+ */
+static uint32_t update_sample_point(const struct can_bittiming_const *btc, uint32_t spt_nominal,
+                                    uint32_t tseg, uint32_t *p_tseg1, uint32_t *p_tseg2, uint32_t *p_spt_error)
+{
+    uint32_t best_spt = 0;
+    uint32_t min_spt_error = UINT32_MAX;
+
+    for (int i = 0; i <= 1; i++) {
+        uint32_t tseg1;
+        uint32_t tseg2;
+        uint32_t spt;
+        uint32_t spt_error;
+
+        tseg2 = tseg + CAN_SYNC_SEG - (spt_nominal * (tseg + CAN_SYNC_SEG)) / 1000 - i;
+        tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
+        tseg1 = tseg - tseg2;
+        if (tseg1 > btc->tseg1_max) {
+            tseg1 = btc->tseg1_max;
+            tseg2 = tseg - tseg1;
+        }
+
+        spt = 1000 * (tseg1 + CAN_SYNC_SEG) / (tseg + CAN_SYNC_SEG);
+        spt_error = max(spt, spt_nominal) - min(spt, spt_nominal);
+        if (spt <= spt_nominal && spt_error < min_spt_error) {
+            best_spt = spt;
+            min_spt_error = spt_error;
+            *p_tseg1 = tseg1;
+            *p_tseg2 = tseg2;
+        }
+
+        if (p_spt_error) {
+            *p_spt_error = min_spt_error;
+        }
+        DEBUG("tseg1=%" PRIu32 ", tseg2=%" PRIu32 ", spt_error=%" PRIu32 "\n",
+              tseg1, tseg2, spt_error);
+    }
+
+    return best_spt;
+}
+
+/*
+ *                   Nominal bit time (nbt) composed of 8 time quantum (tq)
+ * |<------------------------------------------------------------------------------------->|
+ * |                                                                                       |
+ * +----------+----------+-------------------------------------------+---------------------+
+ * | SYNC_SEG | PROP_SEG |                PHASE_SEG_1                |     PHASE_SEG_2     |
+ * +----------+----------+-------------------------------------------+---------------------+
+ * |                                                                 ^                     |
+ * |                                                    Sample point | at 75%              |
+ * |----------|----------|----------|----------|----------|----------|----------|----------|
+ * |   Time quanta                                                 6 | 2                   |
+ *
+ * Synchronization segment = always 1 tq
+ *                SYNC_SEG + PROP_SEG + PHASE_SEG1
+ * Sample point = --------------------------------
+ *                             nbt
+ *
+ * tseg1 = PROP_SEG + PHASE_SEG_1
+ * tseg2 = PHASE_SEG_2
+ * tseg = tseg1 + tseg2
+ * nbt = tseg + SYNC_SEG
+ *
+ */
+int can_device_calc_bittiming(uint32_t clock, const struct can_bittiming_const *timing_const,
+                              struct can_bittiming *timing)
+{
+    uint32_t spt; /* nominal sample point, in one-tenth of a percent */
+    uint32_t spt_error;
+    uint32_t min_spt_error = UINT32_MAX;
+    uint32_t best_brp = 0;
+    uint32_t tseg;
+    uint32_t tseg1;
+    uint32_t tseg2;
+    uint32_t best_tseg = 0;
+    uint32_t rate;        /* current bitrate */
+    uint32_t rate_error;
+    uint32_t min_rate_error;
+
+    assert((timing != NULL) && (timing->bitrate != 0));
+    assert(timing_const != NULL);
+
+    if (timing->sample_point) {
+        spt = timing->sample_point;
+    }
+    else {
+        /* Use recommended sample points */
+        /* See CiA 301 (https://www.can-cia.org/standardization/technical-documents/) */
+        /* 87.5% is recommended from 10kbit/s to 1Mbit/s */
+        spt = 875;
+    }
+    rate_error = min_rate_error = timing->bitrate;
+
+    DEBUG("init_bittiming: rate=%" PRIu32 ", clock=%" PRIu32 ", spt=%" PRIu32 "\n",
+          timing->bitrate, clock, timing->sample_point);
+
+    /* Starting from higher tq per nbt */
+    for (tseg = timing_const->tseg1_max + timing_const->tseg2_max;
+         tseg >= timing_const->tseg1_min + timing_const->tseg2_min; tseg--) {
+        uint32_t nbt = tseg + CAN_SYNC_SEG;
+
+        /* theoritical brp */
+        uint32_t brp = clock / (timing->bitrate * nbt);
+        /* brp according to brp_inc */
+        brp = (brp / timing_const->brp_inc) * timing_const->brp_inc;
+
+        DEBUG("tsegall=%" PRIu32 ", brp=%" PRIu32 "\n", nbt, brp);
+
+        if (brp < timing_const->brp_min || brp > timing_const->brp_max) {
+            /* Invalid brp */
+            DEBUG("invalid brp\n");
+            continue;
+        }
+
+        rate = clock / (brp * nbt);
+        rate_error = max(timing->bitrate, rate) - min(timing->bitrate, rate);
+        if (rate_error > min_rate_error) {
+            DEBUG("timing->rate=%" PRIu32 ", rate=%" PRIu32 ", rate_error=%" PRIu32 " > min_rate_error=%" PRIu32 ", continuing\n",
+                  timing->bitrate, rate, rate_error, min_rate_error);
+            continue;
+        }
+
+        if (rate_error < min_rate_error) {
+            min_spt_error = UINT32_MAX;
+        }
+
+        update_sample_point(timing_const, spt, tseg, &tseg1, &tseg2, &spt_error);
+        if (spt_error > min_spt_error) {
+            DEBUG("spt_error=%" PRIu32 " > min_spt_error=%" PRIu32 ", continuing\n",
+                  spt_error, min_spt_error);
+            continue;
+        }
+
+        min_spt_error = spt_error;
+        min_rate_error = rate_error;
+        best_tseg = tseg;
+        best_brp = brp;
+
+        DEBUG("rate_error=%" PRIu32 ", spt_error=%" PRIu32 "\n", rate_error, spt_error);
+
+        if (rate_error == 0 && spt_error == 0) {
+            break;
+        }
+    }
+
+    DEBUG("computed values: min_rate_error=%" PRIu32 ", min_spt_error=%" PRIu32 "\n", min_rate_error, min_spt_error);
+
+    if (min_rate_error) {
+        rate_error = min_rate_error * 1000 / timing->bitrate;
+        if (rate_error > CAN_MAX_RATE_ERROR) {
+            return -1;
+        }
+    }
+
+    timing->sample_point = update_sample_point(timing_const, spt,
+                                               best_tseg, &tseg1, &tseg2, NULL);
+
+    timing->prop_seg = tseg1 / 2;
+    timing->phase_seg1 = tseg1 - timing->prop_seg;
+    timing->phase_seg2 = tseg2;
+
+    if (!timing->sjw || !timing_const->sjw_max) {
+        timing->sjw = SJW;
+    }
+    else {
+        if (timing->sjw > timing_const->sjw_max) {
+            timing->sjw = timing_const->sjw_max;
+        }
+        if (timing->sjw > tseg2) {
+            timing->sjw = tseg2;
+        }
+    }
+
+    timing->brp = best_brp;
+
+    timing->bitrate = clock / (timing->brp * (CAN_SYNC_SEG + tseg1 + tseg2));
+
+    DEBUG("bitrate=%" PRIu32 ", sample_point=%" PRIu32 ", brp=%" PRIu32 ", prop_seg=%" PRIu32
+          ", phase_seg1=%" PRIu32 ", phase_seg2=%" PRIu32 "\n", timing->bitrate, timing->sample_point,
+          timing->brp, timing->prop_seg, timing->phase_seg1, timing->phase_seg2);
+
+    return 0;
+}
diff --git a/sys/can/dll.c b/sys/can/dll.c
new file mode 100644
index 0000000000..0287863d65
--- /dev/null
+++ b/sys/can/dll.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2016 OTA keys S.A.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @file
+ * @brief       CAN Data Link Layer module
+ *
+ * This module contains the DLL interfaces for upper layer (raw_can_*)
+ * and devices (can_dll_*).
+ * It manages the connection between an device number and its candev thread.
+ *
+ *
+ * @author      Toon Stegen <toon.stegen@altran.com>
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ * @author      Aurelien Gonce <aurelien.gonce@altran.com>
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "thread.h"
+#include "can/dll.h"
+#include "can/raw.h"
+#include "can/device.h"
+#include "can/pkt.h"
+#include "can/common.h"
+#include "can/router.h"
+#include "utlist.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+static candev_dev_t *candev_list[CAN_DLL_NUMOF];
+static int candev_nb = 0;
+static can_reg_entry_t *tx_list[CAN_DLL_NUMOF];
+static mutex_t tx_lock = MUTEX_INIT;
+
+static int _get_ifnum(kernel_pid_t pid)
+{
+    for (int i = 0; i < candev_nb; i++) {
+        if (candev_list[i]->pid == pid) {
+            return i;
+        }
+    }
+
+    return -ENODEV;
+}
+
+int _send_pkt(can_pkt_t *pkt)
+{
+    if (!pkt) {
+        return -ENOMEM;
+    }
+
+    msg_t msg;
+    int handle = pkt->handle;
+
+    mutex_lock(&tx_lock);
+    LL_APPEND(tx_list[pkt->entry.ifnum], &pkt->entry);
+    mutex_unlock(&tx_lock);
+
+    msg.type = CAN_MSG_SEND_FRAME;
+    msg.content.ptr = (void*) pkt;
+
+    if (msg_send(&msg, candev_list[pkt->entry.ifnum]->pid) <= 0) {
+        return -EOVERFLOW;
+    }
+
+    return handle;
+}
+
+int raw_can_send(int ifnum, const struct can_frame *frame, kernel_pid_t pid)
+{
+    can_pkt_t *pkt;
+
+    assert(frame);
+    assert(ifnum < candev_nb);
+
+    pkt = can_pkt_alloc_tx(ifnum, frame, pid);
+
+    DEBUG("raw_can_send: ifnum=%d, id=0x%" PRIx32 " from pid=%" PRIkernel_pid ", handle=%d\n",
+          ifnum, frame->can_id, pid, pkt->handle);
+
+    return _send_pkt(pkt);
+}
+
+#ifdef MODULE_CAN_MBOX
+int raw_can_send_mbox(int ifnum, const struct can_frame *frame, mbox_t *mbox)
+{
+    can_pkt_t *pkt;
+
+    assert(frame);
+    assert(ifnum < candev_nb);
+
+    pkt = can_pkt_alloc_mbox_tx(ifnum, frame, mbox);
+
+    DEBUG("raw_can_send: ifnum=%d, id=0x%" PRIx32 ", handle=%d\n", ifnum, frame->can_id, pkt->handle);
+
+    return _send_pkt(pkt);
+}
+#endif
+
+int raw_can_abort(int ifnum, int handle)
+{
+    msg_t msg, reply;
+    can_pkt_t *pkt = NULL;
+    can_reg_entry_t *entry;
+
+    assert(ifnum < candev_nb);
+
+    DEBUG("raw_can_abort: ifnum=%u, handle=%d\n", ifnum, handle);
+
+    mutex_lock(&tx_lock);
+    LL_FOREACH(tx_list[ifnum], entry) {
+        pkt = container_of(entry, can_pkt_t, entry);
+        if (pkt->handle == handle) {
+            break;
+        }
+    }
+
+    LL_DELETE(tx_list[ifnum], entry);
+    mutex_unlock(&tx_lock);
+
+    if (pkt == NULL) {
+        DEBUG("raw_can_abort: no pkt\n");
+        return -ENODEV;
+    }
+
+    msg.type = CAN_MSG_ABORT_FRAME;
+    msg.content.ptr = pkt;
+
+    msg_send_receive(&msg, &reply, candev_list[ifnum]->pid);
+
+    can_pkt_free(pkt);
+
+    return 0;
+}
+
+static int register_filter_entry(can_reg_entry_t *entry, struct can_filter *filter, void *param)
+{
+    msg_t msg, reply;
+    int ret;
+
+    DEBUG("register_filter_entry: ifnum=%d, filter=0x%" PRIx32 ", mask=0x%" PRIx32 ", param=%p\n",
+          entry->ifnum, filter->can_id, filter->can_mask, param);
+
+    ret = can_router_register(entry, filter->can_id, filter->can_mask, param);
+    if (ret < 0) {
+        return -ENOMEM;
+    }
+    else if (ret == 1) {
+        DEBUG("raw_can_subscribe_rx: filter=0x%" PRIx32 " already in use\n", filter->can_id);
+        return 0;
+    }
+
+    msg.type = CAN_MSG_SET_FILTER;
+    msg.content.ptr = filter;
+    msg_send_receive(&msg, &reply, candev_list[entry->ifnum]->pid);
+
+    if ((int) reply.content.value < 0) {
+        can_router_unregister(entry, filter->can_id, filter->can_mask, param);
+        return -ENOMEM;
+    }
+
+    return 0;
+}
+
+static int unregister_filter_entry(can_reg_entry_t *entry, struct can_filter *filter, void *param)
+{
+    msg_t msg, reply;
+    int ret;
+
+    DEBUG("unregister_filter_entry: ifnum=%d, filter=0x%" PRIx32 ", mask=0x%" PRIx32 ", param=%p\n",
+          entry->ifnum, filter->can_id, filter->can_mask, param);
+
+    ret = can_router_unregister(entry, filter->can_id, filter->can_mask, param);
+    if (ret < 0) {
+        return -ENOMEM;
+    }
+    else if (ret == 1) {
+        DEBUG("raw_can_unsubscribe_rx: filter=0x%" PRIx32 " still in use\n", filter->can_id);
+        return 0;
+    }
+
+    msg.type = CAN_MSG_REMOVE_FILTER;
+    msg.content.ptr = filter;
+    msg_send_receive(&msg, &reply, candev_list[entry->ifnum]->pid);
+
+    if ((int) reply.content.value < 0) {
+        return -ENOMEM;
+    }
+
+    return 0;
+}
+
+int raw_can_subscribe_rx(int ifnum, struct can_filter *filter, kernel_pid_t pid, void *param)
+{
+    assert(ifnum < candev_nb);
+    assert(filter);
+
+    can_reg_entry_t entry;
+    entry.ifnum = ifnum;
+    entry.target.pid = pid;
+#ifdef MODULE_CAN_MBOX
+    entry.type = CAN_TYPE_DEFAULT;
+#endif
+
+    return register_filter_entry(&entry, filter, param);
+}
+
+#ifdef MODULE_CAN_MBOX
+int raw_can_subscribe_rx_mbox(int ifnum, struct can_filter *filter, mbox_t *mbox, void *param)
+{
+    assert(ifnum < candev_nb);
+    assert(filter);
+
+    can_reg_entry_t entry;
+    entry.ifnum = ifnum;
+    entry.target.mbox = mbox;
+    entry.type = CAN_TYPE_MBOX;
+
+    return register_filter_entry(&entry, filter, param);
+}
+#endif
+
+int raw_can_unsubscribe_rx(int ifnum, struct can_filter *filter, kernel_pid_t pid, void *param)
+{
+    assert(ifnum < candev_nb);
+    assert(filter);
+
+    can_reg_entry_t entry;
+    entry.ifnum = ifnum;
+    entry.target.pid = pid;
+#ifdef MODULE_CAN_MBOX
+    entry.type = CAN_TYPE_DEFAULT;
+#endif
+
+    return unregister_filter_entry(&entry, filter, param);
+}
+
+#ifdef MODULE_CAN_MBOX
+int raw_can_unsubscribe_rx_mbox(int ifnum, struct can_filter *filter, mbox_t *mbox, void *param)
+{
+    assert(ifnum < candev_nb);
+    assert(filter);
+
+    can_reg_entry_t entry;
+    entry.ifnum = ifnum;
+    entry.target.mbox = mbox;
+    entry.type = CAN_TYPE_MBOX;
+
+    return unregister_filter_entry(&entry, filter, param);
+}
+#endif
+
+int raw_can_free_frame(can_rx_data_t *frame)
+{
+    int ret = can_router_free_frame((struct can_frame *)frame->data.iov_base);
+
+    can_pkt_free_rx_data(frame);
+
+    return ret;
+}
+
+int raw_can_get_can_opt(int ifnum, can_opt_t *opt)
+{
+    msg_t msg, reply;
+
+    assert(ifnum < CAN_DLL_NUMOF);
+
+    if (!opt) {
+        return -ENOMEM;
+    }
+
+    opt->context = (uint16_t)candev_list[ifnum]->pid;
+
+    msg.type = CAN_MSG_GET;
+    msg.content.ptr = (void *)opt;
+    if (msg_send_receive(&msg, &reply, opt->context) != 1) {
+        return -EBUSY;
+    }
+
+    return (int) reply.content.value;
+}
+
+int raw_can_set_can_opt(int ifnum, can_opt_t *opt)
+{
+    msg_t msg, reply;
+
+    assert(ifnum < CAN_DLL_NUMOF);
+
+    if (!opt) {
+        return -ENOMEM;
+    }
+
+    opt->context = (uint16_t)candev_list[ifnum]->pid;
+
+    msg.type = CAN_MSG_SET;
+    msg.content.ptr = (void *)opt;
+    if (msg_send_receive(&msg, &reply, opt->context) != 1) {
+        return -EBUSY;
+    }
+
+    return (int) reply.content.value;
+}
+
+int can_dll_register_candev(candev_dev_t *candev)
+{
+    if (candev_nb >= CAN_DLL_NUMOF) {
+        return -ENODEV;
+    }
+
+    DEBUG("can_dll_register_candev: candev=%p, ifnum=%d, pid=%" PRIkernel_pid "\n",
+          (void *)candev, candev_nb, candev->pid);
+
+    candev_list[candev_nb] = candev;
+
+    return candev_nb++;
+}
+
+int can_dll_dispatch_rx_frame(struct can_frame *frame, kernel_pid_t pid)
+{
+    can_pkt_t *pkt = can_pkt_alloc_rx(_get_ifnum(pid), frame);
+
+    return can_router_dispatch_rx_indic(pkt);
+}
+
+int can_dll_dispatch_tx_conf(can_pkt_t *pkt)
+{
+    DEBUG("can_dll_dispatch_tx_conf: pkt=0x%p\n", (void*)pkt);
+
+    can_router_dispatch_tx_conf(pkt);
+
+    mutex_lock(&tx_lock);
+    LL_DELETE(tx_list[pkt->entry.ifnum], &pkt->entry);
+    mutex_unlock(&tx_lock);
+
+    can_pkt_free(pkt);
+
+    return 0;
+}
+
+int can_dll_dispatch_tx_error(can_pkt_t *pkt)
+{
+    DEBUG("can_dll_dispatch_tx_error: pkt=0x%p\n", (void*)pkt);
+
+    can_router_dispatch_tx_error(pkt);
+
+    mutex_lock(&tx_lock);
+    LL_DELETE(tx_list[pkt->entry.ifnum], &pkt->entry);
+    mutex_unlock(&tx_lock);
+
+    can_pkt_free(pkt);
+
+    return 0;
+
+}
+
+int can_dll_dispatch_bus_off(kernel_pid_t pid)
+{
+    int ifnum = _get_ifnum(pid);
+    can_reg_entry_t *entry = tx_list[ifnum];
+
+    DEBUG("can_dll_dispatch_bus_off: ifnum=%d, pid=%" PRIkernel_pid "\n", ifnum, pid);
+
+    mutex_lock(&tx_lock);
+    while (entry) {
+        can_pkt_t *pkt = container_of(entry, can_pkt_t, entry);
+        can_router_dispatch_tx_error(pkt);
+        LL_DELETE(tx_list[ifnum], entry);
+        entry = tx_list[ifnum];
+    }
+    mutex_unlock(&tx_lock);
+
+    return 0;
+}
+
+int can_dll_init(void)
+{
+    can_pkt_init();
+
+    return 0;
+}
+
+int raw_can_power_down(int ifnum)
+{
+    msg_t msg, reply;
+
+    assert(ifnum < candev_nb);
+
+    msg.type = CAN_MSG_POWER_DOWN;
+    if (msg_send_receive(&msg, &reply, candev_list[ifnum]->pid) != 1) {
+        return -EBUSY;
+    }
+
+    return (int) reply.content.value;
+}
+
+int raw_can_power_up(int ifnum)
+{
+    msg_t msg, reply;
+
+    assert(ifnum < candev_nb);
+
+    msg.type = CAN_MSG_POWER_UP;
+    if (msg_send_receive(&msg, &reply, candev_list[ifnum]->pid) != 1) {
+        return -EBUSY;
+    }
+
+    return (int) reply.content.value;
+}
+
+int raw_can_set_bitrate(int ifnum, uint32_t bitrate, uint32_t sample_point)
+{
+    assert(ifnum < candev_nb);
+
+    int res = 0;
+    int ret;
+    uint32_t clock;
+    struct can_bittiming_const btc;
+    struct can_bittiming bittiming;
+    bittiming.bitrate = bitrate;
+    bittiming.sample_point = sample_point;
+
+    can_opt_t opt;
+    opt.opt = CANOPT_CLOCK;
+    opt.data = &clock;
+    opt.data_len = sizeof(clock);
+    ret = raw_can_get_can_opt(ifnum, &opt);
+    if (ret < 0) {
+        DEBUG("raw_can_set_bitrate: error when getting clock (%d)\n", ret);
+        return -1;
+    }
+    DEBUG("raw_can_set_bitrate: clock=%" PRIu32 " Hz\n", clock);
+
+    opt.opt = CANOPT_BITTIMING_CONST;
+    opt.data = &btc;
+    opt.data_len = sizeof(btc);
+    ret = raw_can_get_can_opt(ifnum, &opt);
+    if (ret < 0) {
+        DEBUG("raw_can_set_bitrate: error when getting const (%d)\n", ret);
+        return -1;
+    }
+
+    ret = can_device_calc_bittiming(clock, &btc, &bittiming);
+    if (ret < 0) {
+        DEBUG("raw_can_set_bitrate: bittiming might be wrong, ret=%d\n", ret);
+        res = 1;
+    }
+
+    opt.data = &bittiming;
+    opt.data_len = sizeof(bittiming);
+    opt.opt = CANOPT_BITTIMING;
+
+    ret = raw_can_set_can_opt(ifnum, &opt);
+    if (ret < 0) {
+        DEBUG("raw_can_set_bitrate: error when setting bitrate (%d)\n", ret);
+        return -1;
+    }
+
+    DEBUG("raw_can_set_bitrate: success bitrate=%" PRIu32 ", spt=%" PRIu32 "\n",
+          bittiming.bitrate, bittiming.sample_point);
+
+    return res;
+}
+
+int raw_can_get_ifnum_by_name(const char *name)
+{
+    for (int i = 0; i < candev_nb; i++) {
+        if ((strcmp(name, candev_list[i]->name) == 0) &&
+                (strlen(name) == strlen(candev_list[i]->name))) {
+            return i;
+        }
+    }
+
+    return RAW_CAN_DEV_UNDEF;
+}
+
+const char *raw_can_get_name_by_ifnum(int ifnum)
+{
+    assert(ifnum >= 0);
+
+    if (ifnum >= candev_nb) {
+        return NULL;
+    }
+
+    return candev_list[ifnum]->name;
+}
+
+candev_dev_t *raw_can_get_dev_by_ifnum(int ifnum)
+{
+    assert(ifnum >= 0);
+
+    if (ifnum >= candev_nb) {
+        return NULL;
+    }
+
+    return candev_list[ifnum];
+}
diff --git a/sys/can/pkt.c b/sys/can/pkt.c
new file mode 100644
index 0000000000..cf032e81c1
--- /dev/null
+++ b/sys/can/pkt.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2016 OTA keys S.A.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @file
+ * @brief       CAN memory allocation module
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ * @author      Toon Stegen <toon.stegen@altran.com>
+ */
+
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "net/gnrc/pktbuf.h"
+#include "can/pkt.h"
+#include "mutex.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+#define HANDLE_UNUSED 0
+
+static int handle;
+static mutex_t _mutex = MUTEX_INIT;
+
+void can_pkt_init(void)
+{
+    mutex_lock(&_mutex);
+    handle = 1;
+    mutex_unlock(&_mutex);
+}
+
+static can_pkt_t *_pkt_alloc(int ifnum, const struct can_frame *frame)
+{
+    can_pkt_t *pkt;
+
+    gnrc_pktsnip_t *snip = gnrc_pktbuf_add(NULL, NULL, sizeof(*pkt), GNRC_NETTYPE_UNDEF);
+    if (!snip) {
+        DEBUG("can_pkt_alloc: out of memory\n");
+        return NULL;
+    }
+
+    pkt = snip->data;
+    pkt->entry.ifnum = ifnum;
+    pkt->frame = *frame;
+    pkt->snip = snip;
+
+    DEBUG("can_pkt_alloc: pkt allocated\n");
+
+    return pkt;
+}
+
+static void _init_pkt(can_pkt_t *pkt, int tx)
+{
+    if (tx) {
+        mutex_lock(&_mutex);
+        pkt->handle = handle++;
+        if (handle == INT_MAX) {
+            handle = 1;
+        }
+        pkt->entry.next = NULL;
+        mutex_unlock(&_mutex);
+    }
+    else {
+        pkt->handle = 0;
+        atomic_store(&pkt->ref_count, 0);
+    }
+}
+
+can_pkt_t *can_pkt_alloc_tx(int ifnum, const struct can_frame *frame, kernel_pid_t tx_pid)
+{
+    can_pkt_t *pkt = _pkt_alloc(ifnum, frame);
+
+    if (!pkt) {
+        return NULL;
+    }
+
+    _init_pkt(pkt, 1);
+    pkt->entry.target.pid = tx_pid;
+#ifdef MODULE_CAN_MBOX
+    pkt->entry.type = CAN_TYPE_DEFAULT;
+#endif
+
+    return pkt;
+}
+
+can_pkt_t *can_pkt_alloc_rx(int ifnum, const struct can_frame *frame)
+{
+    can_pkt_t *pkt = _pkt_alloc(ifnum, frame);
+
+    if (!pkt) {
+        return NULL;
+    }
+
+    _init_pkt(pkt, 0);
+
+    return pkt;
+}
+
+#ifdef MODULE_CAN_MBOX
+can_pkt_t *can_pkt_alloc_mbox_tx(int ifnum, const struct can_frame *frame, mbox_t *tx_mbox)
+{
+    can_pkt_t *pkt = _pkt_alloc(ifnum, frame);
+
+    if (!pkt) {
+        return NULL;
+    }
+
+    _init_pkt(pkt, 1);
+    pkt->entry.target.mbox = tx_mbox;
+    pkt->entry.type = CAN_TYPE_MBOX;
+
+    return pkt;
+}
+#endif
+
+void can_pkt_free(can_pkt_t *pkt)
+{
+    if (!pkt) {
+        return;
+    }
+
+    DEBUG("can_pkt_free: free pkt=%p\n", (void*)pkt);
+
+    gnrc_pktbuf_release(pkt->snip);
+}
+
+can_rx_data_t *can_pkt_alloc_rx_data(void *data, size_t len, void *arg)
+{
+    can_rx_data_t *rx;
+
+    gnrc_pktsnip_t *snip = gnrc_pktbuf_add(NULL, NULL, sizeof(*rx), GNRC_NETTYPE_UNDEF);
+    if (!snip) {
+        DEBUG("can_pkt_alloc_rx_data: out of memory\n");
+        return NULL;
+    }
+
+    rx = snip->data;
+    DEBUG("can_pkt_alloc_rx_data: rx=%p\n", (void *)rx);
+
+    rx->data.iov_base = data;
+    rx->data.iov_len = len;
+    rx->arg = arg;
+    rx->snip = snip;
+
+    return rx;
+}
+
+void can_pkt_free_rx_data(can_rx_data_t *data)
+{
+    if (!data) {
+        return;
+    }
+
+    gnrc_pktbuf_release(data->snip);
+}
diff --git a/sys/can/router.c b/sys/can/router.c
new file mode 100644
index 0000000000..2471c33b37
--- /dev/null
+++ b/sys/can/router.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2016 OTA keys S.A.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ *
+ * @file
+ * @brief       Functions for routing RX can frames
+ *
+ * @author      Toon Stegen <toon.stegen@altran.com>
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ */
+
+#include <stdint.h>
+#include <errno.h>
+
+#include "kernel_defines.h"
+
+#include "net/gnrc/pktbuf.h"
+
+#include "can/router.h"
+#include "can/pkt.h"
+#include "can/device.h"
+#include "utlist.h"
+#include "mutex.h"
+#include "assert.h"
+
+#ifdef MODULE_CAN_MBOX
+#include "mbox.h"
+#endif
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+#if ENABLE_DEBUG
+#include <inttypes.h>
+#endif
+
+/**
+ * This is a can_id element
+ */
+typedef struct filter_el {
+    can_reg_entry_t entry;   /**< filter entry */
+    canid_t can_id;          /**< CAN ID of the element */
+    canid_t mask;            /**< Mask of the element */
+    void *data;              /**< Private data */
+    gnrc_pktsnip_t *snip;    /**< Pointer to the allocated snip */
+} filter_el_t;
+
+/**
+ * This table contains @p CAN_ROUTER_APP_MAX lists of CAN IDs per interface
+ */
+static can_reg_entry_t *table[CAN_DLL_NUMOF];
+
+
+static mutex_t lock = MUTEX_INIT;
+
+static filter_el_t *_alloc_filter_el(canid_t can_id, canid_t mask, void *data);
+static void _free_filter_el(filter_el_t *el);
+static void _insert_to_list(can_reg_entry_t **list, filter_el_t *el);
+static filter_el_t *_find_filter_el(can_reg_entry_t *list, can_reg_entry_t *entry, canid_t can_id, canid_t mask, void *data);
+static int _filter_is_used(unsigned int ifnum, canid_t can_id, canid_t mask);
+
+#if ENABLE_DEBUG
+static void _print_filters(void)
+{
+    for (int i = 0; i < (int)CAN_DLL_NUMOF; i++) {
+        DEBUG("--- Ifnum: %d ---\n", i);
+        can_reg_entry_t *entry;
+        LL_FOREACH(table[i], entry) {
+            filter_el_t *el = container_of(entry, filter_el_t, entry);
+            DEBUG("App pid=%" PRIkernel_pid ", el=%p, can_id=0x%" PRIx32 ", mask=0x%" PRIx32 ", data=%p\n",
+                  el->entry.target.pid, (void*)el, el->can_id, el->mask, el->data);
+        }
+    }
+}
+
+#define PRINT_FILTERS() _print_filters()
+#else
+#define PRINT_FILTERS()
+#endif
+
+static filter_el_t *_alloc_filter_el(canid_t can_id, canid_t mask, void *data)
+{
+    filter_el_t *el;
+    gnrc_pktsnip_t *snip = gnrc_pktbuf_add(NULL, NULL, sizeof(*el), GNRC_NETTYPE_UNDEF);
+    if (!snip) {
+        DEBUG("can_router: _alloc_canid_el: out of memory\n");
+        return NULL;
+    }
+
+    el = snip->data;
+    el->can_id = can_id;
+    el->mask = mask;
+    el->data = data;
+    el->entry.next = NULL;
+    el->snip = snip;
+    DEBUG("_alloc_canid_el: el allocated with can_id=0x%" PRIx32 ", mask=0x%" PRIx32
+          ", data=%p\n", can_id, mask, data);
+    return el;
+}
+
+static void _free_filter_el(filter_el_t *el)
+{
+    DEBUG("_free_canid_el: el freed with can_id=0x%" PRIx32 ", mask=0x%" PRIx32
+          ", data=%p\n", el->can_id, el->mask, el->data);
+
+    gnrc_pktbuf_release(el->snip);
+}
+
+/* Insert to the list in a sorted way
+ * Lower CAN IDs are inserted first */
+static void _insert_to_list(can_reg_entry_t **list, filter_el_t *el)
+{
+    can_reg_entry_t *next_entry = *list;
+    filter_el_t *next_el = container_of(next_entry, filter_el_t, entry);
+
+    DEBUG("_insert_to_list: list=%p, el=%p\n", (void *)list, (void *)el);
+
+    if (!(*list) || (next_el->can_id > el->can_id)) {
+        LL_PREPEND(*list, &el->entry);
+        DEBUG("_insert_to_list: inserting first el, list=%p\n", (void *)list);
+    }
+    else {
+        do {
+            if (el->can_id <= next_el->can_id) {
+                DEBUG("_insert_to_list: found next_el can_id:0x%" PRIx32
+                      "\n", next_el->can_id);
+                LL_PREPEND_ELEM(*list, next_entry, &el->entry);
+                return;
+            }
+            else if (next_el->entry.next == NULL) {
+                DEBUG("_insert_to_list: insert at the end\n");
+                LL_APPEND(next_entry, &el->entry);
+                return;
+            }
+            else {
+                next_entry = next_entry->next;
+                next_el = container_of(next_entry, filter_el_t, entry);
+                DEBUG("_insert_to_list: going to next el: %p\n", (void*) next_el);
+            }
+        } while (next_el);
+
+    }
+}
+
+#ifdef MODULE_CAN_MBOX
+#define ENTRY_MATCHES(e1, e2) (((e1)->type == (e2)->type) && \
+    (((e1)->type == CAN_TYPE_DEFAULT && (e1)->target.pid == (e2)->target.pid) ||\
+    ((e1)->type == CAN_TYPE_MBOX && (e1)->target.mbox == (e2)->target.mbox)))
+#else
+#define ENTRY_MATCHES(e1, e2)  ((e1)->target.pid == (e2)->target.pid)
+#endif
+
+static filter_el_t *_find_filter_el(can_reg_entry_t *list, can_reg_entry_t *entry, canid_t can_id, canid_t mask, void *data)
+{
+    filter_el_t *el = container_of(list, filter_el_t, entry);
+    if (!el) {
+        return el;
+    }
+    do {
+        if ((el->can_id == can_id) && (el->mask == mask) && (el->data == data) &&
+                ENTRY_MATCHES(&el->entry, entry)) {
+            DEBUG("_find_filter_el: found el=%p, can_id=%" PRIx32 ", mask=%" PRIx32 ", data=%p\n",
+                  (void *)el, el->can_id, el->mask, el->data);
+            return el;
+        }
+        el = container_of(el->entry.next, filter_el_t, entry);
+    }  while (el);
+
+    return NULL;
+}
+
+static int _filter_is_used(unsigned int ifnum, canid_t can_id, canid_t mask)
+{
+    filter_el_t *el = container_of(table[ifnum], filter_el_t, entry);
+    if (!el) {
+        DEBUG("_filter_is_used: empty list\n");
+        return 0;
+    }
+    do {
+        if ((el->can_id == can_id) && (el->mask == mask)) {
+            DEBUG("_filter_is_used: found el=%p, can_id=%" PRIx32 ", mask=%" PRIx32 ", data=%p\n",
+                  (void *)el, el->can_id, el->mask, el->data);
+            return 1;
+        }
+        el = container_of(el->entry.next, filter_el_t, entry);
+    }  while (el);
+
+    DEBUG("_filter_is_used: filter not found\n");
+
+    return 0;
+}
+
+/* register interested users */
+int can_router_register(can_reg_entry_t *entry, canid_t can_id, canid_t mask, void *param)
+{
+    filter_el_t *filter;
+    int ret;
+
+#if ENABLE_DEBUG
+    if (entry->type == CAN_TYPE_DEFAULT) {
+        DEBUG("can_router_register: ifnum=%d, pid=%" PRIkernel_pid ", can_id=0x%" PRIx32
+              ", mask=0x%" PRIx32 ", data=%p\n", entry->ifnum, entry->target.pid, can_id, mask, param);
+    } else if (entry->type == CAN_TYPE_MBOX) {
+        DEBUG("can_router_register: ifnum=%d, mbox=%p, can_id=0x%" PRIx32
+              ", mask=0x%" PRIx32 ", data=%p\n", entry->ifnum, (void *)entry->target.mbox, can_id, mask, param);
+    }
+#endif
+
+    mutex_lock(&lock);
+    ret = _filter_is_used(entry->ifnum, can_id, mask);
+
+    filter = _alloc_filter_el(can_id, mask, param);
+    if (!filter) {
+        mutex_unlock(&lock);
+        return -ENOMEM;
+    }
+
+#ifdef MODULE_CAN_MBOX
+    filter->entry.type = entry->type;
+    switch (entry->type) {
+    case CAN_TYPE_DEFAULT:
+        filter->entry.target.pid = entry->target.pid;
+        break;
+    case CAN_TYPE_MBOX:
+        filter->entry.target.mbox = entry->target.mbox;
+        break;
+    }
+
+#else
+    filter->entry.target.pid = entry->target.pid;
+#endif
+    filter->entry.ifnum = entry->ifnum;
+    _insert_to_list(&table[entry->ifnum], filter);
+    mutex_unlock(&lock);
+
+    PRINT_FILTERS();
+
+    return ret;
+}
+
+/* unregister interested users */
+int can_router_unregister(can_reg_entry_t *entry, canid_t can_id,
+                          canid_t mask, void *param)
+{
+    filter_el_t *el;
+    int ret;
+
+#if ENABLE_DEBUG
+    if (entry->type == CAN_TYPE_DEFAULT) {
+        DEBUG("can_router_unregister: ifnum=%d, pid=%" PRIkernel_pid ", can_id=0x%" PRIx32
+              ", mask=0x%" PRIx32 ", data=%p", entry->ifnum, entry->target.pid, can_id, mask, param);
+    } else if (entry->type == CAN_TYPE_MBOX) {
+        DEBUG("can_router_unregister: ifnum=%d, mbox=%p, can_id=0x%" PRIx32
+              ", mask=0x%" PRIx32 ", data=%p\n", entry->ifnum, (void *)entry->target.mbox, can_id, mask, param);
+    }
+#endif
+
+    mutex_lock(&lock);
+    el = _find_filter_el(table[entry->ifnum], entry, can_id, mask, param);
+    if (!el) {
+        mutex_unlock(&lock);
+        return -EINVAL;
+    }
+    LL_DELETE(table[entry->ifnum], &el->entry);
+    _free_filter_el(el);
+    ret = _filter_is_used(entry->ifnum, can_id, mask);
+    mutex_unlock(&lock);
+
+    PRINT_FILTERS();
+
+    return ret;
+}
+
+static int _send_msg(msg_t *msg, can_reg_entry_t *entry)
+{
+#ifdef MODULE_CAN_MBOX
+    switch (entry->type) {
+    case CAN_TYPE_DEFAULT:
+        return msg_try_send(msg, entry->target.pid);
+    case CAN_TYPE_MBOX:
+        DEBUG("_send_msg: sending msg=%p to mbox=%p\n", (void *)msg, (void *)entry->target.mbox);
+        return mbox_try_put(entry->target.mbox, msg);
+    default:
+        return -ENOTSUP;
+    }
+#else
+    return msg_try_send(msg, entry->target.pid);
+#endif
+}
+
+/* send received pkt to all interested users */
+int can_router_dispatch_rx_indic(can_pkt_t *pkt)
+{
+    if (!pkt) {
+        DEBUG("can_router_dispatch_rx_indic: invalid pkt\n");
+        return -EINVAL;
+    }
+
+    int res = 0;
+    msg_t msg;
+    msg.type = CAN_MSG_RX_INDICATION;
+#if ENABLE_DEBUG
+    int msg_cnt = 0;
+#endif
+    DEBUG("can_router_dispatch_rx_indic: pkt=%p, ifnum=%d, can_id=%" PRIx32 "\n",
+          (void *)pkt, pkt->entry.ifnum, pkt->frame.can_id);
+
+    mutex_lock(&lock);
+    can_reg_entry_t *entry;
+    filter_el_t *el;
+    LL_FOREACH(table[pkt->entry.ifnum], entry) {
+        el = container_of(entry, filter_el_t, entry);
+        if ((pkt->frame.can_id & el->mask) == el->can_id) {
+            DEBUG("can_router_dispatch_rx_indic: found el=%p, data=%p\n",
+                  (void *)el, (void *)el->data);
+            DEBUG("can_router_dispatch_rx_indic: rx_ind to pid: %"
+                  PRIkernel_pid "\n", entry->target.pid);
+            atomic_fetch_add(&pkt->ref_count, 1);
+            msg.content.ptr = can_pkt_alloc_rx_data(&pkt->frame, sizeof(pkt->frame), el->data);
+#if ENABLE_DEBUG
+            msg_cnt++;
+#endif
+            if (!msg.content.ptr || (_send_msg(&msg, entry) <= 0)) {
+                can_pkt_free_rx_data(msg.content.ptr);
+                atomic_fetch_sub(&pkt->ref_count, 1);
+                DEBUG("can_router_dispatch_rx_indic: failed to send msg to "
+                      "pid=%" PRIkernel_pid "\n", entry->target.pid);
+                res = -EBUSY;
+                break;
+            }
+        }
+    }
+    mutex_unlock(&lock);
+#if ENABLE_DEBUG
+    DEBUG("can_router_dispatch_rx: msg send to %d threads\n", msg_cnt);
+#endif
+    if (atomic_load(&pkt->ref_count) == 0) {
+        can_pkt_free(pkt);
+    }
+
+    return res;
+}
+
+int can_router_dispatch_tx_conf(can_pkt_t *pkt)
+{
+    msg_t msg;
+    msg.type = CAN_MSG_TX_CONFIRMATION;
+    msg.content.value = pkt->handle;
+
+    DEBUG("can_router_dispatch_tx_conf: frame=%p, pid=%" PRIkernel_pid "\n",
+          (void *)&pkt->frame, pkt->entry.target.pid);
+
+    if (_send_msg(&msg, &pkt->entry) <= 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int can_router_dispatch_tx_error(can_pkt_t *pkt)
+{
+    msg_t msg;
+    msg.type = CAN_MSG_TX_ERROR;
+    msg.content.value = pkt->handle;
+
+    DEBUG("can_router_dispatch_tx_error: frame=%p, pid=%" PRIkernel_pid "\n",
+          (void *)&pkt->frame, pkt->entry.target.pid);
+
+    if (_send_msg(&msg, &pkt->entry) <= 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int can_router_free_frame(struct can_frame *frame)
+{
+    can_pkt_t *pkt = NULL;
+
+    pkt = container_of(frame, can_pkt_t, frame);
+
+    DEBUG("can_router_free_frame: pkt=%p\n", (void*) pkt);
+
+    if (!pkt || (atomic_load(&pkt->ref_count) <= 0)) {
+        return -1;
+    }
+
+    atomic_fetch_sub(&pkt->ref_count, 1);
+
+    if (atomic_load(&pkt->ref_count) == 0) {
+        can_pkt_free(pkt);
+    }
+    return 0;
+}
diff --git a/sys/include/can/can.h b/sys/include/can/can.h
new file mode 100644
index 0000000000..477aec7ed4
--- /dev/null
+++ b/sys/include/can/can.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 OTA keys S.A.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     can
+ * @defgroup    can_dll Data Link Layer
+ * @brief       CAN Data Link Layer
+ *
+ * The Data Link Layer is composed of the device, router, pkt and dll files.
+ * It can be used to send and receive raw CAN frames through multiple CAN controllers.
+ *
+ * @{
+ *
+ *
+ * @file
+ * @brief       Definitions high-level CAN interface
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ * @author      Toon Stegen <toon.stegen@altran.com>
+ */
+
+#ifndef CAN_CAN_H
+#define CAN_CAN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#if defined(__linux__)
+
+#include <linux/can.h>
+#include <libsocketcan.h>
+
+#else
+
+/**
+ * @brief Max data length for a CAN frame
+ */
+#define CAN_MAX_DLEN (8)
+
+/**
+ * @name CAN_ID flags and masks
+ * @{
+ */
+/* special address description flags for the CAN_ID */
+#define CAN_EFF_FLAG (0x80000000U) /**< EFF/SFF is set in the MSB */
+#define CAN_RTR_FLAG (0x40000000U) /**< remote transmission request */
+#define CAN_ERR_FLAG (0x20000000U) /**< error message frame */
+
+/* valid bits in CAN ID for frame formats */
+#define CAN_SFF_MASK (0x000007FFU) /**< standard frame format (SFF) */
+#define CAN_EFF_MASK (0x1FFFFFFFU) /**< extended frame format (EFF) */
+#define CAN_ERR_MASK (0x1FFFFFFFU) /**< omit EFF, RTR, ERR flags */
+/** @} */
+
+/**
+ * @brief CAN operational and error states
+ */
+ enum can_state {
+     CAN_STATE_ERROR_ACTIVE = 0,     /**< RX/TX error count < 96 */
+     CAN_STATE_ERROR_WARNING,        /**< RX/TX error count < 128 */
+     CAN_STATE_ERROR_PASSIVE,        /**< RX/TX error count < 256 */
+     CAN_STATE_BUS_OFF,              /**< RX/TX error count >= 256 */
+     CAN_STATE_STOPPED,              /**< Device is stopped */
+     CAN_STATE_SLEEPING,             /**< Device is sleeping */
+     CAN_STATE_MAX
+ };
+
+/**
+ * @brief Controller Area Network Identifier structure
+ *
+ * bit 0-28  : CAN identifier (11/29 bit) right aligned for 11 bit
+ * bit 29    : error message frame flag (0 = data frame, 1 = error message)
+ * bit 30    : remote transmission request flag (1 = rtr frame)
+ * bit 31    : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
+ */
+typedef uint32_t canid_t;
+
+/**
+ * @brief Controller Area Network frame
+ */
+struct can_frame {
+    canid_t can_id;  /**< 32 bit CAN_ID + EFF/RTR/ERR flags */
+    uint8_t can_dlc; /**< frame payload length in byte (0 .. CAN_MAX_DLEN) */
+    uint8_t __pad;   /**< padding */
+    uint8_t __res0;  /**< reserved / padding */
+    uint8_t __res1;  /**< reserved / padding */
+    /** Frame data */
+    uint8_t data[CAN_MAX_DLEN] __attribute__((aligned(8)));
+};
+
+/**
+ * @brief Controller Area Network filter
+ */
+struct can_filter {
+    canid_t can_id;    /**< CAN ID */
+    canid_t can_mask;  /**< Mask */
+};
+
+/**
+ * @brief CAN bit-timing parameters
+ *
+ * For further information, please read chapter "8 BIT TIMING
+ * REQUIREMENTS" of the "Bosch CAN Specification version 2.0"
+ * at http://www.semiconductors.bosch.de/pdf/can2spec.pdf.
+ */
+struct can_bittiming {
+    uint32_t bitrate;      /**< Bit-rate in bits/second */
+    uint32_t sample_point; /**< Sample point in one-tenth of a percent */
+    uint32_t tq;           /**< Time quanta (TQ) in nanoseconds */
+    uint32_t prop_seg;     /**< Propagation segment in TQs */
+    uint32_t phase_seg1;   /**< Phase buffer segment 1 in TQs */
+    uint32_t phase_seg2;   /**< Phase buffer segment 2 in TQs */
+    uint32_t sjw;          /**< Synchronisation jump width in TQs */
+    uint32_t brp;          /**< Bit-rate prescaler */
+};
+
+/**
+ * @brief CAN hardware-dependent bit-timing constant
+ *
+ * Used for calculating and checking bit-timing parameters
+ */
+struct can_bittiming_const {
+    uint32_t tseg1_min;  /**< Time segment 1 = prop_seg + phase_seg1, min value */
+    uint32_t tseg1_max;  /**< Time segment 1, max value */
+    uint32_t tseg2_min;  /**< Time segment 2 = phase_seg2, min value */
+    uint32_t tseg2_max;  /**< Time segment 2, max value */
+    uint32_t sjw_max;    /**< Synchronisation jump width */
+    uint32_t brp_min;    /**< Bit-rate prescaler, min value */
+    uint32_t brp_max;    /**< Bit-rate prescaler, max value */
+    uint32_t brp_inc;    /**< Bit-rate prescaler, increment */
+};
+
+#endif /* defined(__linux__) */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CAN_CAN_H */
+
+/** @} */
diff --git a/sys/include/can/common.h b/sys/include/can/common.h
new file mode 100644
index 0000000000..663d2a59fd
--- /dev/null
+++ b/sys/include/can/common.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2016 OTA keys S.A.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup    can
+ * @defgroup   can_common  Common
+ * @brief      CAN stack common definitions
+ *
+ * This module defines the common part of the CAN stack, including structures
+ * and messages.
+ *
+ * @{
+ *
+ *
+ * @file
+ * @brief       Definitions of high-level CAN interface
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ */
+
+#ifndef CAN_COMMON_H
+#define CAN_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <sys/uio.h>
+
+#include "timex.h"
+#include "thread.h"
+#ifdef MODULE_CAN_MBOX
+#include "mbox.h"
+#endif
+#include "net/gnrc/pktbuf.h"
+
+/**
+ * @brief CAN options
+ */
+typedef enum {
+    CANOPT_BITTIMING,       /**< bit timing parameter */
+    CANOPT_RX_FILTERS,      /**< rx filters */
+    CANOPT_TEC,             /**< Transmit Error Counter */
+    CANOPT_REC,             /**< Receive Error Counter*/
+    CANOPT_LEC,             /**< Last Error Code */
+    CANOPT_CLOCK,           /**< controller main clock */
+    CANOPT_BITTIMING_CONST, /**< controller bittiming parameters */
+    CANOPT_STATE,           /**< set controller state @ref canopt_state_t */
+} canopt_t;
+
+/**
+ * @brief CAN state options
+ *
+ * CAN state options to be used with @p CANOPT_STATE
+ */
+typedef enum {
+    CANOPT_STATE_OFF,             /**< powered off */
+    CANOPT_STATE_SLEEP,           /**< sleep mode */
+    CANOPT_STATE_LISTEN_ONLY,     /**< listen only mode */
+    CANOPT_STATE_ON,              /**< power on, rx / tx mode */
+} canopt_state_t;
+
+
+/**
+ * @brief Structure to pass a CAN option
+ */
+typedef struct {
+    canopt_t opt;               /**< the option to get/set */
+    uint16_t context;           /**< (optional) context for that option */
+    void *data;                 /**< data to set or buffer to read into */
+    uint16_t data_len;          /**< size of the data / the buffer */
+} can_opt_t;
+
+/**
+ * @brief Messages which can be sent through the CAN stack
+ */
+enum can_msg {
+    /* High level messages */
+    CAN_MSG_ACK = 0x100,      /**< acknowledgment */
+    CAN_MSG_SEND_FRAME,       /**< send a frame */
+    CAN_MSG_ABORT_FRAME,      /**< abort a frame */
+    CAN_MSG_SET,              /**< set an option */
+    CAN_MSG_GET,              /**< get an option */
+    CAN_MSG_SET_FILTER,       /**< set a filter */
+    CAN_MSG_REMOVE_FILTER,    /**< remove a filter */
+    CAN_MSG_POWER_UP,         /**< power up */
+    CAN_MSG_POWER_DOWN,       /**< power down */
+    /* candev internal messages */
+    CAN_MSG_EVENT = 0x200,    /**< driver event */
+    CAN_MSG_WAKE_UP,          /**< driver has been woken up by bus */
+    CAN_MSG_TX_CONFIRMATION,  /**< a frame has been sent */
+    CAN_MSG_RX_INDICATION,    /**< a frame has been received */
+    CAN_MSG_TX_ERROR,         /**< there was an error when transmitting */
+    CAN_MSG_RX_ERROR,         /**< there was an error when receiving */
+    CAN_MSG_BUS_OFF,          /**< bus-off detected */
+    CAN_MSG_ERROR_PASSIVE,    /**< driver switched in error passive */
+    CAN_MSG_ERROR_WARNING,    /**< driver reached error warning */
+#if defined(MODULE_CAN_PM) || defined(DOXYGEN)
+    CAN_MSG_PM,               /**< power management event */
+#endif
+    /* isotp messages */
+#if defined(MODULE_CAN_ISOTP) || defined(DOXYGEN)
+    CAN_MSG_ISOTP_RX_TIMEOUT = 0x400,  /**< isotp rx timeout */
+    CAN_MSG_ISOTP_TX_TIMEOUT,          /**< isotp tx timeout */
+#endif
+};
+
+/**
+ * @brief Received data structure
+ *
+ * This structure is used when a layer sends received data
+ * to the upper layer
+ */
+typedef struct can_rx_data {
+    struct iovec data;    /**< iovec containing received data */
+    void *arg;            /**< upper layer private param */
+    gnrc_pktsnip_t *snip; /**< pointer to the allocated snip */
+} can_rx_data_t;
+
+
+/**
+ * @brief registry entry types
+ */
+typedef enum {
+    CAN_TYPE_DEFAULT = 0, /**< default entry (use msg) */
+#if defined(MODULE_CAN_MBOX) || defined(DOXYGEN)
+    CAN_TYPE_MBOX,        /**< mbox entry */
+#endif
+} can_reg_type_t;
+
+/**
+ * @brief registry entry
+ *
+ * This structure is used through the stack to describe how to contact
+ * the upper layer and which CAN interface to use
+ */
+typedef struct can_reg_entry {
+    struct can_reg_entry *next; /**< next for linked list */
+    int ifnum;                  /**< interface number for the entry */
+    union {
+        kernel_pid_t pid;       /**< pid of the thread when using msg */
+#if defined(MODULE_CAN_MBOX) || defined(DOXYGEN)
+        mbox_t *mbox;           /**< mbox pointer */
+#endif
+    } target;                   /**< entry target */
+#if defined(MODULE_CAN_MBOX) || defined(DOXYGEN)
+    can_reg_type_t type;        /**< entry type */
+#endif
+} can_reg_entry_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CAN_COMMON_H */
+/** @} */
diff --git a/sys/include/can/device.h b/sys/include/can/device.h
new file mode 100644
index 0000000000..f01dc44922
--- /dev/null
+++ b/sys/include/can/device.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2016 OTA keys S.A.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup    can_dll
+ * @{
+ *
+ *
+ * @file
+ * @brief       Definitions of CAN device interface
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ * @author      Toon Stegen <toon.stegen@altran.com>
+ */
+
+#ifndef CAN_DEVICE_H
+#define CAN_DEVICE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "can/candev.h"
+#include "kernel_types.h"
+
+#ifdef MODULE_CAN_PM
+#include "xtimer.h"
+#endif
+
+#ifndef CAN_MAX_RATE_ERROR
+/**
+ * Maximum bit-rate error allowed when computing bittimings
+ * in tenth of percent
+ */
+#define CAN_MAX_RATE_ERROR  (50) /* 5 % */
+#endif
+
+#ifndef CAN_DLL_NUMOF
+/**
+ * Maximum number of interfaces which can be registered on DLL
+ */
+#define CAN_DLL_NUMOF       (1U)
+#endif
+
+/**
+ * @brief Parameters to initialize a candev
+ */
+typedef struct candev_params {
+    const char *name;                /**< candev name to set */
+#if defined(MODULE_CAN_PM) || defined(DOXYGEN)
+    uint32_t rx_inactivity_timeout;  /**< power management rx timeout value */
+    uint32_t tx_wakeup_timeout;      /**< power management tx wake up value */
+#endif
+} candev_params_t;
+
+/**
+ * @brief candev descriptor to pass to the device thread
+ */
+typedef struct candev_dev {
+    candev_t *dev;    /**< the device */
+    int ifnum;        /**< interface number */
+    kernel_pid_t pid; /**< pid */
+    const char *name; /**< device name */
+#if defined(MODULE_CAN_PM) || defined(DOXYGEN)
+    uint32_t rx_inactivity_timeout; /**< Min timeout loaded when a frame is received */
+    uint32_t tx_wakeup_timeout;     /**< Min timeout loaded when a frame is sent */
+    uint32_t last_pm_update;   /**< time when the pm was updated */
+    uint32_t last_pm_value;    /**< last pm timer value set */
+    xtimer_t pm_timer;         /**< timer for power management */
+#endif
+} candev_dev_t;
+
+/**
+ * @brief Initialize a CAN device thread
+ *
+ * This function sets up a CAN device thread
+ *
+ * @param[in] stack      the device thread stack
+ * @param[in] stacksize  the device thread stack size
+ * @param[in] priority   the device thread priority
+ * @param[in] name       the device thread name
+ * @param[in] params     the parameters containing the device pointer and the ifnum
+ *
+ * @return the pid of the created thread
+ */
+kernel_pid_t can_device_init(char *stack, int stacksize, char priority,
+                             const char *name, candev_dev_t *params);
+
+/**
+ * @brief Fill in a @p bittiming structure from @p bittiming->bitrate and @p timing_const
+ *
+ * @param[in] clock         the clock of the CAN controller
+ * @param[in] timing_const  the timing parameter of the CAN controller
+ * @param[in,out] bittiming the calculated bittiming (bitrate field must be set)
+ *
+ * @return 0 on success
+ * @return < 0 on error
+ */
+int can_device_calc_bittiming(uint32_t clock, const struct can_bittiming_const *timing_const,
+                              struct can_bittiming *bittiming);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CAN_DEVICE_H */
+
+/** @} */
diff --git a/sys/include/can/dll.h b/sys/include/can/dll.h
new file mode 100644
index 0000000000..503e97fb98
--- /dev/null
+++ b/sys/include/can/dll.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 OTA keys S.A.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup    can_dll
+ * @{
+ *
+ *
+ * @file
+ * @brief       Definitions of low-level CAN DLL interface
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ * @author      Toon Stegen <toon.stegen@altran.com>
+ */
+
+#ifndef CAN_DLL_H
+#define CAN_DLL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "can/common.h"
+#include "can/pkt.h"
+#include "can/device.h"
+#include "thread.h"
+
+/**
+ * @brief Initialize the CAN DLL
+ *
+ * @return 0 on success
+ */
+int can_dll_init(void);
+
+/**
+ * @brief Register a CAN device into the DLL
+ *
+ * This function must be called by the device thread to register the device into the DLL
+ *
+ * @param[in] candev  the candev to register
+ *
+ * @return interface number on success
+ * @return -ENODEV if ifnum is invalid
+ */
+int can_dll_register_candev(candev_dev_t *candev);
+
+/**
+ * @brief Dispatch a received frame
+ *
+ * This function is used to send a message to the DLL thread when a @p frame is received
+ * from the device identified by its @p pid
+ *
+ * @param[in] frame the received frame
+ * @param[in] pid   the pid of the receiver device
+ *
+ * @return 0 on success
+ * @return -ENOMEM if the message can not be sent
+ */
+int can_dll_dispatch_rx_frame(struct can_frame *frame, kernel_pid_t pid);
+
+/**
+ * @brief Dispatch a tx confirmation
+ *
+ * This function is used to send a message to the sender thread when the
+ * @p pkt has been sent correctly.
+ *
+ * @param[in] pkt   the pkt which has been sent
+ *
+ * @return 0 on success
+ * @return -ENOMEM if the message can not be sent
+ */
+int can_dll_dispatch_tx_conf(can_pkt_t *pkt);
+
+/**
+ * @brief Dispatch a tx error
+ *
+ * This function is used to send a message to the sender thread when the
+ * @p pkt has not been sent correctly
+ *
+ * @param[in] pkt   the pkt which has not been sent correctly
+ *
+ * @return 0 on success
+ * @return -ENOMEM if the message can not be sent
+ */
+int can_dll_dispatch_tx_error(can_pkt_t *pkt);
+
+/**
+ * @brief Dispatch RX error from a device
+ *
+ * Dispatch RX error from a device to receivers threads
+ * which have subscribed to frames on that interface
+ *
+ * @param[in] pid   the device thread pid
+ *
+ * @return 0 on success
+ */
+int can_dll_dispatch_bus_off(kernel_pid_t pid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CAN_DLL_H */
+
+/** @} */
diff --git a/sys/include/can/doc.txt b/sys/include/can/doc.txt
new file mode 100644
index 0000000000..6b17fecc42
--- /dev/null
+++ b/sys/include/can/doc.txt
@@ -0,0 +1,23 @@
+/**
+ * @defgroup can CAN
+ * @brief RIOT CAN stack
+ *
+ * This module is a full CAN stack integrated to RIOT.
+ * It includes a low-level interface, a data link layer, an ISO-TP layer and
+ * a user interface.
+ *
+ * The low-level interface, candev, must be implemented by controler drivers.
+ * The optional transceiver support can also be activated. Transceiver drivers must
+ * then implement the trx_can interface.
+ *
+ * The data link layer is built around a device thread (one thread per CAN device),
+ * and a common part. The common part is composed of the dll interface, for low-level
+ * calls (from the device) and the raw interface for upper-level calls.
+ * Internally it also uses the pkt module to allocate frames and the router module
+ * to manage CAN filters.
+ *
+ * The ISO-TP layer uses the data link layer to send and receive CAN frames.
+ *
+ * Finally, the connection layer is the user interface to send and receive raw
+ * CAN frames or ISO-TP datagrams.
+ */
diff --git a/sys/include/can/pkt.h b/sys/include/can/pkt.h
new file mode 100644
index 0000000000..9744254dda
--- /dev/null
+++ b/sys/include/can/pkt.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2016 OTA keys S.A.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup    can_dll
+ * @{
+ *
+ *
+ * @file
+ * @brief       CAN memory allocation module
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ * @author      Toon Stegen <toon.stegen@altran.com>
+ */
+
+#ifndef CAN_PKT_H
+#define CAN_PKT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdatomic.h>
+
+#include "net/gnrc/pktbuf.h"
+
+#include "can/common.h"
+#include "can/can.h"
+#include "msg.h"
+#ifdef MODULE_CAN_MBOX
+#include "mbox.h"
+#endif
+
+/**
+ * @brief A CAN packet
+ *
+ * A CAN packet is used to add stack-related data around a CAN frame
+ */
+typedef struct {
+    can_reg_entry_t entry;   /**< entry containing ifnum and upper layer info */
+    atomic_uint ref_count;   /**< Reference counter (for rx frames) */
+    int handle;              /**< handle (for tx frames */
+    struct can_frame frame;  /**< CAN Frame */
+    gnrc_pktsnip_t *snip;    /**< Pointer to the allocated snip */
+} can_pkt_t;
+
+/**
+ * @brief Initialize the CAN packet module
+ *
+ * This must be called by the DLL to initialize the module
+ */
+void can_pkt_init(void);
+
+/**
+ * @brief Allocate a CAN packet to transmit
+ *
+ * This function allocates a CAN packet and associates it to the @p ifnum and @p tx_pid.
+ * The provided @p frame is copied into the CAN packet and a unique handle is set.
+ *
+ * @param[in] ifnum  the interface number
+ * @param[in] frame  the frame to copy
+ * @param[in] tx_pid the pid of the sender's device thread
+ *
+ * @return an allocated CAN packet, NULL if an error occured
+ */
+can_pkt_t *can_pkt_alloc_tx(int ifnum, const struct can_frame *frame, kernel_pid_t tx_pid);
+
+/**
+ * @brief Allocate an incoming CAN packet
+ *
+ * @param[in] ifnum  the interface number
+ * @param[in] frame  the received frame
+ *
+ * @return an allocated CAN packet, NULL if an error occured
+ */
+can_pkt_t *can_pkt_alloc_rx(int ifnum, const struct can_frame *frame);
+
+#if defined(MODULE_CAN_MBOX) || defined(DOXYGEN)
+/**
+ * @brief Allocate a CAN packet for a mbox to transmit
+ *
+ * This function allocates a CAN packet and associate it to the @p ifnum and @p mbox.
+ * The provided @p frame is copied into the CAN packet and a unique handle is set.
+ *
+ * @param[in] ifnum  the interface number
+ * @param[in] frame  the frame to copy
+ * @param[in] mbox   the pointer to the sender's mbox
+ *
+ * @return an allocated CAN packet, NULL if an error occured
+ */
+can_pkt_t *can_pkt_alloc_mbox_tx(int ifnum, const struct can_frame *frame, mbox_t *mbox);
+#endif
+
+/**
+ * @brief Free a CAN packet
+ *
+ * @param[in] pkt     the packet to free, it must be a pointer returned
+ *                    by @ref can_pkt_alloc_tx or @ref can_pkt_alloc_rx
+ */
+void can_pkt_free(can_pkt_t *pkt);
+
+/**
+ * @brief Allocate a @p can_rx_data_t and initialize it with gieven parameters
+ *
+ * This is used to allocate a return value to the upper layer
+ *
+ * @param[in] data  data which will be returned
+ * @param[in] len   length of @p data
+ * @param[in] arg   optional argument for the upper layer
+ *
+ * @return a @p can_rx_data_t pointer, NULL if out of memory
+ */
+can_rx_data_t *can_pkt_alloc_rx_data(void *data, size_t len, void *arg);
+
+/**
+ * @brief Free rx data previously allocated by can_pkt_alloc_rx_data()
+ *
+ * @param[in] data  the pointer to free
+ */
+void can_pkt_free_rx_data(can_rx_data_t *data);
+
+/**
+ * @brief Allocate @p size bytes and return the pointer
+ *
+ * This function has been copied from gnrc_pktbuf_static
+ *
+ * @param[in] size  the number of bytes to allocate
+ *
+ * @return the pointer to thje allocated data, NULL if out of memory
+ */
+void *can_pkt_buf_alloc(size_t size);
+
+/**
+ * @brief Free the data allocated by can_pkt_buf_alloc()
+ *
+ * @param[in] data  the pointer to free
+ * @param[in] size  the size of the data to free
+ */
+void can_pkt_buf_free(void *data, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CAN_PKT_H */
+
+/** @} */
diff --git a/sys/include/can/raw.h b/sys/include/can/raw.h
new file mode 100644
index 0000000000..1316bf9663
--- /dev/null
+++ b/sys/include/can/raw.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2016 OTA keys S.A.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup    can_dll
+ * @{
+ *
+ *
+ * @file
+ * @brief       Definitions high-level RAW CAN interface
+ *
+ * This file defines the hig-level CAN interface to send and receive RAW CAN frame.
+ *
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ * @author      Toon Stegen <toon.stegen@altran.com>
+ * @author      Aurelien Gonce <aurelien.gonce@altran.com>
+ */
+
+#ifndef CAN_RAW_H
+#define CAN_RAW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "kernel_types.h"
+#include "can/can.h"
+#include "can/common.h"
+#include "can/device.h"
+
+#ifdef MODULE_CAN_MBOX
+#include "mbox.h"
+#endif
+
+
+/**
+ * @brief Default value for undefined interface number
+ */
+#define RAW_CAN_DEV_UNDEF (-1)
+
+/**
+ * @brief Send a CAN frame
+ *
+ * Send a CAN @p frame through the @p ifnum interface. The result is
+ * sent to the @p pid thread via IPC.
+ *
+ * @param[in] ifnum the interface number to send to
+ * @param[in] frame the frame to send
+ * @param[in] pid   the user thread id to whom the result msg will be sent
+ *                  it can be THREAD_PID_UNDEF if no feedback is expected
+ *
+ * @return a positive handle identifying the sent frame on success
+ * @return < 0 on error
+ */
+int raw_can_send(int ifnum, const struct can_frame *frame, kernel_pid_t pid);
+
+/**
+ * @brief Abort a CAN frame
+ *
+ * Abort the frame identified by @p handle in the interface @p ifnum
+ * If no tx confirmation is received, this function must be called by the upper layer
+ * to ensure the driver frees its tx mailbox. The driver is not responsible of tx timeouts.
+ *
+ * @param[in] ifnum  the interface number used to send the frame
+ * @param[in] handle the handle of the frame to abort,
+ *                   it must be the value returned by raw_can_send
+ * @return 0 on succes
+ * @return < 0 on error (-ENODEV)
+ */
+int raw_can_abort(int ifnum, int handle);
+
+/**
+ * @brief Subscribe to a CAN filter
+ *
+ * This function must be called if a user thread @p pid wants to receive the CAN frame matching @p filter
+ * on the interface @p ifnum.
+ * The user thread will then receive msg via IPC on reception of frame matching @p filters.
+ *
+ * @param[in] ifnum      the interface number to listen
+ * @param[in] filter     the list of filter to receive
+ * @param[in] pid        the thread id of the user
+ * @param[in] param      optional user parameter
+ *
+ * @return the @p ifnum on success
+ * @return < 0 on error
+ */
+int raw_can_subscribe_rx(int ifnum, struct can_filter *filter, kernel_pid_t pid, void *param);
+
+/**
+ * @brief Unsubscribe from reception for the given CAN @p filter on @p pid thread
+ *
+ * @param[in] ifnum    the interface number
+ * @param[in] filter   the filter to remove
+ * @param[in] pid      the thread id of the user
+ * @param[in] param    optional user parameter
+ *
+ * @return 0 on success
+ * @return < 0 on error
+ */
+int raw_can_unsubscribe_rx(int ifnum, struct can_filter *filter, kernel_pid_t pid, void *param);
+
+/**
+ * @brief Free a received frame
+ *
+ * This function must be called by the user when a received frame is not needed anymore.
+ *
+ * @param[in] frame the frame to free, it must be a pointer to a frame received by the stack
+ *
+ * @return 0 on success
+ * @return < 0 on error
+ */
+int raw_can_free_frame(can_rx_data_t *frame);
+
+/**
+ * @brief Get a CAN option @p opt from interface @p ifnum
+ *
+ * @param[in] ifnum   the interface number
+ * @param[in,out] opt the option to get
+ *
+ * @return 0 on success
+ * @return < 0 on error
+ */
+int raw_can_get_can_opt(int ifnum, can_opt_t *opt);
+
+/**
+ * @brief Set a CAN option @p opt to interface @p ifnum
+ *
+ * @param[in] ifnum   the interface number
+ * @param[in,out] opt the option to set
+ *
+ * @return 0 on success
+ * @return < 0 on error
+ */
+int raw_can_set_can_opt(int ifnum, can_opt_t *opt);
+
+#if  defined(MODULE_CAN_MBOX) || defined(DOXYGEN)
+/**
+ * @brief Send a CAN frame
+ *
+ * Send a CAN @p frame through the @p ifnum interface. The result is
+ * sent to the @p mbox thread via mailbox IPC.
+ *
+ * @param[in] ifnum the interface number to send to
+ * @param[in] frame the frame to send
+ * @param[in] mbox  the user mbox to whom the result msg will be sent
+ *                  it can be NULL if no feedback is expected
+ *
+ * @return a positive handle identifying the sent frame on success
+ * @return < 0 on error
+ */
+int raw_can_send_mbox(int ifnum, const struct can_frame *frame, mbox_t *mbox);
+
+/**
+ * @brief Subscribe to a CAN filter
+ *
+ * This function must be called if a user thread waiting on @p mbox wants to receive
+ * the CAN frame matching @p filter on the interface @p ifnum.
+ * The user thread will then receive msg via mailbox IPC on reception of frame matching @p filters.
+ *
+ * Currently only single frame ID (i.e. filters->can_mask = 0xFFFFFFFF) are supported.
+ *
+ * @param[in] ifnum      the interface number to listen
+ * @param[in] filter     the list of filter to receive
+ * @param[in] mbox       the mbox of the user
+ * @param[in] param      optional user parameter
+ *
+ * @return the @p ifnum on success
+ * @return < 0 on error
+ */
+int raw_can_subscribe_rx_mbox(int ifnum, struct can_filter *filter, mbox_t *mbox, void *param);
+
+/**
+ * @brief Unsubscribe from reception for the given CAN @p filter and @p mbox
+ *
+ * @param[in] ifnum    the interface number
+ * @param[in] filter   the filter to remove
+ * @param[in] mbox     the mbox of the user
+ * @param[in] param    optional user parameter
+ *
+ * @return 0 on success
+ * @return < 0 on error
+ */
+int raw_can_unsubscribe_rx_mbox(int ifnum, struct can_filter *filter, mbox_t *mbox, void *param);
+#endif
+
+/**
+ * @brief Power down a given interface
+ *
+ * @param[in] ifnum    the interface number to power down
+ *
+ * @return 0 on success
+ * @return < 0 on error
+ */
+int raw_can_power_down(int ifnum);
+
+/**
+ * @brief Power up a given interface
+ *
+ * @param[in] ifnum    the interface number to power up
+ *
+ * @return 0 on success
+ * @return < 0 on error
+ */
+int raw_can_power_up(int ifnum);
+
+/**
+ * @brief Get the interface number of a given interface
+ *
+ * @param[in] name   interface name
+ *
+ * @return the interface number, RAW_CAN_DEV_UNDEF if not defined
+ */
+int raw_can_get_ifnum_by_name(const char *name);
+
+/**
+ * @brief Get the interface name of a given interface number
+ *
+ * @param[in] ifnum   interface number
+ *
+ * @return the interface name, NULL if no interface registered with this number
+ */
+const char *raw_can_get_name_by_ifnum(int ifnum);
+
+/**
+ * @brief Get the candev descriptor from a given interface number
+ *
+ * @param[in] ifnum   interface number
+ *
+ * @return pointer to a candev descriptor, NULL if no interface is registered with
+ *         this number
+ */
+candev_dev_t *raw_can_get_dev_by_ifnum(int ifnum);
+
+/**
+ * @brief Set the given bitrate/sample_point to the given ifnum
+ *
+ * Set the given @p bitrate and @p sample_point to the given @p ifnum. This is a
+ * helper function which calculates the right bittiming from @p bitrate and
+ * @p sample_point.
+ *
+ * @param[in] ifnum          the interface number
+ * @param[in] bitrate        the bitrate in bits/s
+ * @param[in] sample_point   the sample point in tenth of percent (875 = 87.5%)
+ *                           if not set, the default value of 87.5% is used
+ * @return 0 on success
+ * @return 1 if the bitrate/sample_point couple can not be reached precisely but the bitrate is set
+ * @return < 0  on error
+ */
+int raw_can_set_bitrate(int ifnum, uint32_t bitrate, uint32_t sample_point);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CAN_RAW_H */
+/** @} */
diff --git a/sys/include/can/router.h b/sys/include/can/router.h
new file mode 100644
index 0000000000..d5679a1df8
--- /dev/null
+++ b/sys/include/can/router.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 OTA keys S.A.
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup    can_dll
+ * @{
+ *
+ *
+ * @file
+ * @brief       Functions for routing RX can frames
+ *
+ * @author      Toon Stegen <toon.stegen@altran.com>
+ * @author      Vincent Dupont <vincent@otakeys.com>
+ */
+
+#ifndef CAN_ROUTER_H
+#define CAN_ROUTER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "kernel_types.h"
+
+#include "can/can.h"
+#include "can/pkt.h"
+
+/**
+ * @brief Register a user @p entry to receive a frame @p can_id
+ *
+ * @param[in] entry   the entry containing ifnum and user info
+ * @param[in] can_id  the CAN ID of the frame to receive
+ * @param[in] mask    the mask of the frame to receive
+ * @param[in] param   a user private pointer
+ *
+ * @return 0 on success
+ * @return < 0 on error
+ */
+int can_router_register(can_reg_entry_t *entry, canid_t can_id, canid_t mask, void *param);
+
+/**
+ * @brief Unregister a user @p entry from receiving @p can_id
+ *
+ * The filter is unregistered from the 'router' layer if @p can_id, @p mask and @p param
+ * matches a registered entry.
+ *
+ * @param[in] entry   the entry containing ifnum and user info which was registered
+ * @param[in] can_id  the CAN ID of the frame to stop receiving
+ * @param[in] mask    the mask of the frame to stop receiving
+ * @param[in] param   a user private pointer
+ *
+ * @return 0 if @p can_id is not used anymore
+ * @return 1 if @p can_id is still used by another pid
+ * @return < 0 on error
+ */
+int can_router_unregister(can_reg_entry_t *entry, canid_t can_id, canid_t mask, void *param);
+
+/**
+ * @brief Free a received frame
+ *
+ * This function decrements the ref counter of the packet and frees it if the packet
+ * is no more in use.
+ *
+ * @param[in] frame    the frame to free, it must be a frame returned by the stack
+ *
+ * @return 0 on success
+ * @return < 0 on error
+ */
+int can_router_free_frame(struct can_frame *frame);
+
+/**
+ * @brief Dispatch a RX indication to subscribers threads
+ *
+ * This function goes through the list of subscribed filters to send a message to each
+ * subscriber's thread. If all the subscriber's threads cannot receive message,
+ * the packet is freed.
+ *
+ * @param[in] pkt   the packet to dispatch
+ *
+ * @return 0 on success
+ * @return < 0 on error, if at least a thread cannot receive message
+ */
+int can_router_dispatch_rx_indic(can_pkt_t *pkt);
+
+/**
+ * @brief Dispatch a TX confirmation to the sender's thread
+ *
+ * @param[in] pkt  the correctly sent packet
+ *
+ * @return 0 on success
+ * @return < 0 on error
+ */
+int can_router_dispatch_tx_conf(can_pkt_t *pkt);
+
+/**
+ * @brief Dispatch a TX error to the sender's thread
+ *
+ * @param[in] pkt  the error packet
+ *
+ * @return 0 on success
+ * @return < 0 on error
+ */
+int can_router_dispatch_tx_error(can_pkt_t *pkt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CAN_ROUTER_H */
+
+/** @} */
-- 
GitLab