net: l2: 6LoCAN implementation

This commit is an implementation of 6LoCAN, a 6Lo adaption layer for
Controller Area Networks. 6LoCAN is not yet standardised.

Signed-off-by: Alexander Wachter <alexander.wachter@student.tugraz.at>
This commit is contained in:
Alexander Wachter 2019-08-06 16:12:24 +02:00 committed by Jukka Rissanen
parent c8c5f3bbf3
commit 35f01673ac
28 changed files with 2096 additions and 65 deletions

View file

@ -353,6 +353,7 @@
/subsys/net/lib/sockets/ @jukkar @tbursztyka @pfalcon
/subsys/net/lib/tls_credentials/ @rlubos
/subsys/net/l2/ @jukkar @tbursztyka
/subsys/net/l2/canbus/ @alexanderwachter @jukkar
/subsys/power/ @wentongwu @pizi-nordic
/subsys/settings/ @nvlsianpu
/subsys/shell/ @jakub-uC @nordic-krch

View file

@ -8,3 +8,4 @@ zephyr_sources_ifdef(CONFIG_CAN_MCUX_FLEXCAN can_mcux_flexcan.c)
zephyr_sources_ifdef(CONFIG_USERSPACE can_handlers.c)
zephyr_sources_ifdef(CONFIG_CAN_SHELL can_shell.c)
zephyr_sources_ifdef(CONFIG_CAN_NET can_net.c)

View file

@ -64,5 +64,6 @@ source "drivers/can/Kconfig.stm32"
source "drivers/can/Kconfig.mcux"
source "drivers/can/Kconfig.mcp2515"
source "drivers/can/Kconfig.loopback"
source "drivers/can/Kconfig.net"
endif # CAN

37
drivers/can/Kconfig.net Normal file
View file

@ -0,0 +1,37 @@
# Kconfig.net - Configuration options for IPv6 over CAN
#
# Copyright (c) 2019 Alexander Wachter
#
# SPDX-License-Identifier: Apache-2.0
#
config CAN_NET
bool "Enable 6loCAN network interface [EXPERIMENTAL]"
help
Enable IPv6 Networking over can (6loCAN)
if CAN_NET
module = CAN_NET
module-dep = NET_LOG
module-str = Log level for Network CAN
module-help = Enables logging for CAN L2 networking
source "subsys/net/Kconfig.template.log_config.net"
config CAN_NET_NAME
string "Network device name"
default "NET_CAN"
help
Name of the network device driver for IPv6 over CAN.
config CAN_NET_INIT_PRIORITY
int "CAN NET driver init priority"
default 80
help
CAN NET device driver initialization priority.
Do not mess with it unless you know what you are doing.
Note that the priority needs to be lower than the net stack
so that it can start before the networking sub-system.
endif #CAN_NET

258
drivers/can/can_net.c Normal file
View file

