From 93b7a951335fe48e738d7fb63bd6e4e8091a0498 Mon Sep 17 00:00:00 2001 From: Vipin Anand Date: Fri, 16 Nov 2018 13:23:36 +0530 Subject: [PATCH] net: socket: add PF_CAN protocol for socket can this patch add support for PF_CAN protocol and CAN_RAW type sockets, also it adds common APIs for socket can driver and header file. Signed-off-by: Vipin Anand --- include/net/net_context.h | 37 +++- include/net/net_ip.h | 4 + include/net/net_l2.h | 6 + include/net/socket.h | 14 ++ include/net/socket_can.h | 158 +++++++++++++++++ subsys/net/ip/CMakeLists.txt | 1 + subsys/net/ip/connection.c | 49 +++++- subsys/net/ip/connection.h | 13 ++ subsys/net/ip/net_context.c | 117 ++++++++++--- subsys/net/ip/net_core.c | 21 ++- subsys/net/ip/net_pkt.c | 20 ++- subsys/net/ip/utils.c | 4 + subsys/net/l2/CMakeLists.txt | 4 + subsys/net/l2/Kconfig | 6 + subsys/net/l2/can/CMakeLists.txt | 4 + subsys/net/l2/can/can_l2.c | 40 +++++ subsys/net/lib/sockets/CMakeLists.txt | 1 + subsys/net/lib/sockets/Kconfig | 7 + subsys/net/lib/sockets/socket_can.c | 237 ++++++++++++++++++++++++++ subsys/net/lib/sockets/sockets.c | 23 ++- 20 files changed, 737 insertions(+), 29 deletions(-) mode change 100644 => 100755 include/net/socket.h create mode 100644 include/net/socket_can.h create mode 100644 subsys/net/l2/can/CMakeLists.txt create mode 100644 subsys/net/l2/can/can_l2.c create mode 100644 subsys/net/lib/sockets/socket_can.c mode change 100644 => 100755 subsys/net/lib/sockets/sockets.c diff --git a/include/net/net_context.h b/include/net/net_context.h index 9b1c2ec96d8c69..686d1eb9eb2058 100644 --- a/include/net/net_context.h +++ b/include/net/net_context.h @@ -27,6 +27,8 @@ #include #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -287,7 +289,7 @@ struct net_context { u8_t iface; /** Flags for the context */ - u8_t flags; + u16_t flags; }; static inline bool net_context_is_used(struct net_context *context) @@ -354,6 +356,11 @@ static inline sa_family_t net_context_get_family(struct net_context *context) return AF_INET6; } + if (IS_ENABLED(CONFIG_SOCKET_CAN) && + (context->flags & CAN_CONTEXT_FAMILY)) { + return AF_CAN; + } + return AF_INET; } @@ -376,6 +383,12 @@ static inline void net_context_set_family(struct net_context *context, return; } + if (IS_ENABLED(CONFIG_SOCKET_CAN) && + (family == AF_CAN)) { + context->flags |= CAN_CONTEXT_FAMILY; + return; + } + context->flags &= ~NET_CONTEXT_FAMILY; } @@ -398,6 +411,11 @@ enum net_sock_type net_context_get_type(struct net_context *context) return SOCK_STREAM; } + if (IS_ENABLED(CONFIG_SOCKET_CAN) && + (context->flags & CAN_CONTEXT_FAMILY)) { + return SOCK_RAW; + } + return SOCK_DGRAM; } @@ -420,6 +438,12 @@ static inline void net_context_set_type(struct net_context *context, return; } + if (IS_ENABLED(CONFIG_SOCKET_CAN) && + (type == SOCK_RAW)) { + context->flags |= CAN_CONTEXT_TYPE; + return; + } + context->flags &= ~NET_CONTEXT_TYPE; } @@ -442,6 +466,11 @@ enum net_ip_protocol net_context_get_ip_proto(struct net_context *context) return IPPROTO_TCP; } + if (IS_ENABLED(CONFIG_SOCKET_CAN) && + (context->flags & CAN_CONTEXT_PROTO)) { + return CAN_RAW; + } + return IPPROTO_UDP; } @@ -464,6 +493,12 @@ static inline void net_context_set_ip_proto(struct net_context *context, return; } + if (IS_ENABLED(CONFIG_SOCKET_CAN) && + (ip_proto == CAN_RAW)) { + context->flags |= CAN_CONTEXT_PROTO; + return; + } + context->flags &= ~NET_CONTEXT_PROTO; } diff --git a/include/net/net_ip.h b/include/net/net_ip.h index 45ac7b865cce58..f34ec840627b5d 100644 --- a/include/net/net_ip.h +++ b/include/net/net_ip.h @@ -40,11 +40,13 @@ extern "C" { #define PF_UNSPEC 0 /* Unspecified. */ #define PF_INET 2 /* IP protocol family. */ #define PF_INET6 10 /* IP version 6. */ +#define PF_CAN 13 /* CAN protocol family */ /** Address families. */ #define AF_UNSPEC PF_UNSPEC #define AF_INET PF_INET #define AF_INET6 PF_INET6 +#define AF_CAN PF_CAN /* CAN address family */ /** Protocol numbers from IANA */ enum net_ip_protocol { @@ -52,6 +54,7 @@ enum net_ip_protocol { IPPROTO_TCP = 6, IPPROTO_UDP = 17, IPPROTO_ICMPV6 = 58, + CAN_RAW = 252, }; /* Protocol numbers for TLS protocols */ @@ -67,6 +70,7 @@ enum net_ip_protocol_secure { enum net_sock_type { SOCK_STREAM = 1, SOCK_DGRAM, + SOCK_RAW, }; #define ntohs(x) sys_be16_to_cpu(x) diff --git a/include/net/net_l2.h b/include/net/net_l2.h index 1b79f2c06f4bb3..e805baa1188044 100644 --- a/include/net/net_l2.h +++ b/include/net/net_l2.h @@ -103,6 +103,12 @@ NET_L2_DECLARE_PUBLIC(BLUETOOTH_L2); NET_L2_DECLARE_PUBLIC(OPENTHREAD_L2); #endif /* CONFIG_NET_L2_OPENTHREAD */ +#ifdef CONFIG_NET_L2_CAN +#define CAN_L2 CAN +#define CAN_L2_CTX_TYPE void* +NET_L2_DECLARE_PUBLIC(CAN_L2); +#endif /* CONFIG_NET_L2_CAN */ + #define NET_L2_INIT(_name, _recv_fn, _send_fn, _reserve_fn, _enable_fn, \ _get_flags_fn) \ const struct net_l2 (NET_L2_GET_NAME(_name)) __used \ diff --git a/include/net/socket.h b/include/net/socket.h old mode 100644 new mode 100755 index e8409b8ed1c8d8..e748e38205d6cc --- a/include/net/socket.h +++ b/include/net/socket.h @@ -52,6 +52,10 @@ struct zsock_pollfd { */ #define SOL_TLS 282 +/* Protocl level of CAN */ +#define SOL_CAN_BASE 100 +#define SOL_CAN_RAW (SOL_CAN_BASE + CAN_RAW) + /* Socket options for TLS */ /* Socket option to select TLS credentials to use. It accepts and returns an @@ -93,6 +97,16 @@ struct zsock_pollfd { * 0 - client, * 1 - server. */ + +/* Socket optaions for CAN */ + +/* Get ifindex for corresponding socket*/ +#define SOCKET_CAN_GET_IF_INDEX 6 +/* Confifgure CAN controller operation mode defined in can.h */ +#define SOCKET_CAN_SET_MODE 7 +/* Configure CAN filter for acceptance filtering */ +#define SOCKET_CAN_SET_FILTER 8 + #define TLS_DTLS_ROLE 6 struct zsock_addrinfo { diff --git a/include/net/socket_can.h b/include/net/socket_can.h new file mode 100644 index 00000000000000..ce5f1818173a82 --- /dev/null +++ b/include/net/socket_can.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SOCKET_CAN_H_ +#define _SOCKET_CAN_H_ + +#include +#include +#include +#include + +/** Max length of socket packet */ +#define CAN_NET_MTU (72) + +/** Protocol family of socket can connection */ +#define CAN_CONTEXT_FAMILY BIT(8) + +/** Context type of socket can connection */ +#define CAN_CONTEXT_TYPE BIT(9) + +/** Context proto for socket can connection */ +#define CAN_CONTEXT_PROTO BIT(10) + +/** + * @brief socket addr structure for AF_CAN protocol + * + * Socket address structure for AF_CAN protocol family + * + */ +struct sockaddr_can { + /** protocol family for socket can */ + sa_family_t can_family; + /** net_if interface associated with socket */ + u8_t can_ifindex; +}; + +/** + * @brief check matched CAN filter for incoming CAN message. + * + * This routine matches id with configured filters id and return true or false. + * * + * @param dev Pointer to the device structure for the driver instance. + * @param pkt incoming net_pkt + * + * @retval 1 if filter matched otherwise 0. + */ +typedef int (*socket_can_check_filter_matched_t)(struct device *dev, + struct net_pkt *pkt); + +/** + * @brief configure filter for accpetance filter. + * + * This routine configure can filter and register rx callback. + * * + * @param dev Pointer to the device structure for the driver instance. + * @param filter can_filter structure + * + * @retval return < 0 in case of error and 0 for success. + */ +typedef int (*socket_can_config_filter_t)(struct device *dev, + struct can_filter *filter); + +int socket_can_get_opt(struct net_context *context, int optname, + void *optval, socklen_t *optlen); +int socket_can_set_opt(struct net_context *context, int optname, + const void *optval, socklen_t optlen); + + + +/** + * @brief socket can driver api structure + * Socket CAN driver apis for iface interface functions and ioctl call. + * + */ +struct socket_can_driver_api_t { + /** iface interface for socket apis to send and init function*/ + struct net_if_api iface_api; + /** check matching filter for loopback messages */ + socket_can_check_filter_matched_t check_matched_filter; + /** configure filter with rx callback */ + socket_can_config_filter_t config_filter; +}; + +/** + * @brief socket can context structure + * + * socket can driver specific structure. + * + */ +struct socket_can_context { + /** id of CAN instance */ + u32_t id; + /** iface interface reference structure*/ + struct net_if *iface; + /** can device structure reference */ + struct device *can_dev; +}; + +/** + * @brief socket can mode structure + * + * This structure will be passed via setSocketOpt and configure can controller + * operation mode as well as baud rate + */ +struct socket_can_mode { + enum can_mode op_mode; + u32_t baud_rate; +}; + +__syscall int socket_can_check_filter_matched(struct device *dev, + struct net_pkt *pkt); + +static inline int _impl_socket_can_check_filter_matched(struct device *dev, + struct net_pkt *pkt) +{ + const struct socket_can_driver_api_t *api = NULL; + int result = 0; + + if (pkt == NULL) { + goto err; + } + + api = dev->driver_api; + if (api && api->check_matched_filter) { + result = api->check_matched_filter(dev, pkt); + } +err: + return result; +} + +__syscall int socket_can_config_filter(struct device *dev, + struct can_filter *filter); + +static inline int _impl_socket_can_config_filter(struct device *dev, + struct can_filter *filter) +{ + const struct socket_can_driver_api_t *api = NULL; + int res = 0; + + if (filter == NULL) { + res = -EBADF; + goto err; + } + + api = dev->driver_api; + if (api && api->config_filter) { + res = api->config_filter(dev, filter); + } +err: + return res; +} + +#include + +#endif /*_SOCKET_CAN_H_ */ diff --git a/subsys/net/ip/CMakeLists.txt b/subsys/net/ip/CMakeLists.txt index 00deeadaf97515..cf09b987cb9dd3 100644 --- a/subsys/net/ip/CMakeLists.txt +++ b/subsys/net/ip/CMakeLists.txt @@ -31,6 +31,7 @@ zephyr_library_sources_ifdef(CONFIG_NET_TCP connection.c tcp.c) zephyr_library_sources_ifdef(CONFIG_NET_TRICKLE trickle.c) zephyr_library_sources_ifdef(CONFIG_NET_UDP connection.c udp.c) zephyr_library_sources_ifdef(CONFIG_NET_PROMISCUOUS_MODE promiscuous.c) +zephyr_library_sources_ifdef(CONFIG_SOCKET_CAN connection.c) if(CONFIG_NET_SHELL) zephyr_library_include_directories(. ${ZEPHYR_BASE}/subsys/net/l2) diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c index 1e3b0c0b479735..b1dbe5a6b72721 100644 --- a/subsys/net/ip/connection.c +++ b/subsys/net/ip/connection.c @@ -603,7 +603,10 @@ int net_conn_register(enum net_ip_protocol proto, } } else #endif - { + if (IS_ENABLED(CONFIG_SOCKET_CAN) && + (local_addr->sa_family == AF_CAN)) { + conns[i].local_addr.sa_family = AF_CAN; + } else { NET_ERR("Remote address family not set"); return -EINVAL; } @@ -639,7 +642,12 @@ int net_conn_register(enum net_ip_protocol proto, } } else #endif - { + if (IS_ENABLED(CONFIG_SOCKET_CAN) && + (local_addr->sa_family == AF_CAN)) { + memcpy(&conns[i].local_addr, + local_addr, + sizeof(struct sockaddr_can)); + } else { NET_ERR("Local address family not set"); return -EINVAL; } @@ -1053,3 +1061,40 @@ void net_conn_init(void) } while (0); #endif /* CONFIG_NET_CONN_CACHE */ } +#if defined(CONFIG_SOCKET_CAN) +extern bool socket_can_check_matched_id_filter(struct net_pkt *pkt); + +enum net_verdict can_conn_input(struct net_pkt *pkt, bool loopback) +{ + int i; + int ret = NET_DROP; + + if (!pkt || !(pkt->frags)) { + ret = NET_CONTINUE; + goto err; + } + for (i = 0; i < CONFIG_NET_MAX_CONN; i++) { + if ((conns[i].flags & NET_CONN_IN_USE) && + (conns[i].proto == CAN_RAW)) { + if (loopback) { + if (!socket_can_check_matched_id_filter(pkt)) { + /* No filter matched but dont unref */ + /* net_pkt data */ + ret = NET_OK; + goto err; + } + } + + if (conns[i].cb(&conns[i], pkt, conns[i].user_data) + == NET_DROP) { + goto err; + } + ret = NET_OK; + break; + } + } +err: + return ret; +} +#endif + diff --git a/subsys/net/ip/connection.h b/subsys/net/ip/connection.h index 266b1dc5d6fc15..1c711530194985 100644 --- a/subsys/net/ip/connection.h +++ b/subsys/net/ip/connection.h @@ -21,6 +21,8 @@ #include #include +#include + #ifdef __cplusplus extern "C" { #endif @@ -164,6 +166,17 @@ void net_conn_foreach(net_conn_foreach_cb_t cb, void *user_data); void net_conn_init(void); +#if defined(CONFIG_SOCKET_CAN) +/** + * @brief Trigger connection callback for sending a can packet and loopback. + * + * @param pkt Pointer to net_pkt structure + * @param loopback boolean for loopback transmission + * @return net_verdict NET_OK is callback triggered else NET_DROP. + */ +enum net_verdict can_conn_input(struct net_pkt *pkt, bool loopback); +#endif + #ifdef __cplusplus } #endif diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c index b9a0254d295682..ad49fdb98f7a6f 100644 --- a/subsys/net/ip/net_context.c +++ b/subsys/net/ip/net_context.c @@ -129,6 +129,11 @@ int net_context_get(sa_family_t family, return -EPFNOSUPPORT; } #endif + if (!IS_ENABLED(CONFIG_SOCKET_CAN) && (family == AF_CAN)) { + NET_ASSERT_INFO((family != AF_CAN), "AF_CAN disabled"); + return -EPFNOSUPPORT; + } + #if !defined(CONFIG_NET_UDP) if (type == SOCK_DGRAM) { @@ -155,31 +160,51 @@ int net_context_get(sa_family_t family, return -EPROTONOSUPPORT; } #endif + if (!IS_ENABLED(CONFIG_SOCKET_CAN) && (type == SOCK_RAW)) { + NET_ASSERT_INFO((type != SOCK_RAW), "SOCKET RAW disabled"); + return -EPROTOTYPE; + } - if (family != AF_INET && family != AF_INET6) { - NET_ASSERT_INFO(family == AF_INET || family == AF_INET6, - "Unknown address family %d", family); + if (!IS_ENABLED(CONFIG_SOCKET_CAN) && (ip_proto == CAN_RAW)) { + NET_ASSERT_INFO(ip_proto != CAN_RAW, "CAN_RAW disabled"); + return -EPROTONOSUPPORT; + } + + if (family != AF_INET && family != AF_INET6 && + (IS_ENABLED(CONFIG_SOCKET_CAN) && (family != AF_CAN))) { + NET_ASSERT_INFO(family == AF_INET || family == AF_INET6 || + (IS_ENABLED(CONFIG_SOCKET_CAN) && (family == AF_CAN)), + "Unknown address family %d", family); return -EAFNOSUPPORT; } - if (type != SOCK_DGRAM && type != SOCK_STREAM) { - NET_ASSERT_INFO(type == SOCK_DGRAM || type == SOCK_STREAM, - "Unknown context type"); + if (type != SOCK_DGRAM && type != SOCK_STREAM && + (IS_ENABLED(CONFIG_SOCKET_CAN) && (type != SOCK_RAW))) { + NET_ASSERT_INFO(type == SOCK_DGRAM || (type == SOCK_STREAM) || + (IS_ENABLED(CONFIG_SOCKET_CAN) && (type == SOCK_RAW)), + "Unknown context type"); return -EPROTOTYPE; } - if (ip_proto != IPPROTO_UDP && ip_proto != IPPROTO_TCP) { + if (ip_proto != IPPROTO_UDP && ip_proto != IPPROTO_TCP && + (IS_ENABLED(CONFIG_SOCKET_CAN) && (ip_proto != CAN_RAW))) { NET_ASSERT_INFO(ip_proto == IPPROTO_UDP || - ip_proto == IPPROTO_TCP, - "Unknown IP protocol %d", ip_proto); + ip_proto == IPPROTO_TCP || + (IS_ENABLED(CONFIG_SOCKET_CAN) && (ip_proto == CAN_RAW)), + "Unknown IP protocol %d", ip_proto); return -EPROTONOSUPPORT; } if ((type == SOCK_STREAM && ip_proto == IPPROTO_UDP) || - (type == SOCK_DGRAM && ip_proto == IPPROTO_TCP)) { + (type == SOCK_DGRAM && ip_proto == IPPROTO_TCP) || + (IS_ENABLED(CONFIG_SOCKET_CAN) && + (((type == SOCK_STREAM) && (ip_proto == CAN_RAW)) || + ((type == SOCK_RAW) && (ip_proto != CAN_RAW))))) { NET_ASSERT_INFO(\ - (type != SOCK_STREAM || ip_proto != IPPROTO_UDP) && - (type != SOCK_DGRAM || ip_proto != IPPROTO_TCP), + (type != SOCK_STREAM || ip_proto != IPPROTO_UDP) && + (type != SOCK_DGRAM || ip_proto != IPPROTO_TCP) && + (IS_ENABLED(CONFIG_SOCKET_CAN) && + ((type != SOCK_RAW) || (ip_proto != CAN_RAW))), "Context type and protocol mismatch, type %d proto %d", type, ip_proto); return -EOPNOTSUPP; @@ -581,7 +606,19 @@ int net_context_bind(struct net_context *context, const struct sockaddr *addr, return 0; } #endif - + /* user application need to call ioctl to get iface index and to need + * to pass same for binding with net context + */ + if (IS_ENABLED(CONFIG_SOCKET_CAN) && (addr->sa_family == AF_CAN)) { + struct sockaddr_can *addr_can = (struct sockaddr_can *)addr; + struct net_if *iface = net_if_get_by_index( + addr_can->can_ifindex); + if (!iface) { + return -EINVAL; + } + net_context_set_iface(context, iface); + return 0; + } return -EINVAL; } @@ -966,7 +1003,8 @@ static int sendto(struct net_pkt *pkt, return -EBADF; } - if (!dst_addr) { + if (!dst_addr && (IS_ENABLED(CONFIG_SOCKET_CAN) && + (net_context_get_ip_proto(context) != CAN_RAW))) { return -EDESTADDRREQ; } @@ -997,7 +1035,11 @@ static int sendto(struct net_pkt *pkt, } } else #endif /* CONFIG_NET_IPV4 */ - { + if (IS_ENABLED(CONFIG_SOCKET_CAN) && + (net_context_get_ip_proto(context) == CAN_RAW)) { + net_pkt_set_family(pkt, AF_CAN); + ret = 0; + } else { NET_DBG("Invalid protocol family %d", net_pkt_family(pkt)); return -EINVAL; } @@ -1027,6 +1069,11 @@ static int sendto(struct net_pkt *pkt, case IPPROTO_TCP: ret = net_tcp_queue_data(context, pkt); break; +#if defined(CONFIG_SOCKET_CAN) + case CAN_RAW: + ret = 0; + break; +#endif default: ret = -EPROTONOSUPPORT; @@ -1054,7 +1101,10 @@ static int sendto(struct net_pkt *pkt, case IPPROTO_TCP: return net_tcp_send_data(context, cb, token, user_data); - +#if defined(CONFIG_SOCKET_CAN) + case CAN_RAW: + return net_send_data(pkt); +#endif default: return -EPROTONOSUPPORT; } @@ -1080,8 +1130,10 @@ int net_context_send(struct net_pkt *pkt, } #endif /* CONFIG_NET_OFFLOAD */ - if (!(context->flags & NET_CONTEXT_REMOTE_ADDR_SET) || - !net_sin(&context->remote)->sin_port) { + if ((!(context->flags & NET_CONTEXT_REMOTE_ADDR_SET) || + !net_sin(&context->remote)->sin_port) && + (IS_ENABLED(CONFIG_SOCKET_CAN) && + (net_context_get_ip_proto(context) != CAN_RAW))) { return -EDESTADDRREQ; } @@ -1144,9 +1196,14 @@ enum net_verdict net_context_packet_received(struct net_conn *conn, return NET_DROP; } - if (net_context_get_ip_proto(context) != IPPROTO_TCP) { + if (net_context_get_ip_proto(context) != IPPROTO_TCP && + (IS_ENABLED(CONFIG_SOCKET_CAN) && + (net_context_get_ip_proto(context) != CAN_RAW))) { /* TCP packets get appdata earlier in tcp_established(). */ net_pkt_set_appdata_values(pkt, IPPROTO_UDP); + } else if (IS_ENABLED(CONFIG_SOCKET_CAN) && + (net_context_get_ip_proto(context) == CAN_RAW)) { + net_pkt_set_appdata_values(pkt, CAN_RAW); } else { net_stats_update_tcp_recv(net_pkt_iface(pkt), net_pkt_appdatalen(pkt)); @@ -1240,6 +1297,13 @@ int net_context_recv(struct net_context *context, void *user_data) { int ret; + +#if defined(CONFIG_SOCKET_CAN) + struct sockaddr local_addr = { + .sa_family = net_context_get_family(context), + }; +#endif + NET_ASSERT(context); if (!net_context_is_used(context)) { @@ -1264,7 +1328,20 @@ int net_context_recv(struct net_context *context, case IPPROTO_TCP: ret = net_tcp_recv(context, cb, user_data); break; - +#if defined(CONFIG_SOCKET_CAN) + case CAN_RAW: + if (context->conn_handler) { + return 0; + } + context->recv_cb = cb; + ret = net_conn_register(net_context_get_ip_proto(context), + NULL, + &local_addr, 0, 0, + net_context_packet_received, + user_data, + &context->conn_handler); + break; +#endif default: ret = -EPROTOTYPE; break; diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index 059e979daa55cd..b32a8a2883711f 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -89,6 +89,11 @@ static inline enum net_verdict process_data(struct net_pkt *pkt, } } + /* Check for CAN packets */ + if (IS_ENABLED(CONFIG_SOCKET_CAN) && (net_pkt_family(pkt) == AF_CAN)) { + return can_conn_input(pkt, is_loopback); + } + /* IP version and header length. */ switch (NET_IPV6_HDR(pkt)->vtc & 0xf0) { #if defined(CONFIG_NET_IPV6) @@ -248,8 +253,10 @@ static inline int check_ip_addr(struct net_pkt *pkt) } } else #endif /* CONFIG_NET_IPV4 */ - - { + if (IS_ENABLED(CONFIG_SOCKET_CAN) && + (net_pkt_family(pkt) == AF_CAN)) { + return 1; + } else { ; } @@ -284,6 +291,11 @@ int net_send_data(struct net_pkt *pkt) #endif status = check_ip_addr(pkt); + /* For Socket CAN it wil be sent to all nodes in the network */ + if (IS_ENABLED(CONFIG_SOCKET_CAN) && (net_pkt_family(pkt) == AF_CAN)) { + status = 1; + } + if (status < 0) { return status; } else if (status > 0) { @@ -292,7 +304,10 @@ int net_send_data(struct net_pkt *pkt) */ NET_DBG("Loopback pkt %p back to us", pkt); processing_data(pkt, true); - return 0; + + if (net_pkt_family(pkt) != AF_CAN) { + return 0; + } } if (net_if_send_data(net_pkt_iface(pkt), pkt) == NET_DROP) { diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c index 302f3ca8893418..6817932759cf4b 100644 --- a/subsys/net/ip/net_pkt.c +++ b/subsys/net/ip/net_pkt.c @@ -46,6 +46,8 @@ #else #if defined(CONFIG_NET_IPV4) #define MAX_IP_PROTO_LEN NET_IPV4H_LEN +#elif defined(CONFIG_SOCKET_CAN) +#define MAX_IP_PROTO_LEN #else #error "Either IPv6 or IPv4 needs to be selected." #endif /* IPv4 */ @@ -581,6 +583,10 @@ static struct net_pkt *net_pkt_get(struct k_mem_slab *slab, data_len -= NET_IPV4H_LEN; } + if (IS_ENABLED(CONFIG_SOCKET_CAN) && (family == AF_CAN)) { + data_len = max(iface_len, CAN_NET_MTU); + } + proto = net_context_get_ip_proto(context); if (IS_ENABLED(CONFIG_NET_TCP) && proto == IPPROTO_TCP) { @@ -1789,7 +1795,9 @@ static int net_pkt_get_addr(struct net_pkt *pkt, bool is_src, /* Set the family */ family = net_pkt_family(pkt); addr->sa_family = family; - + if (IS_ENABLED(CONFIG_SOCKET_CAN) && (family == PF_CAN)) { + return 0; + } /* Examine the transport protocol */ proto = net_pkt_transport_proto(pkt); @@ -2110,7 +2118,15 @@ void net_pkt_set_appdata_values(struct net_pkt *pkt, case IPPROTO_TCP: proto_len = tcp_hdr_len(pkt); break; - +#if defined(CONFIG_SOCKET_CAN) + case CAN_RAW: + frag = pkt->frags; + if (frag) { + net_pkt_set_appdata(pkt, frag->data); + } + net_pkt_set_appdatalen(pkt, total_len); + return; +#endif default: return; } diff --git a/subsys/net/ip/utils.c b/subsys/net/ip/utils.c index 524ec2ce519c4b..e873a85a1af7af 100644 --- a/subsys/net/ip/utils.c +++ b/subsys/net/ip/utils.c @@ -43,6 +43,10 @@ const char *net_proto2str(enum net_ip_protocol proto) return "UDP"; case IPPROTO_ICMPV6: return "ICMPv6"; +#if defined(CONFIG_SOCKET_CAN) + case CAN_RAW: + return "CAN_RAW"; +#endif default: break; } diff --git a/subsys/net/l2/CMakeLists.txt b/subsys/net/l2/CMakeLists.txt index b5fdb45b5b2441..a0c5f8e7c97bf8 100644 --- a/subsys/net/l2/CMakeLists.txt +++ b/subsys/net/l2/CMakeLists.txt @@ -21,3 +21,7 @@ endif() if(CONFIG_NET_L2_WIFI_MGMT OR CONFIG_NET_L2_WIFI_SHELL) add_subdirectory(wifi) endif() + +if(CONFIG_NET_L2_CAN) + add_subdirectory(can) +endif() diff --git a/subsys/net/l2/Kconfig b/subsys/net/l2/Kconfig index a53da98e745bb4..d98c974e918865 100644 --- a/subsys/net/l2/Kconfig +++ b/subsys/net/l2/Kconfig @@ -98,4 +98,10 @@ config NET_L2_WIFI_SHELL This can be used for controlling WiFi through the console via exposing a shell module named "wifi". +config NET_L2_CAN + bool "Enable L2 layer for CAN" + default y if SOCKET_CAN + depends on SOCKET_CAN + help + Add support l2 layer for CAN. endmenu diff --git a/subsys/net/l2/can/CMakeLists.txt b/subsys/net/l2/can/CMakeLists.txt new file mode 100644 index 00000000000000..9e6a1ae5ca417a --- /dev/null +++ b/subsys/net/l2/can/CMakeLists.txt @@ -0,0 +1,4 @@ +zephyr_library() +zephyr_library_include_directories(. ${ZEPHYR_BASE}/subsys/net/ip) + +zephyr_library_sources_ifdef(CONFIG_NET_L2_CAN can_l2.c) diff --git a/subsys/net/l2/can/can_l2.c b/subsys/net/l2/can/can_l2.c new file mode 100644 index 00000000000000..2c988ff7bf7b98 --- /dev/null +++ b/subsys/net/l2/can/can_l2.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum net_verdict can_l2_recv(struct net_if *iface, + struct net_pkt *pkt) +{ + return NET_CONTINUE; +} + +enum net_verdict can_l2_send(struct net_if *iface, + struct net_pkt *pkt) +{ + net_if_queue_tx(iface, pkt); + + return NET_OK; +} + +u16_t can_l2_reserve(struct net_if *iface, void *unused) +{ + ARG_UNUSED(iface); + ARG_UNUSED(unused); + + return 0; +} + diff --git a/subsys/net/lib/sockets/CMakeLists.txt b/subsys/net/lib/sockets/CMakeLists.txt index 0136e5a7ba82a5..5d40cb20ed820d 100644 --- a/subsys/net/lib/sockets/CMakeLists.txt +++ b/subsys/net/lib/sockets/CMakeLists.txt @@ -6,3 +6,4 @@ zephyr_sources( zephyr_sources_ifdef(CONFIG_NET_SOCKETS_SOCKOPT_TLS sockets_tls.c) zephyr_sources_ifdef(CONFIG_NET_SOCKETS_OFFLOAD socket_offload.c) +zephyr_sources_ifdef(CONFIG_SOCKET_CAN socket_can.c) diff --git a/subsys/net/lib/sockets/Kconfig b/subsys/net/lib/sockets/Kconfig index 46f107b2addf4b..a5b36e2f9ab837 100644 --- a/subsys/net/lib/sockets/Kconfig +++ b/subsys/net/lib/sockets/Kconfig @@ -96,6 +96,13 @@ config NET_SOCKETS_OFFLOAD See NET_OFFLOAD for a more deeply integrated approach which offloads from the net_context() API within the Zephyr IP stack. +config SOCKET_CAN + bool "Enable socket can for CAN_RAW type sockets" + default n + depends on CAN + help + "Enable socket can" + module = NET_SOCKETS module-dep = NET_LOG module-str = Log level for BSD sockets compatible API calls diff --git a/subsys/net/lib/sockets/socket_can.c b/subsys/net/lib/sockets/socket_can.c new file mode 100644 index 00000000000000..ef3f5a2ec9ee93 --- /dev/null +++ b/subsys/net/lib/sockets/socket_can.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define LOG_MODULE_NAME net_sock_can + +#define NET_LOG_LEVEL CONFIG_NET_SOCKETS_LOG_LEVEL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int socket_can_get_opt(struct net_context *context, int optname, + void *optval, socklen_t *optlen) +{ + int ret = 0; + struct device *dev; + struct net_if *iface; + struct socket_can_context *sock_ctx; + + if (!context) { + ret = -EBADF; + goto err; + } + + if (!optval || !optlen) { + ret = -EINVAL; + goto err; + } + + iface = net_context_get_iface(context); + if (iface == NULL) { + ret = -EBADF; + goto err; + } + + dev = net_if_get_device(iface); + if (dev == NULL) { + ret = -EBADF; + goto err; + } + + sock_ctx = dev->driver_data; + + switch (optname) { + case SOCKET_CAN_GET_IF_INDEX: + *((u8_t *)optval) = net_if_get_by_iface(sock_ctx->iface); + *optlen = sizeof(u8_t); + break; + default: + ret = ENOPROTOOPT; + } + +err: + return ret; + +} + +int socket_can_set_opt(struct net_context *context, int optname, + const void *optval, socklen_t optlen) +{ + int ret = 0; + struct device *dev; + struct can_filter *filter; + struct socket_can_mode *mode; + struct device *can_dev; + struct net_if *iface; + struct socket_can_context *sock_ctx; + const struct socket_can_driver_api_t *api; + + ARG_UNUSED(optlen); + + if (!context) { + ret = -EBADF; + goto err; + } + + if (!optval) { + ret = -EINVAL; + goto err; + } + + iface = net_context_get_iface(context); + if (iface == NULL) { + ret = -EBADF; + goto err; + } + + dev = net_if_get_device(iface); + if (dev == NULL) { + ret = -EBADF; + goto err; + } + + sock_ctx = dev->driver_data; + if (sock_ctx == NULL) { + ret = -EBADF; + goto err; + } + + can_dev = sock_ctx->can_dev; + + if (can_dev == NULL) { + ret = -EBADF; + goto err; + } + + switch (optname) { + case SOCKET_CAN_SET_FILTER: + filter = (struct can_filter *)optval; + api = dev->driver_api; + if (api == NULL) { + ret = -EBADF; + goto err; + } + if (api->config_filter) { + ret = api->config_filter(dev, filter); + } else { + ret = -ENOPROTOOPT; + goto err; + } + break; + case SOCKET_CAN_SET_MODE: + mode = (struct socket_can_mode *)optval; + ret = can_configure(can_dev, + mode->op_mode, mode->baud_rate); + break; + default: + ret = -ENOPROTOOPT; + } + +err: + return ret; + +} + +void socket_can_iface_init(struct net_if *iface) +{ + struct device *dev = net_if_get_device(iface); + struct socket_can_context *context = dev->driver_data; + + context->iface = iface; +} + +static void socket_can_tx_callback(u32_t flags) +{ + NET_DBG("TX CALLBACK OCCURRED flags = %x", flags); + if (flags != CAN_TX_OK) { + NET_DBG("SOCKET_CAN_TRANSMISSION FAILED ERR = %d", flags); + } +} + +int socket_can_iface_send(struct net_if *iface, struct net_pkt *pkt) +{ + int ret = CAN_TX_ERR; + struct device *dev; + struct socket_can_context *context; + struct device *can_dev; + struct net_buf *buf; + struct can_msg *msg; + + if (pkt == NULL) { + goto err; + } + dev = net_if_get_device(iface); + if (dev == NULL) { + goto err; + } + context = dev->driver_data; + if (context == NULL) { + goto err; + } + can_dev = context->can_dev; + + buf = pkt->frags; + if ((buf == NULL) || (buf->data == NULL)) { + goto err; + } + msg = (struct can_msg *)(buf->data); + + ret = can_send(can_dev, msg, K_FOREVER, socket_can_tx_callback); +err: + return ret; +} + +bool socket_can_check_matched_id_filter(struct net_pkt *pkt) +{ + struct net_if *iface = NULL; + struct net_context *ctx = NULL; + struct device *dev = NULL; + const struct socket_can_driver_api_t *api = NULL; + bool result = false; + + if (pkt == NULL) { + goto err; + } + + ctx = net_pkt_context(pkt); + if (ctx == NULL) { + goto err; + } + + iface = net_context_get_iface(ctx); + if (iface == NULL) { + goto err; + } + + dev = net_if_get_device(iface); + if (dev == NULL) { + goto err; + } + + api = dev->driver_api; + if (api == NULL) { + goto err; + } + + if (api->check_matched_filter) { + result = api->check_matched_filter(dev, pkt); + } + +err: + return result; +} + diff --git a/subsys/net/lib/sockets/sockets.c b/subsys/net/lib/sockets/sockets.c old mode 100644 new mode 100755 index 7cfc3eb3619c3a..c6797254376bf5 --- a/subsys/net/lib/sockets/sockets.c +++ b/subsys/net/lib/sockets/sockets.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -220,7 +221,9 @@ int _impl_zsock_bind(int sock, const struct sockaddr *addr, socklen_t addrlen) * bind(), but for STREAM socket, next expected operation is * listen(), which doesn't work if recv callback is set. */ - if (net_context_get_type(ctx) == SOCK_DGRAM) { + if (net_context_get_type(ctx) == SOCK_DGRAM || + (IS_ENABLED(CONFIG_SOCKET_CAN) && + (net_context_get_type(ctx) == SOCK_RAW))) { SET_ERRNO(net_context_recv(ctx, zsock_received_cb, K_NO_WAIT, ctx->user_data)); } @@ -493,6 +496,9 @@ static inline ssize_t zsock_recv_dgram(struct net_context *ctx, *addrlen = sizeof(struct sockaddr_in); } else if (src_addr->sa_family == AF_INET6) { *addrlen = sizeof(struct sockaddr_in6); + } else if (IS_ENABLED(CONFIG_SOCKET_CAN) && + (src_addr->sa_family == AF_CAN)) { + *addrlen = sizeof(struct sockaddr_can); } else { errno = ENOTSUP; return -1; @@ -614,6 +620,9 @@ ssize_t zsock_recvfrom_ctx(struct net_context *ctx, void *buf, size_t max_len, return zsock_recv_dgram(ctx, buf, max_len, flags, src_addr, addrlen); } else if (sock_type == SOCK_STREAM) { return zsock_recv_stream(ctx, buf, max_len, flags); + } else if (IS_ENABLED(CONFIG_SOCKET_CAN) && (sock_type == SOCK_RAW)) { + return zsock_recv_dgram(ctx, buf, max_len, flags, src_addr, + addrlen); } else { __ASSERT(0, "Unknown socket type"); } @@ -862,6 +871,12 @@ Z_SYSCALL_HANDLER(zsock_inet_pton, family, src, dst) int zsock_getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen) { + struct net_context *context = sock_to_net_ctx(sock); + + if (IS_ENABLED(CONFIG_SOCKET_CAN) && level == SOL_CAN_RAW) { + return socket_can_get_opt(context, optname, optval, optlen); + } + errno = ENOPROTOOPT; return -1; } @@ -869,6 +884,12 @@ int zsock_getsockopt(int sock, int level, int optname, int zsock_setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen) { + struct net_context *context = sock_to_net_ctx(sock); + + if (IS_ENABLED(CONFIG_SOCKET_CAN) && level == SOL_CAN_RAW) { + return socket_can_set_opt(context, optname, optval, optlen); + } + errno = ENOPROTOOPT; return -1; }