@ -0,0 +1,258 @@
/*
* Copyright (c) 2019 Alexander Wachter
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <net/can.h>
#include <net/net_pkt.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(net_can, CONFIG_CAN_NET_LOG_LEVEL);
struct net_can_context {
struct device *can_dev;
struct net_if *iface;
int recv_filter_id;
int mcast_filter_id;
};
static inline u8_t can_get_frame_datalength(struct zcan_frame *frame)
{
/* TODO: Needs update when CAN FD support is added */
return frame->dlc;
}
static inline u16_t can_get_lladdr_src(struct zcan_frame *frame)
{
return (frame->ext_id >> CAN_NET_IF_ADDR_SRC_POS) &
CAN_NET_IF_ADDR_MASK;
}
static inline u16_t can_get_lladdr_dest(struct zcan_frame *frame)
{
return (frame->ext_id >> CAN_NET_IF_ADDR_DEST_POS) &
CAN_NET_IF_ADDR_MASK;
}
static inline void can_set_lladdr(struct net_pkt *pkt, struct zcan_frame *frame)
{
struct net_buf *buf = pkt->buffer;
/* Put the destination at the beginning of the pkt.
* The net_canbus_lladdr has a size if 14 bits. To convert it to
* network byte order, we treat it as 16 bits here.
*/
net_pkt_lladdr_dst(pkt)->addr = buf->data;
net_pkt_lladdr_dst(pkt)->len = sizeof(struct net_canbus_lladdr);
net_pkt_lladdr_dst(pkt)->type = NET_LINK_CANBUS;
net_buf_add_be16(buf, can_get_lladdr_dest(frame));
net_buf_pull(buf, sizeof(u16_t));
/* Do the same as above for the source address */
net_pkt_lladdr_src(pkt)->addr = buf->data;
net_pkt_lladdr_src(pkt)->len = sizeof(struct net_canbus_lladdr);
net_pkt_lladdr_src(pkt)->type = NET_LINK_CANBUS;
net_buf_add_be16(buf, can_get_lladdr_src(frame));
net_buf_pull(buf, sizeof(u16_t));
}
static void net_can_iface_init(struct net_if *iface)
{
struct device *dev = net_if_get_device(iface);
struct net_can_context *ctx = dev->driver_data;
ctx->iface = iface;
NET_DBG("Init CAN network interface %p dev %p", iface, dev);
net_6locan_init(iface);
}
static int net_can_send(struct device *dev, const struct zcan_frame *frame,
can_tx_callback_t cb, void *cb_arg, s32_t timeout)
{
struct net_can_context *ctx = dev->driver_data;
NET_ASSERT(frame->id_type == CAN_EXTENDED_IDENTIFIER);
return can_send(ctx->can_dev, frame, timeout, cb, cb_arg);
}
static void net_can_recv(struct zcan_frame *frame, void *arg)
{
struct net_can_context *ctx = (struct net_can_context *)arg;
size_t pkt_size = 2 * sizeof(struct net_canbus_lladdr) +
can_get_frame_datalength(frame);
struct net_pkt *pkt;
int ret;
NET_DBG("Frame with ID 0x%x received", frame->ext_id);
pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, pkt_size, AF_UNSPEC, 0,
K_NO_WAIT);
if (!pkt) {
LOG_ERR("Failed to obtain net_pkt with size of %d", pkt_size);
goto drop;
}
pkt->canbus_rx_ctx = NULL;
can_set_lladdr(pkt, frame);
net_pkt_cursor_init(pkt);
ret = net_pkt_write(pkt, frame->data, can_get_frame_datalength(frame));
if (ret) {
LOG_ERR("Failed to append frame data to net_pkt");
goto drop;
}
ret = net_recv_data(ctx->iface, pkt);
if (ret < 0) {
LOG_ERR("Packet dropped by NET stack");
goto drop;
}
return;
drop:
NET_INFO("pkt dropped");
if (pkt) {
net_pkt_unref(pkt);
}
}
static int can_attach_filter(struct device *dev, can_rx_callback_t cb, void *cb_arg,
const struct zcan_filter *filter)
{
struct net_can_context *ctx = dev->driver_data;
return can_attach_isr(ctx->can_dev, cb, cb_arg, filter);
}
static void can_detach_filter(struct device *dev, int filter_id)
{
struct net_can_context *ctx = dev->driver_data;
if (filter_id >= 0) {
can_detach(ctx->can_dev, filter_id);
}
}
static inline int can_attach_unicast_filter(struct net_can_context *ctx)
{
struct zcan_filter filter = {
.id_type = CAN_EXTENDED_IDENTIFIER,
.rtr = CAN_DATAFRAME,
.rtr_mask = 1,
.ext_id_mask = CAN_NET_IF_ADDR_DEST_MASK
};
const u8_t *link_addr = net_if_get_link_addr(ctx->iface)->addr;
const u16_t dest = sys_be16_to_cpu(UNALIGNED_GET((u16_t *) link_addr));
int filter_id;
filter.ext_id = (dest << CAN_NET_IF_ADDR_DEST_POS);
filter_id = can_attach_isr(ctx->can_dev, net_can_recv,
ctx, &filter);
if (filter_id == CAN_NET_FILTER_NOT_SET) {
NET_ERR("Can't attach FF filter");
return CAN_NET_FILTER_NOT_SET;
}
NET_DBG("Attached FF filter %d", filter_id);
return filter_id;
}
static inline int can_attach_mcast_filter(struct net_can_context *ctx)
{
struct zcan_filter filter = {
.id_type = CAN_EXTENDED_IDENTIFIER,
.rtr = CAN_DATAFRAME,
.rtr_mask = 1,
.ext_id_mask = CAN_NET_IF_ADDR_DEST_MASK
};
int filter_id;
filter.ext_id = (NET_CAN_MULTICAST_ADDR << CAN_NET_IF_ADDR_DEST_POS);
filter_id = can_attach_isr(ctx->can_dev, net_can_recv,
ctx, &filter);
if (filter_id == CAN_NET_FILTER_NOT_SET) {
NET_ERR("Can't attach multicast filter");
return CAN_NET_FILTER_NOT_SET;
}
NET_DBG("Attached multicast filter %d", filter_id);
return filter_id;
}
static int can_enable(struct device *dev, bool enable)
{
struct net_can_context *ctx = dev->driver_data;
if (enable) {
if (ctx->recv_filter_id == CAN_NET_FILTER_NOT_SET) {
ctx->recv_filter_id = can_attach_unicast_filter(ctx);
if (ctx->recv_filter_id < 0) {
return -EIO;
}
}
if (ctx->mcast_filter_id == CAN_NET_FILTER_NOT_SET) {
ctx->mcast_filter_id = can_attach_mcast_filter(ctx);
if (ctx->mcast_filter_id < 0) {
can_detach(ctx->can_dev, ctx->recv_filter_id);
return -EIO;
}
}
} else {
if (ctx->recv_filter_id != CAN_NET_FILTER_NOT_SET) {
can_detach(ctx->can_dev, ctx->recv_filter_id);
}
if (ctx->mcast_filter_id != CAN_NET_FILTER_NOT_SET) {
can_detach(ctx->can_dev, ctx->mcast_filter_id);
}
}
return 0;
}
static struct net_can_api net_can_api_inst = {
.iface_api.init = net_can_iface_init,
.send = net_can_send,
.attach_filter = can_attach_filter,
.detach_filter = can_detach_filter,
.enable = can_enable,
};
static int net_can_init(struct device *dev)
{
struct device *can_dev = device_get_binding(DT_CAN_1_NAME);
struct net_can_context *ctx = dev->driver_data;
ctx->recv_filter_id = CAN_NET_FILTER_NOT_SET;
ctx->mcast_filter_id = CAN_NET_FILTER_NOT_SET;
if (!can_dev) {
NET_ERR("Can't get binding to CAN device %s", DT_CAN_1_NAME);
return -EIO;
}
NET_DBG("Init net CAN device %p (%s) for dev %p (%s)",
dev, dev->config->name, can_dev, can_dev->config->name);
ctx->can_dev = can_dev;
return 0;
}
static struct net_can_context net_can_context_1;
NET_DEVICE_INIT(net_can_1, CONFIG_CAN_NET_NAME, net_can_init,
&net_can_context_1, NULL,
CONFIG_CAN_NET_INIT_PRIORITY,
&net_can_api_inst,
CANBUS_L2, NET_L2_GET_CTX_TYPE(CANBUS_L2), NET_CAN_MTU);

230
include/net/can.h Normal file
View file

@ -0,0 +1,230 @@
/** @file
* @brief IPv6 Networking over CAN definitions.
*
* Definitions for IPv6 Networking over CAN support.
*/
/*
* Copyright (c) 2019 Alexander Wachter
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_NET_CAN_H_
#define ZEPHYR_INCLUDE_NET_CAN_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <zephyr/types.h>
#include <net/net_ip.h>
#include <net/net_if.h>
#include <can.h>
/**
* @brief IPv6 over CAN library
* @defgroup net_can Network Core Library
* @ingroup networking
* @{
*/
/**
* CAN L2 driver API. Used by 6loCAN.
*/
/*
* Abbreviations
* BS Block Size
* CAN_DL CAN LL data size
* CF Consecutive Frame
* CTS Continue to send
* DLC Data length code
* FC Flow Control
* FF First Frame
* FS Flow Status
*/
/** @cond INTERNAL_HIDDEN */
#define NET_CAN_DL 8
#define NET_CAN_MTU 0x0FFF
/* 0x3DFF - bit 4 to 10 must not be zero. Also prevent stuffing bit*/
#define NET_CAN_MULTICAST_ADDR 0x3DFF
#define NET_CAN_DAD_ADDR 0x3DFE
#define NET_CAN_ETH_TRANSLATOR_ADDR 0x3DF0
#define NET_CAN_MAX_ADDR 0x3DEF
#define NET_CAN_MIN_ADDR 0x0100
#define CAN_NET_IF_ADDR_MASK 0x3FFF
#define CAN_NET_IF_ADDR_BYTE_LEN 2U
#define CAN_NET_IF_ADDR_DEST_POS 14U
#define CAN_NET_IF_ADDR_DEST_MASK (CAN_NET_IF_ADDR_MASK << CAN_NET_IF_ADDR_DEST_POS)
#define CAN_NET_IF_ADDR_SRC_POS 0U
#define CAN_NET_IF_ADDR_SRC_MASK (CAN_NET_IF_ADDR_MASK << CAN_NET_IF_ADDR_SRC_POS)
#define CAN_NET_IF_ADDR_MCAST_POS 28U
#define CAN_NET_IF_ADDR_MCAST_MASK (1UL << CAN_NET_IF_ADDR_MCAST_POS)
#define CAN_NET_IF_IS_MCAST_BIT (1U << 14)
#define CAN_NET_FILTER_NOT_SET -1
/** @endcond */
/*
* +-----------+ +-----------+
* | | | |
* | IPv6 | | IPv6 |
* | 6LoCAN | | 6LoCAN |
* | | | |
* +----+-+----+ +----+-+----+
* | | | | +---+
* +----+ | | | | / \ +-+
* | | | | | | +--+ / \_/ \
* +++ +---+ +--+----+ +-------+ +--+----+ +--/ \_/ \
* | | \ / | \ / \ / | \ / / |
* | | X | X CAN X | X | Internet |
* | | / \ | / \ / \ | / \ \ /
* +++ +---+ +----+--+ +-------+ +----+--+ +--+ /
* | | +-------------------+
* +----+
*/
struct net_can_api {
/**
* The net_if_api must be placed in first position in this
* struct so that we are compatible with network interface API.
*/
struct net_if_api iface_api;
/** Send a single CAN frame */
int (*send)(struct device *dev, const struct zcan_frame *frame,
can_tx_callback_t cb, void *cb_arg, s32_t timeout);
/** Attach a filter with it's callback */
int (*attach_filter)(struct device *dev, can_rx_callback_t cb,
void *cb_arg, const struct zcan_filter *filter);
/** Detach a filter */
void (*detach_filter)(struct device *dev, int filter_id);
/** Enable or disable the reception of frames for net CAN */
int (*enable)(struct device *dev, bool enable);
};
/** @cond INTERNAL_HIDDEN */
#define CANBUS_L2_CTX_TYPE struct net_canbus_context *
/**
* Context for canbus net device.
*/
struct canbus_net_ctx {
/** Filter ID for link layer duplicate address detection. */
int dad_filter_id;
/** Work item for responding to link layer DAD requests. */
struct k_work dad_work;
/** The interface associated with this device */
struct net_if *iface;
/** The link layer address chosen for this interface */
u16_t ll_addr;
};
/**
* Canbus link layer addresses have a length of 14 bit for source and destination.
* Both together are 28 bit to fit a CAN extended identifier with 29 bit length.
*/
struct net_canbus_lladdr {
u16_t addr : 14;
};
/**
* STmin is split in two valid ranges:
* 0-127: 0ms-127ms
* 128-240: Reserved
* 241-249: 100us-900us (multiples of 100us)
* 250- : Reserved
*/
struct canbus_fc_opts {
/** Block size. Number of CF PDUs before next CF is sent */
u8_t bs;
/**< Minimum separation time. Min time between frames */
u8_t stmin;
};
/**
* Context for a transmission of messages that didn't fit in a single frame.
* These messages Start with a FF (First Frame) that is in case of unicast
* acknowledged by a FC (Frame Control). After that, one or more CF
* (Consecutive frames) carry the rest of the message.
*/
struct canbus_isotp_tx_ctx {
/** Pkt containing the data to transmit */
struct net_pkt *pkt;
/** Timeout for TX Timeout and separation time */
struct _timeout timeout;
/** Frame Control options received from FC frame */
struct canbus_fc_opts opts;
/** CAN destination address */
struct net_canbus_lladdr dest_addr;
/** Remaining data to transmit in bytes */
u16_t rem_len;
/** Number of bytes in the tx queue */
s8_t tx_backlog;
/** State of the transmission */
u8_t state;
/** Actual block number that is transmitted. Counts from BS to 0 */
u8_t act_block_nr;
/** Number of WAIT frames received */
u8_t wft;
/** Sequence number that is added to CF */
u8_t sn : 4;
/** Transmission is multicast */
u8_t is_mcast : 1;
};
/**
* Context for reception of messages that are not single frames.
* This is the counterpart of the canbus_isotp_tx_ctx.
*/
struct canbus_isotp_rx_ctx {
/** Pkt that is large enough to hold the entire message */
struct net_pkt *pkt;
/** Timeout for RX timeout*/
struct _timeout timeout;
/** Remaining data to receive. Goes from message length to zero */
u16_t rem_len;
/** State of the reception */
u8_t state;
/** Number of frames received in this block. Counts from BS to 0 */
u8_t act_block_nr;
/** Number of WAIT frames transmitted */
u8_t wft;
/** Expected sequence number in CF */
u8_t sn : 4;
};
/**
* Initialization of the canbus L2.
*
* This function starts the TX workqueue and does some initialization.
*/
void net_6locan_init(struct net_if *iface);
/**
* Ethernet frame input function for Ethernet to 6LoCAN translation
*
* This function checks the destination link layer address for addresses
* that has to be forwarded. Frames that need to be forwarded are forwarded here.
*/
enum net_verdict net_canbus_translate_eth_frame(struct net_if *iface,
struct net_pkt *pkt);
/** @endcond */
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_NET_CAN_H_ */

View file

@ -1038,7 +1038,8 @@ static inline void net_ipv6_addr_create_iid(struct in6_addr *addr,
/* The generated IPv6 shall not toggle the
* Universal/Local bit. RFC 6282 ch 3.2.2
*/
if (lladdr->type == NET_LINK_IEEE802154) {
if (lladdr->type == NET_LINK_IEEE802154 ||
lladdr->type == NET_LINK_CANBUS) {
UNALIGNED_PUT(0, &addr->s6_addr32[2]);
addr->s6_addr[11] = 0xff;
addr->s6_addr[12] = 0xfe;

View file

@ -120,6 +120,11 @@ NET_L2_DECLARE_PUBLIC(OPENTHREAD_L2);
NET_L2_DECLARE_PUBLIC(CANBUS_RAW_L2);
#endif /* CONFIG_NET_L2_CANBUS_RAW */
#ifdef CONFIG_NET_L2_CANBUS
#define CANBUS_L2 CANBUS
NET_L2_DECLARE_PUBLIC(CANBUS_L2);
#endif /* CONFIG_NET_L2_CANBUS */
#define NET_L2_INIT(_name, _recv_fn, _send_fn, _enable_fn, _get_flags_fn) \
const struct net_l2 (NET_L2_GET_NAME(_name)) __used \
__attribute__((__section__(".net_l2.init"))) = { \

View file

@ -57,6 +57,8 @@ enum net_link_type {
NET_LINK_DUMMY,
/** CANBUS link address. */
NET_LINK_CANBUS_RAW,
/** 6loCAN link address. */
NET_LINK_CANBUS,
} __packed;
/**

View file

@ -41,6 +41,8 @@ extern "C" {
*/
struct net_context;
struct canbus_net_isotp_tx_ctx;
struct canbus_net_isotp_rx_ctx;
/* buffer cursor used in net_pkt */
@ -208,6 +210,12 @@ struct net_pkt {
#if defined(CONFIG_IEEE802154)
u8_t ieee802154_rssi; /* Received Signal Strength Indication */
u8_t ieee802154_lqi; /* Link Quality Indicator */
#endif
#if defined(CONFIG_NET_L2_CANBUS)
union {
struct canbus_isotp_tx_ctx *canbus_tx_ctx;
struct canbus_isotp_rx_ctx *canbus_rx_ctx;
};
#endif
/* @endcond */
};

View file

@ -12,7 +12,7 @@ CONFIG_NET_MGMT=n
CONFIG_NET_TCP=n
CONFIG_NET_UDP=n
CONFIG_NET_DEFAULT_IF_CANBUS=y
CONFIG_NET_DEFAULT_IF_CANBUS_RAW=y
CONFIG_NET_PKT_RX_COUNT=30
CONFIG_NET_PKT_TX_COUNT=30

View file

@ -81,7 +81,7 @@ static int create_socket(const struct can_filter *filter)
}
can_addr.can_ifindex = net_if_get_by_iface(
net_if_get_first_by_type(&NET_L2_GET_NAME(CANBUS)));
net_if_get_first_by_type(&NET_L2_GET_NAME(CANBUS_RAW)));
can_addr.can_family = PF_CAN;
ret = bind(fd, (struct sockaddr *)&can_addr, sizeof(can_addr));
@ -170,7 +170,7 @@ static int setup_socket(void)
can_copy_zfilter_to_filter(&zfilter, &filter);
iface = net_if_get_first_by_type(&NET_L2_GET_NAME(CANBUS));
iface = net_if_get_first_by_type(&NET_L2_GET_NAME(CANBUS_RAW));
if (!iface) {
LOG_ERR("No CANBUS network interface found!");
return -ENOENT;

View file

@ -547,9 +547,14 @@ config NET_DEFAULT_IF_DUMMY
depends on NET_L2_DUMMY
config NET_DEFAULT_IF_CANBUS
bool "Socket CAN interface"
bool "6LoCAN (IPv6 over CAN) interface"
depends on NET_L2_CANBUS
config NET_DEFAULT_IF_CANBUS_RAW
bool "Socket CAN interface"
depends on NET_L2_CANBUS_RAW
endchoice
config NET_PKT_TIMESTAMP

View file

@ -21,7 +21,7 @@ LOG_MODULE_REGISTER(net_sockets_can, CONFIG_NET_SOCKETS_LOG_LEVEL);
enum net_verdict net_canbus_socket_input(struct net_pkt *pkt)
{
if (net_pkt_family(pkt) == AF_CAN &&
net_if_l2(net_pkt_iface(pkt)) == &NET_L2_GET_NAME(CANBUS)) {
net_if_l2(net_pkt_iface(pkt)) == &NET_L2_GET_NAME(CANBUS_RAW)) {
return net_conn_input(pkt, NULL, CAN_RAW, NULL);
}

View file

@ -976,6 +976,8 @@ static inline u8_t get_llao_len(struct net_if *iface)
return 8;
} else if (net_if_get_link_addr(iface)->len == 8U) {
return 16;
} else if (net_if_get_link_addr(iface)->len == 2U) {
return 8;
}
/* What else could it be? */

View file

@ -446,11 +446,11 @@ static int bind_default(struct net_context *context)
if (context->iface >= 0) {
return 0;
} else {
#if defined(CONFIG_NET_L2_CANBUS)
#if defined(CONFIG_NET_L2_CANBUS_RAW)
struct net_if *iface;
iface = net_if_get_first_by_type(
&NET_L2_GET_NAME(CANBUS));
&NET_L2_GET_NAME(CANBUS_RAW));
if (!iface) {
return -ENOENT;
}

View file

@ -399,6 +399,9 @@ struct net_if *net_if_get_default(void)
#if defined(CONFIG_NET_DEFAULT_IF_OFFLOAD)
iface = net_if_get_first_by_type(NULL);
#endif
#if defined(CONFIG_NET_DEFAULT_IF_CANBUS_RAW)
iface = net_if_get_first_by_type(&NET_L2_GET_NAME(CANBUS_RAW));
#endif
#if defined(CONFIG_NET_DEFAULT_IF_CANBUS)
iface = net_if_get_first_by_type(&NET_L2_GET_NAME(CANBUS));
#endif

View file

@ -207,6 +207,16 @@ static const char *iface2str(struct net_if *iface, const char **extra)
}
#endif
#ifdef CONFIG_NET_L2_CANBUS_RAW
if (net_if_l2(iface) == &NET_L2_GET_NAME(CANBUS_RAW)) {
if (extra) {
*extra = "==========";
}
return "CANBUS_RAW";
}
#endif
if (extra) {
*extra = "==============";
}

View file

@ -172,7 +172,9 @@ static inline u32_t retry_timeout(const struct net_tcp *tcp)
((IS_ENABLED(CONFIG_NET_L2_BT) && \
net_pkt_lladdr_dst(pkt)->type == NET_LINK_BLUETOOTH) || \
(IS_ENABLED(CONFIG_NET_L2_IEEE802154) && \
net_pkt_lladdr_dst(pkt)->type == NET_LINK_IEEE802154)))
net_pkt_lladdr_dst(pkt)->type == NET_LINK_IEEE802154) || \
(IS_ENABLED(CONFIG_NET_L2_CANBUS) && \
net_pkt_lladdr_dst(pkt)->type == NET_LINK_CANBUS)))
/* The ref should not be done for Bluetooth and IEEE 802.15.4 which use
* IPv6 header compression (6lo). For BT and 802.15.4 we copy the pkt

View file

@ -95,6 +95,9 @@ char *net_sprint_ll_addr_buf(const u8_t *ll, u8_t ll_len,
case 6:
len = 6U;
break;
case 2:
len = 2U;
break;
default:
len = 6U;
break;

View file

@ -28,6 +28,6 @@ if(CONFIG_NET_L2_WIFI_MGMT OR CONFIG_NET_L2_WIFI_SHELL)
add_subdirectory(wifi)
endif()
if(CONFIG_NET_L2_CANBUS)
if(CONFIG_NET_L2_CANBUS OR CONFIG_NET_L2_CANBUS_RAW)
add_subdirectory(canbus)
endif()

View file

@ -77,6 +77,8 @@ source "subsys/net/l2/ieee802154/Kconfig"
source "subsys/net/l2/openthread/Kconfig"
source "subsys/net/l2/canbus/Kconfig"
config NET_L2_WIFI_MGMT
bool "Enable Wi-Fi Management support"
select NET_MGMT
@ -100,9 +102,4 @@ config NET_L2_WIFI_SHELL
This can be used for controlling Wi-Fi through the console via
exposing a shell module named "wifi".
config NET_L2_CANBUS
bool "Enable CANBUS l2 layer"
help
Add a CANBUS L2 layer driver.
endmenu

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,10 @@
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_include_directories(. ${ZEPHYR_BASE}/subsys/net/ip)
zephyr_library_compile_definitions_ifdef(
CONFIG_NEWLIB_LIBC __LINUX_ERRNO_EXTENSIONS__
)
zephyr_library_sources_ifdef(CONFIG_NET_L2_CANBUS canbus.c)
zephyr_library_sources_ifdef(CONFIG_NET_L2_CANBUS_RAW canbus_raw.c)
zephyr_library_sources_ifdef(CONFIG_NET_L2_CANBUS 6locan.c)

View file

@ -0,0 +1,68 @@
#
# Copyright (c) 2019 Alexander Wachter
#
# SPDX-License-Identifier: Apache-2.0
#
config NET_L2_CANBUS
bool "Enable CANBUS L2 layer [EXPERIMENTAL]"
depends on CAN_NET
select NET_6LO
help
Add a CANBUS L2 layer driver. This is the layer for IPv6 over CAN
(6loCAN). It uses IPHC to compress the IP header and ISO-TP for
flow control and reassembling.
if NET_L2_CANBUS
config NET_L2_CANBUS_USE_FIXED_ADDR
bool "Use fixed L2 address"
help
Use a fixed L2 address for 6LoCAN instead of a random chosen one.
config NET_L2_CANBUS_FIXED_ADDR
hex "L2 address"
depends on NET_L2_CANBUS_USE_FIXED_ADDR
range 0x00FF 0x3DEF
config NET_L2_CANBUS_DAD_RETRIES
int "Number of DAD retries"
default 5
help
Number of retries for Duplicate Address Detection.
Greater than one only makes sense for random link layer addresses.
config NET_L2_CANBUS_STMIN
int "STmin"
default 0
range 0 127
help
Minimal separation time between frames in ms.
The timer starts when the frame is queued and the next frame is
transmitted after expiration.
STmin is chosen by the receiver and transmitted in the FC
(Flow Control) frame. See also: ISO 15765-2:2016
config NET_L2_CANBUS_BS
int "BS (Block Size)"
default 8
range 0 256
help
Number of CF (Contiguous Frame) PDUs before next FC (Flow Control)
frame is sent. Zero value means all frames are sent consecutive
without an additional FC frame.
A BS counter at the sender counts from one to BS. When BS is reached,
the sender waits for a FC frame again an BS is reset.
See also: ISO 15765-2:2016
module = NET_L2_CANBUS
module-dep = NET_LOG
module-str = Log level for CANbus L2 layer
module-help = Enables CANbus L2 to output debug messages.
source "subsys/net/Kconfig.template.log_config.net"
endif #NET_L2_CANBUS
config NET_L2_CANBUS_RAW
bool "Enable CANBUS RAW l2 layer"
help
Add a CANBUS L2 layer driver. This is the layer for SOCKET CAN.

View file

@ -1,49 +0,0 @@
/*
* Copyright (c) 2019 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <logging/log.h>
LOG_MODULE_REGISTER(net_l2_canbus, LOG_LEVEL_NONE);
#include <net/net_core.h>
#include <net/net_l2.h>
#include <net/net_if.h>
#include <net/net_pkt.h>
#include <net/socket_can.h>
static inline enum net_verdict canbus_recv(struct net_if *iface,
struct net_pkt *pkt)
{
net_pkt_lladdr_src(pkt)->addr = NULL;
net_pkt_lladdr_src(pkt)->len = 0U;
net_pkt_lladdr_src(pkt)->type = NET_LINK_CANBUS;
net_pkt_lladdr_dst(pkt)->addr = NULL;
net_pkt_lladdr_dst(pkt)->len = 0U;
net_pkt_lladdr_dst(pkt)->type = NET_LINK_CANBUS;
net_pkt_set_family(pkt, AF_CAN);
return NET_CONTINUE;
}
static inline int canbus_send(struct net_if *iface, struct net_pkt *pkt)
{
const struct canbus_api *api = net_if_get_device(iface)->driver_api;
int ret;
if (!api) {
return -ENOENT;
}
ret = api->send(net_if_get_device(iface), pkt);
if (!ret) {
ret = net_pkt_get_len(pkt);
net_pkt_unref(pkt);
}
return ret;
}
NET_L2_INIT(CANBUS_L2, canbus_recv, canbus_send, NULL, NULL);

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2019 Alexander Wachter
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_SUBSYS_NET_L2_CANBUS_INTERNAL_H_
#define ZEPHYR_SUBSYS_NET_L2_CANBUS_INTERNAL_H_
#ifdef NET_CAN_USE_CAN_FD
#define NET_CAN_DL 64
#else
#define NET_CAN_DL 8
#endif/*NET_CAN_USE_CAN_FD*/
/* Protocol control information*/
#define NET_CAN_PCI_SF 0x00 /* Single frame*/
#define NET_CAN_PCI_FF 0x01 /* First frame */
#define NET_CAN_PCI_CF 0x02 /* Consecutive frame */
#define NET_CAN_PCI_FC 0x03 /* Flow control frame */
#define NET_CAN_PCI_TYPE_BYTE 0
#define NET_CAN_PCI_TYPE_POS 4
#define NET_CAN_PCI_TYPE_MASK 0xF0
#define NET_CAN_PCI_TYPE_SF (NET_CAN_PCI_SF << NET_CAN_PCI_TYPE_POS)
#define NET_CAN_PCI_TYPE_FF (NET_CAN_PCI_FF << NET_CAN_PCI_TYPE_POS)
#define NET_CAN_PCI_TYPE_CF (NET_CAN_PCI_CF << NET_CAN_PCI_TYPE_POS)
#define NET_CAN_PCI_TYPE_FC (NET_CAN_PCI_FC << NET_CAN_PCI_TYPE_POS)
#define NET_CAN_PCI_SF_DL_MASK 0x0F
#define NET_CAN_PCI_FF_DL_UPPER_BYTE 0
#define NET_CAN_PCI_FF_DL_UPPER_MASK 0x0F
#define NET_CAN_PCI_FF_DL_LOWER_BYTE 1
#define NET_CAN_PCI_FS_BYTE 0
#define NET_CAN_PCI_FS_MASK 0x0F
#define NET_CAN_PCI_BS_BYTE 1
#define NET_CAN_PCI_ST_MIN_BYTE 2
#define NET_CAN_PCI_FS_CTS 0x0
#define NET_CAN_PCI_FS_WAIT 0x1
#define NET_CAN_PCI_FS_OVFLW 0x2
#define NET_CAN_PCI_SN_MASK 0x0F
#define NET_CAN_FF_DL_MIN (NET_CAN_CAN_DL)
#define NET_CAN_WFT_FIRST 0xFF
#define NET_CAN_BS_TIME K_MSEC(1000)
#define NET_CAN_A_TIME K_MSEC(1000)
#define NET_CAN_FF_CF_TIME K_MSEC(1)
#define NET_CAN_STMIN_MAX 0xFA
#define NET_CAN_STMIN_MS_MAX 0x7F
#define NET_CAN_STMIN_US_BEGIN 0xF1
#define NET_CAN_STMIN_US_END 0xF9
#ifdef __cplusplus
extern "C" {
#endif
enum net_can_isotp_tx_state {
NET_CAN_TX_STATE_UNUSED,
NET_CAN_TX_STATE_RESET,
NET_CAN_TX_STATE_WAIT_FC,
NET_CAN_TX_STATE_SEND_CF,
NET_CAN_TX_STATE_WAIT_ST,
NET_CAN_TX_STATE_WAIT_TX_BACKLOG,
NET_CAN_TX_STATE_FIN,
NET_CAN_TX_STATE_ERR
};
enum net_can_isotp_rx_state {
NET_CAN_RX_STATE_UNUSED,
NET_CAN_RX_STATE_RESET,
NET_CAN_RX_STATE_FF,
NET_CAN_RX_STATE_CF,
NET_CAN_RX_STATE_FIN,
NET_CAN_RX_STATE_TIMEOUT
};
struct canbus_l2_ctx {
struct canbus_isotp_tx_ctx tx_ctx[CONFIG_NET_PKT_TX_COUNT];
struct canbus_isotp_rx_ctx rx_ctx[CONFIG_NET_PKT_RX_COUNT];
struct k_mutex tx_ctx_mtx;
struct k_mutex rx_ctx_mtx;
struct k_sem tx_sem;
};
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_SUBSYS_NET_L2_CANBUS_INTERNAL_H_ */

View file

@ -95,6 +95,7 @@ CONFIG_NET_L2_IEEE802154_SECURITY=y
CONFIG_NET_L2_IEEE802154_SECURITY_CRYPTO_DEV_NAME="CRYPTO-DEV"
CONFIG_NET_L2_DUMMY=y
CONFIG_NET_L2_ETHERNET=y
CONFIG_NET_L2_CANBUS=y
CONFIG_NET_L2_CANBUS_RAW=y
CONFIG_NET_L2_ETHERNET_MGMT=y
CONFIG_NET_L2_IEEE802154_RADIO_DFLT_TX_POWER=2
@ -368,6 +369,7 @@ CONFIG_NET_SOCKETS_TLS_MAX_CREDENTIALS=10
# Network interface defaults
CONFIG_NET_DEFAULT_IF_BLUETOOTH=y
CONFIG_NET_DEFAULT_IF_CANBUS=y
CONFIG_NET_DEFAULT_IF_CANBUS_RAW=y
CONFIG_NET_DEFAULT_IF_DUMMY=y
CONFIG_NET_DEFAULT_IF_ETHERNET=y