You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/06/15 14:07:30 UTC
[incubator-nuttx] 01/04: net: Add SocketCAN support
This is an automated email from the ASF dual-hosted git repository.
gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 55d9e5f7af05e75ca62f57863b880d723aa83c56
Author: Peter van der Perk <pe...@nxp.com>
AuthorDate: Mon Jun 15 10:23:25 2020 +0200
net: Add SocketCAN support
---
fs/vfs/fs_write.c | 9 +-
include/net/if.h | 19 +-
include/netpacket/can.h | 140 ++++
include/nuttx/can.h | 319 ++++++++
include/nuttx/can/error.h | 129 ++++
include/nuttx/mm/iob.h | 10 +-
include/nuttx/net/can.h | 122 +++
include/nuttx/net/ioctl.h | 8 +
include/nuttx/net/net.h | 31 +-
include/nuttx/wqueue.h | 3 +-
include/sys/socket.h | 13 +
libs/libc/net/lib_recvmsg.c | 7 +-
libs/libc/net/lib_sendmsg.c | 4 +-
net/Kconfig | 1 +
net/Makefile | 1 +
net/bluetooth/bluetooth_sockif.c | 38 +-
net/can/Kconfig | 97 +++
net/can/Make.defs | 48 ++
net/can/can.h | 385 ++++++++++
net/can/can_callback.c | 242 ++++++
net/can/can_conn.c | 223 ++++++
net/can/can_getsockopt.c | 220 ++++++
net/can/can_input.c | 204 +++++
.../net/lib_recvmsg.c => net/can/can_notifier.c | 56 +-
net/can/can_poll.c | 88 +++
net/can/can_recvfrom.c | 838 +++++++++++++++++++++
net/can/can_send.c | 441 +++++++++++
net/can/can_setsockopt.c | 177 +++++
net/{netlink/netlink_sockif.c => can/can_sockif.c} | 723 +++++++++---------
net/devif/Make.defs | 4 +
net/devif/devif.h | 112 +--
.../local_sendpacket.c => devif/devif_cansend.c} | 124 +--
net/devif/devif_poll.c | 48 ++
net/icmp/icmp_sockif.c | 18 +-
net/icmpv6/icmpv6_sockif.c | 32 +-
net/ieee802154/ieee802154_sockif.c | 47 +-
net/inet/inet_sockif.c | 4 +
net/local/local_sendpacket.c | 1 +
net/local/local_sockif.c | 12 +-
net/net_initialize.c | 7 +
net/netdev/Kconfig | 8 +
net/netdev/netdev_ioctl.c | 48 ++
net/netdev/netdev_register.c | 12 +
net/netlink/netlink_sockif.c | 4 +
net/pkt/pkt_sockif.c | 4 +
net/socket/Kconfig | 24 +
net/socket/Make.defs | 6 +
net/socket/getsockopt.c | 19 +
net/socket/net_sockif.c | 7 +
net/socket/recvmsg.c | 244 ++++++
net/socket/sendmsg.c | 243 ++++++
net/socket/setsockopt.c | 29 +
net/socket/socket.h | 2 +-
net/utils/net_lock.c | 51 ++
54 files changed, 5085 insertions(+), 621 deletions(-)
diff --git a/fs/vfs/fs_write.c b/fs/vfs/fs_write.c
index 6e9a379..d1b7f03 100644
--- a/fs/vfs/fs_write.c
+++ b/fs/vfs/fs_write.c
@@ -86,7 +86,8 @@
*
****************************************************************************/
-ssize_t file_write(FAR struct file *filep, FAR const void *buf, size_t nbytes)
+ssize_t file_write(FAR struct file *filep, FAR const void *buf,
+ size_t nbytes)
{
FAR struct inode *inode;
@@ -149,8 +150,10 @@ ssize_t nx_write(int fd, FAR const void *buf, size_t nbytes)
if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS)
{
-#ifdef CONFIG_NET_TCP
- /* Write to a socket descriptor is equivalent to send with flags == 0. */
+#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_CAN)
+ /* Write to a socket descriptor is equivalent to
+ * send with flags == 0.
+ */
ret = nx_send(fd, buf, nbytes, 0);
#else
diff --git a/include/net/if.h b/include/net/if.h
index 0b90045..0332ab7 100644
--- a/include/net/if.h
+++ b/include/net/if.h
@@ -136,6 +136,18 @@ struct mii_ioctl_data_s
uint16_t val_out; /* PHY output data */
};
+/* Structure passed to get or set the CAN bitrate
+ * SIOCxCANBITRATE ioctl commands.
+ */
+
+struct can_ioctl_data_s
+{
+ uint16_t arbi_bitrate; /* Classic CAN / Arbitration phase bitrate kbit/s */
+ uint16_t arbi_samplep; /* Classic CAN / Arbitration phase input % */
+ uint16_t data_bitrate; /* Data phase bitrate kbit/s */
+ uint16_t data_samplep; /* Data phase sample point % */
+};
+
/* There are two forms of the I/F request structure. One for IPv6 and one for IPv4.
* Notice that they are (and must be) cast compatible and really different only
* in the size of the structure allocation.
@@ -158,6 +170,7 @@ struct lifreq
uint8_t lifru_flags; /* Interface flags */
struct mii_ioctl_notify_s llfru_mii_notify; /* PHY event notification */
struct mii_ioctl_data_s lifru_mii_data; /* MII request data */
+ struct can_ioctl_data_s lifru_can_data; /* CAN bitrate request data */
} lifr_ifru;
};
@@ -196,6 +209,9 @@ struct lifconf
struct ifreq
{
char ifr_name[IFNAMSIZ]; /* Network device name (e.g. "eth0") */
+#ifdef CONFIG_NETDEV_IFINDEX
+ int16_t ifr_ifindex; /* Interface index */
+#endif
union
{
struct sockaddr ifru_addr; /* IP Address */
@@ -208,6 +224,7 @@ struct ifreq
uint8_t ifru_flags; /* Interface flags */
struct mii_ioctl_notify_s ifru_mii_notify; /* PHY event notification */
struct mii_ioctl_data_s ifru_mii_data; /* MII request data */
+ struct can_ioctl_data_s ifru_can_data; /* CAN bitrate request data */
} ifr_ifru;
};
@@ -226,7 +243,7 @@ struct ifreq
#define ifr_mii_val_in ifr_ifru.ifru_mii_data.val_in /* PHY input data */
#define ifr_mii_val_out ifr_ifru.ifru_mii_data.val_out /* PHY output data */
-/* Used only with the SIOCGIFCONF IOCTL command*/
+/* Used only with the SIOCGIFCONF IOCTL command */
struct ifconf
{
diff --git a/include/netpacket/can.h b/include/netpacket/can.h
new file mode 100644
index 0000000..4ee6645
--- /dev/null
+++ b/include/netpacket/can.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+ * include/netpacket/can.h
+ * Definitions for use with AF_PACKET sockets
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NETPACKET_CAN_H
+#define __INCLUDE_NETPACKET_CAN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Special address description flags for the CAN_ID */
+
+#define CAN_EFF_FLAG 0x80000000 /* EFF/SFF is set in the MSB */
+#define CAN_RTR_FLAG 0x40000000 /* Remote transmission request */
+#define CAN_ERR_FLAG 0x20000000 /* Error message frame */
+
+/* Valid bits in CAN ID for frame formats */
+
+#define CAN_SFF_MASK 0x000007ff /* Standard frame format (SFF) */
+#define CAN_EFF_MASK 0x1fffffff /* Extended frame format (EFF) */
+#define CAN_ERR_MASK 0x1fffffff /* Omit EFF, RTR, ERR flags */
+
+#define CAN_MTU (sizeof(struct can_frame))
+#define CANFD_MTU (sizeof(struct canfd_frame))
+
+/* PF_CAN protocols */
+
+#define CAN_RAW 1 /* RAW sockets */
+#define CAN_BCM 2 /* Broadcast Manager */
+#define CAN_TP16 3 /* VAG Transport Protocol v1.6 */
+#define CAN_TP20 4 /* VAG Transport Protocol v2.0 */
+#define CAN_MCNET 5 /* Bosch MCNet */
+#define CAN_ISOTP 6 /* ISO 15765-2 Transport Protocol */
+#define CAN_J1939 7 /* SAE J1939 */
+#define CAN_NPROTO 8
+
+/* CAN_RAW socket options */
+
+#define CAN_RAW_FILTER (__SO_PROTOCOL + 0)
+ /* set 0 .. n can_filter(s) */
+#define CAN_RAW_ERR_FILTER (__SO_PROTOCOL + 1)
+ /* set filter for error frames */
+#define CAN_RAW_LOOPBACK (__SO_PROTOCOL + 2)
+ /* local loopback (default:on) */
+#define CAN_RAW_RECV_OWN_MSGS (__SO_PROTOCOL + 3)
+ /* receive my own msgs (default:off) */
+#define CAN_RAW_FD_FRAMES (__SO_PROTOCOL + 4)
+ /* allow CAN FD frames (default:off) */
+#define CAN_RAW_JOIN_FILTERS (__SO_PROTOCOL + 5)
+ /* all filters must match to trigger */
+#define CAN_RAW_TX_DEADLINE (__SO_PROTOCOL + 6)
+ /* Abort frame when deadline passed */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Controller Area Network Identifier structure
+ *
+ * Bit 0-28: CAN identifier (11/29 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;
+
+/* The sockaddr structure for CAN sockets
+ *
+ * can_family: Address family number AF_CAN.
+ * can_ifindex: CAN network interface index.
+ * can_addr: Protocol specific address information
+ */
+
+struct sockaddr_can
+{
+ sa_family_t can_family;
+ int16_t can_ifindex;
+ union
+ {
+ /* Transport protocol class address information */
+
+ struct
+ {
+ canid_t rx_id;
+ canid_t tx_id;
+ } tp;
+
+ /* J1939 address information */
+
+ struct
+ {
+ /* 8 byte name when using dynamic addressing */
+
+ uint64_t name;
+
+ /* pgn:
+ * 8 bit: PS in PDU2 case, else 0
+ * 8 bit: PF
+ * 1 bit: DP
+ * 1 bit: reserved
+ */
+
+ uint32_t pgn;
+
+ /* 1 byte address */
+
+ uint8_t addr;
+ } j1939;
+ } can_addr;
+};
+
+#endif /* __INCLUDE_NETPACKET_CAN_H */
diff --git a/include/nuttx/can.h b/include/nuttx/can.h
new file mode 100644
index 0000000..c681b32
--- /dev/null
+++ b/include/nuttx/can.h
@@ -0,0 +1,319 @@
+/************************************************************************************
+ * include/nuttx/can/can.h
+ *
+ * Copyright (C) 2008, 2009, 2011-2012, 2015-2017, 2019 Gregory Nutt. All rights
+ * reserved.
+ * Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_CAN_CAN_H
+#define __INCLUDE_NUTTX_CAN_CAN_H
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#ifdef CONFIG_CAN_TXREADY
+# include <nuttx/wqueue.h>
+#endif
+
+#include <queue.h>
+
+#ifdef CONFIG_NET_CAN
+
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+
+/* Ioctl Commands *******************************************************************/
+
+/* Ioctl commands supported by the upper half CAN driver.
+ *
+ * CANIOC_RTR:
+ * Description: Send the remote transmission request and wait for the response.
+ * Argument: A reference to struct canioc_rtr_s
+ *
+ * Ioctl commands that may or may not be supported by the lower half CAN driver.
+ *
+ * CANIOC_ADD_STDFILTER:
+ * Description: Add an address filter for a standard 11 bit address.
+ * Argument: A reference to struct canioc_stdfilter_s
+ * Returned Value: A non-negative filter ID is returned on success.
+ * Otherwise -1 (ERROR) is returned with the errno
+ * variable set to indicate the nature of the error.
+ * Dependencies: None
+ *
+ * CANIOC_ADD_EXTFILTER:
+ * Description: Add an address filter for a extended 29 bit address.
+ * Argument: A reference to struct canioc_extfilter_s
+ * Returned Value: A non-negative filter ID is returned on success.
+ * Otherwise -1 (ERROR) is returned with the errno
+ * variable set to indicate the nature of the error.
+ * Dependencies: Requires CONFIG_CAN_EXTID=y
+ *
+ * CANIOC_DEL_STDFILTER:
+ * Description: Remove an address filter for a standard 11 bit address.
+ * Argument: The filter index previously returned by the
+ * CANIOC_ADD_STDFILTER command
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: None
+ *
+ * CANIOC_DEL_EXTFILTER:
+ * Description: Remove an address filter for a standard 29 bit address.
+ * Argument: The filter index previously returned by the
+ * CANIOC_ADD_EXTFILTER command
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: Requires CONFIG_CAN_EXTID=y
+ *
+ * CANIOC_GET_BITTIMING:
+ * Description: Return the current bit timing settings
+ * Argument: A pointer to a write-able instance of struct
+ * canioc_bittiming_s in which current bit timing values
+ * will be returned.
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: None
+ *
+ * CANIOC_SET_BITTIMING:
+ * Description: Set new current bit timing values
+ * Argument: A pointer to a read-able instance of struct
+ * canioc_bittiming_s in which the new bit timing values
+ * are provided.
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: None
+ *
+ * CANIOC_GET_CONNMODES:
+ * Description: Get the current bus connection modes
+ * Argument: A pointer to a write-able instance of struct
+ * canioc_connmodes_s in which the new bus modes will be returned.
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: None
+ *
+ * CANIOC_SET_CONNMODES:
+ * Description: Set new bus connection modes values
+ * Argument: A pointer to a read-able instance of struct
+ * canioc_connmodes_s in which the new bus modes are provided.
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: None
+ *
+ * CANIOC_BUSOFF_RECOVERY:
+ * Description: Initiates the BUS-OFF recovery sequence
+ * Argument: None
+ * Returned Value: Zero (OK) is returned on success. Otherwise -1 (ERROR)
+ * is returned with the errno variable set to indicate the
+ * nature of the error.
+ * Dependencies: None
+ */
+
+#define CANIOC_RTR _CANIOC(1)
+#define CANIOC_GET_BITTIMING _CANIOC(2)
+#define CANIOC_SET_BITTIMING _CANIOC(3)
+#define CANIOC_ADD_STDFILTER _CANIOC(4)
+#define CANIOC_ADD_EXTFILTER _CANIOC(5)
+#define CANIOC_DEL_STDFILTER _CANIOC(6)
+#define CANIOC_DEL_EXTFILTER _CANIOC(7)
+#define CANIOC_GET_CONNMODES _CANIOC(8)
+#define CANIOC_SET_CONNMODES _CANIOC(9)
+#define CANIOC_BUSOFF_RECOVERY _CANIOC(10)
+
+#define CAN_FIRST 0x0001 /* First common command */
+#define CAN_NCMDS 10 /* Ten common commands */
+
+/* User defined ioctl commands are also supported. These will be forwarded
+ * by the upper-half CAN driver to the lower-half CAN driver via the co_ioctl()
+ * method fo the CAN lower-half interface. However, the lower-half driver
+ * must reserve a block of commands as follows in order prevent IOCTL
+ * command numbers from overlapping.
+ *
+ * This is generally done as follows. The first reservation for CAN driver A would
+ * look like:
+ *
+ * CAN_A_FIRST (CAN_FIRST + CAN_NCMDS) <- First command
+ * CAN_A_NCMDS 42 <- Number of commands
+ *
+ * IOCTL commands for CAN driver A would then be defined in a CAN A header file like:
+ *
+ * CANIOC_A_CMD1 _CANIOC(CAN_A_FIRST+0)
+ * CANIOC_A_CMD2 _CANIOC(CAN_A_FIRST+1)
+ * CANIOC_A_CMD3 _CANIOC(CAN_A_FIRST+2)
+ * ...
+ * CANIOC_A_CMD42 _CANIOC(CAN_A_FIRST+41)
+ *
+ * The next reservation would look like:
+ *
+ * CAN_B_FIRST (CAN_A_FIRST + CAN_A_NCMDS) <- Next command
+ * CAN_B_NCMDS 77 <- Number of commands
+ */
+
+/* CAN payload length and DLC definitions according to ISO 11898-1 */
+
+#define CAN_MAX_DLC 8
+#define CAN_MAX_DLEN 8
+
+/* CAN FD payload length and DLC definitions according to ISO 11898-7 */
+
+#define CANFD_MAX_DLC 15
+#define CANFD_MAX_DLEN 64
+
+/* Defined bits for canfd_frame.flags
+ *
+ * The use of struct canfd_frame implies the Extended Data Length (EDL) bit to
+ * be set in the CAN frame bitstream on the wire. The EDL bit switch turns
+ * the CAN controllers bitstream processor into the CAN FD mode which creates
+ * two new options within the CAN FD frame specification:
+ *
+ * Bit Rate Switch - to indicate a second bitrate is/was used for the payload
+ * Error State Indicator - represents the error state of the transmitting node
+ *
+ * As the CANFD_ESI bit is internally generated by the transmitting CAN
+ * controller only the CANFD_BRS bit is relevant for real CAN controllers when
+ * building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make
+ * sense for virtual CAN interfaces to test applications with echoed frames.
+ */
+
+#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
+#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
+
+#define CAN_INV_FILTER 0x20000000U /* to be set in can_filter.can_id */
+
+/************************************************************************************
+ * Public Types
+ ************************************************************************************/
+
+typedef FAR void *CAN_HANDLE;
+
+struct can_response_s
+{
+ sq_entry_t flink;
+
+ /* Message-specific data may follow */
+}; /* FIXME remove */
+
+typedef uint32_t canid_t;
+
+/* Controller Area Network Error Message Frame Mask structure
+ *
+ * bit 0-28 : error class mask (see include/uapi/linux/can/error.h)
+ * bit 29-31 : set to zero
+ */
+
+typedef uint32_t can_err_mask_t;
+
+/* struct can_frame - basic CAN frame structure
+ * can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
+ * can_dlc: frame payload length in byte (0 .. 8) aka data length code
+ * N.B. the DLC field from ISO 11898-1 Chapter 8.4.2.3 has a 1:1
+ * mapping of the 'data length code' to the real payload length
+ * __pad: padding
+ * __res0: reserved / padding
+ * __res1: reserved / padding
+ * data: CAN frame payload (up to 8 byte)
+ */
+
+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 */
+ uint8_t data[CAN_MAX_DLEN] __attribute__((aligned(8)));
+};
+
+/* struct canfd_frame - CAN flexible data rate frame structure
+ * can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
+ * len: frame payload length in byte (0 .. CANFD_MAX_DLEN)
+ * flags: additional flags for CAN FD
+ * __res0: reserved / padding
+ * __res1: reserved / padding
+ * data: CAN FD frame payload (up to CANFD_MAX_DLEN byte)
+ */
+
+struct canfd_frame
+{
+ canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
+ uint8_t len; /* frame payload length in byte */
+ uint8_t flags; /* additional flags for CAN FD */
+ uint8_t __res0; /* reserved / padding */
+ uint8_t __res1; /* reserved / padding */
+ uint8_t data[CANFD_MAX_DLEN] __attribute__((aligned(8)));
+};
+
+/* struct can_filter - CAN ID based filter in can_register().
+ * can_id: relevant bits of CAN ID which are not masked out.
+ * can_mask: CAN mask (see description)
+ *
+ * Description:
+ * A filter matches, when
+ *
+ * <received_can_id> & mask == can_id & mask
+ *
+ * The filter can be inverted (CAN_INV_FILTER bit set in can_id) or it can
+ * filter for error message frames (CAN_ERR_FLAG bit set in mask).
+ */
+
+struct can_filter
+{
+ canid_t can_id;
+ canid_t can_mask;
+};
+
+/************************************************************************************
+ * Public Function Prototypes
+ ************************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* CONFIG_CAN */
+#endif /* __INCLUDE_NUTTX_CAN_CAN_H */
diff --git a/include/nuttx/can/error.h b/include/nuttx/can/error.h
new file mode 100644
index 0000000..cf5fec6
--- /dev/null
+++ b/include/nuttx/can/error.h
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: ((GPL-2.0-only WITH Linux-syscall-note) OR BSD-3-Clause) */
+
+/************************************************************************************
+ * linux/can/error.h
+ *
+ * Definitions of the CAN error messages to be filtered and passed to the
+ * user.
+ *
+ * Author: Oliver Hartkopp <ol...@volkswagen.de>
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ ************************************************************************************/
+
+#ifndef _UAPI_CAN_ERROR_H
+#define _UAPI_CAN_ERROR_H
+
+#define CAN_ERR_DLC 8 /* dlc for error message frames */
+
+/* error class (mask) in can_id */
+#define CAN_ERR_TX_TIMEOUT 0x00000001U /* TX timeout (by netdevice driver) */
+#define CAN_ERR_LOSTARB 0x00000002U /* lost arbitration / data[0] */
+#define CAN_ERR_CRTL 0x00000004U /* controller problems / data[1] */
+#define CAN_ERR_PROT 0x00000008U /* protocol violations / data[2..3] */
+#define CAN_ERR_TRX 0x00000010U /* transceiver status / data[4] */
+#define CAN_ERR_ACK 0x00000020U /* received no ACK on transmission */
+#define CAN_ERR_BUSOFF 0x00000040U /* bus off */
+#define CAN_ERR_BUSERROR 0x00000080U /* bus error (may flood!) */
+#define CAN_ERR_RESTARTED 0x00000100U /* controller restarted */
+
+/* arbitration lost in bit ... / data[0] */
+#define CAN_ERR_LOSTARB_UNSPEC 0x00 /* unspecified */
+
+/* else bit number in bitstream */
+
+/* error status of CAN-controller / data[1] */
+#define CAN_ERR_CRTL_UNSPEC 0x00 /* unspecified */
+#define CAN_ERR_CRTL_RX_OVERFLOW 0x01 /* RX buffer overflow */
+#define CAN_ERR_CRTL_TX_OVERFLOW 0x02 /* TX buffer overflow */
+#define CAN_ERR_CRTL_RX_WARNING 0x04 /* reached warning level for RX errors */
+#define CAN_ERR_CRTL_TX_WARNING 0x08 /* reached warning level for TX errors */
+#define CAN_ERR_CRTL_RX_PASSIVE 0x10 /* reached error passive status RX */
+#define CAN_ERR_CRTL_TX_PASSIVE 0x20 /* reached error passive status TX */
+ /* (at least one error counter exceeds */
+ /* the protocol-defined level of 127) */
+#define CAN_ERR_CRTL_ACTIVE 0x40 /* recovered to error active state */
+
+/* error in CAN protocol (type) / data[2] */
+#define CAN_ERR_PROT_UNSPEC 0x00 /* unspecified */
+#define CAN_ERR_PROT_BIT 0x01 /* single bit error */
+#define CAN_ERR_PROT_FORM 0x02 /* frame format error */
+#define CAN_ERR_PROT_STUFF 0x04 /* bit stuffing error */
+#define CAN_ERR_PROT_BIT0 0x08 /* unable to send dominant bit */
+#define CAN_ERR_PROT_BIT1 0x10 /* unable to send recessive bit */
+#define CAN_ERR_PROT_OVERLOAD 0x20 /* bus overload */
+#define CAN_ERR_PROT_ACTIVE 0x40 /* active error announcement */
+#define CAN_ERR_PROT_TX 0x80 /* error occurred on transmission */
+
+/* error in CAN protocol (location) / data[3] */
+#define CAN_ERR_PROT_LOC_UNSPEC 0x00 /* unspecified */
+#define CAN_ERR_PROT_LOC_SOF 0x03 /* start of frame */
+#define CAN_ERR_PROT_LOC_ID28_21 0x02 /* ID bits 28 - 21 (SFF: 10 - 3) */
+#define CAN_ERR_PROT_LOC_ID20_18 0x06 /* ID bits 20 - 18 (SFF: 2 - 0 )*/
+#define CAN_ERR_PROT_LOC_SRTR 0x04 /* substitute RTR (SFF: RTR) */
+#define CAN_ERR_PROT_LOC_IDE 0x05 /* identifier extension */
+#define CAN_ERR_PROT_LOC_ID17_13 0x07 /* ID bits 17-13 */
+#define CAN_ERR_PROT_LOC_ID12_05 0x0f /* ID bits 12-5 */
+#define CAN_ERR_PROT_LOC_ID04_00 0x0e /* ID bits 4-0 */
+#define CAN_ERR_PROT_LOC_RTR 0x0c /* RTR */
+#define CAN_ERR_PROT_LOC_RES1 0x0d /* reserved bit 1 */
+#define CAN_ERR_PROT_LOC_RES0 0x09 /* reserved bit 0 */
+#define CAN_ERR_PROT_LOC_DLC 0x0b /* data length code */
+#define CAN_ERR_PROT_LOC_DATA 0x0a /* data section */
+#define CAN_ERR_PROT_LOC_CRC_SEQ 0x08 /* CRC sequence */
+#define CAN_ERR_PROT_LOC_CRC_DEL 0x18 /* CRC delimiter */
+#define CAN_ERR_PROT_LOC_ACK 0x19 /* ACK slot */
+#define CAN_ERR_PROT_LOC_ACK_DEL 0x1b /* ACK delimiter */
+#define CAN_ERR_PROT_LOC_EOF 0x1a /* end of frame */
+#define CAN_ERR_PROT_LOC_INTERM 0x12 /* intermission */
+
+/* error status of CAN-transceiver / data[4] */
+
+ /* CANH CANL */
+#define CAN_ERR_TRX_UNSPEC 0x00 /* 0000 0000 */
+#define CAN_ERR_TRX_CANH_NO_WIRE 0x04 /* 0000 0100 */
+#define CAN_ERR_TRX_CANH_SHORT_TO_BAT 0x05 /* 0000 0101 */
+#define CAN_ERR_TRX_CANH_SHORT_TO_VCC 0x06 /* 0000 0110 */
+#define CAN_ERR_TRX_CANH_SHORT_TO_GND 0x07 /* 0000 0111 */
+#define CAN_ERR_TRX_CANL_NO_WIRE 0x40 /* 0100 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_BAT 0x50 /* 0101 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_VCC 0x60 /* 0110 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_GND 0x70 /* 0111 0000 */
+#define CAN_ERR_TRX_CANL_SHORT_TO_CANH 0x80 /* 1000 0000 */
+
+/* controller specific additional information / data[5..7] */
+
+#endif /* _UAPI_CAN_ERROR_H */
diff --git a/include/nuttx/mm/iob.h b/include/nuttx/mm/iob.h
index 8984af6..32c0bfd 100644
--- a/include/nuttx/mm/iob.h
+++ b/include/nuttx/mm/iob.h
@@ -54,6 +54,7 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
+
/* Configuration ************************************************************/
/* I/O buffer allocation logic supports a throttle value for read-ahead
@@ -220,6 +221,9 @@ enum iob_user_e
#ifdef CONFIG_WIRELESS_BLUETOOTH
IOBUSER_WIRELESS_BLUETOOTH,
#endif
+#ifdef CONFIG_NET_CAN
+ IOBUSER_NET_CAN_READAHEAD,
+#endif
IOBUSER_GLOBAL,
IOBUSER_NENTRIES /* MUST BE LAST ENTRY */
};
@@ -248,7 +252,8 @@ void iob_initialize(void);
* Name: iob_alloc
*
* Description:
- * Allocate an I/O buffer by taking the buffer at the head of the free list.
+ * Allocate an I/O buffer by taking the buffer at the head of the free
+ * list.
*
****************************************************************************/
@@ -586,7 +591,8 @@ void iob_dump(FAR const char *msg, FAR struct iob_s *iob, unsigned int len,
* Name: iob_getuserstats
*
* Description:
- * Return a reference to the IOB usage statistics for the IOB consumer/producer
+ * Return a reference to the IOB usage statistics for the IOB
+ * consumer/producer
*
* Input Parameters:
* userid - id representing the IOB producer/consumer
diff --git a/include/nuttx/net/can.h b/include/nuttx/net/can.h
new file mode 100644
index 0000000..f9cbe93
--- /dev/null
+++ b/include/nuttx/net/can.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+ * include/nuttx/net/can.h
+ * Macros and definitions for the CAN link layer.
+ *
+ * Copyright (C) 2007, 2009-2012, 2015 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Derived from uIP with has a similar BSD-styple license:
+ *
+ * Author: Adam Dunkels <ad...@dunkels.com>
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_NET_CAN_H
+#define __INCLUDE_NUTTX_NET_CAN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/can.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#ifdef CONFIG_NET_CAN_CANFD
+#define NET_CAN_PKTSIZE sizeof(struct canfd_frame)
+#else
+#define NET_CAN_PKTSIZE sizeof(struct can_frame)
+#endif
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CAN_CANFD
+
+/* Lookup tables convert can_dlc <-> payload len */
+
+extern const uint8_t can_dlc_to_len[16];
+extern const uint8_t len_to_can_dlc[65];
+
+#endif
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_input
+ *
+ * Description:
+ * Handle incoming CAN frame input
+ *
+ * This function provides the interface between CAN device drivers and
+ * SocketCAN logic. All frames that are received should be provided to
+ * can_input() prior to other routing.
+ *
+ * Input Parameters:
+ * dev - The device driver structure containing the received packet
+ *
+ * Returned Value:
+ * OK The packet has been processed and can be deleted
+ * ERROR There is a matching connection, but could not dispatch the packet
+ * yet. Useful when a packet arrives before a recv call is in
+ * place.
+ *
+ * Assumptions:
+ * Called from the CAN device diver with the network locked.
+ *
+ ****************************************************************************/
+
+struct net_driver_s; /* Forward reference */
+int can_input(FAR struct net_driver_s *dev);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_NET_CAN_H */
diff --git a/include/nuttx/net/ioctl.h b/include/nuttx/net/ioctl.h
index 4717542..6f2f20e 100644
--- a/include/nuttx/net/ioctl.h
+++ b/include/nuttx/net/ioctl.h
@@ -85,6 +85,9 @@
#define SIOCGIFCONF _SIOC(0x0018) /* Return an interface list (IPv4) */
#define SIOCGLIFCONF _SIOC(0x0019) /* Return an interface list (IPv6) */
+#define SIOCGIFNAME _SIOC(0x002A) /* Get interface name string */
+#define SIOCGIFINDEX _SIOC(0x002B) /* Get index based name string */
+
/* Interface flags */
#define SIOCSIFFLAGS _SIOC(0x001a) /* Sets the interface flags */
@@ -122,6 +125,11 @@
#define SIOCTELNET _SIOC(0x0029) /* Create a Telnet sessions.
* See include/nuttx/net/telnet.h */
+/* SocketCAN ****************************************************************/
+
+#define SIOCGCANBITRATE _SIOC(0x002C) /* Get bitrate from a CAN controller */
+#define SIOCSCANBITRATE _SIOC(0x002D) /* Set bitrate of a CAN controller */
+
/****************************************************************************
* Public Type Definitions
****************************************************************************/
diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h
index c2cbb93..836edbf 100644
--- a/include/nuttx/net/net.h
+++ b/include/nuttx/net/net.h
@@ -156,7 +156,8 @@ enum net_lltype_e
NET_LL_IEEE80211, /* IEEE 802.11 */
NET_LL_IEEE802154, /* IEEE 802.15.4 MAC */
NET_LL_PKTRADIO, /* Non-standard packet radio */
- NET_LL_MBIM /* CDC-MBIM USB host driver */
+ NET_LL_MBIM, /* CDC-MBIM USB host driver */
+ NET_LL_CAN /* CAN bus */
};
/* This defines a bitmap big enough for one bit for each socket option */
@@ -215,6 +216,12 @@ struct sock_intf_s
CODE ssize_t (*si_recvfrom)(FAR struct socket *psock, FAR void *buf,
size_t len, int flags, FAR struct sockaddr *from,
FAR socklen_t *fromlen);
+#ifdef CONFIG_NET_CMSG
+ CODE ssize_t (*si_recvmsg)(FAR struct socket *psock,
+ FAR struct msghdr *msg, int flags);
+ CODE ssize_t (*si_sendmsg)(FAR struct socket *psock,
+ FAR struct msghdr *msg, int flags);
+#endif
CODE int (*si_close)(FAR struct socket *psock);
#ifdef CONFIG_NET_USRSOCK
CODE int (*si_ioctl)(FAR struct socket *psock, int cmd,
@@ -271,6 +278,9 @@ struct socket
#ifdef CONFIG_NET_SOLINGER
socktimeo_t s_linger; /* Linger timeout value (in deciseconds) */
#endif
+#ifdef CONFIG_NET_TIMESTAMP
+ int32_t s_timestamp; /* Socket timestamp enabled/disabled */
+#endif
#endif
FAR void *s_conn; /* Connection inherits from struct socket_conn_s */
@@ -371,6 +381,25 @@ void net_initialize(void);
int net_lock(void);
/****************************************************************************
+ * Name: net_trylock
+ *
+ * Description:
+ * Try to take the network lock only when it is currently not locked.
+ * Otherwise, it locks the semaphore. In either
+ * case, the call returns without blocking.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned on
+ * failured (probably -EAGAIN).
+ *
+ ****************************************************************************/
+
+int net_trylock(void);
+
+/****************************************************************************
* Name: net_unlock
*
* Description:
diff --git a/include/nuttx/wqueue.h b/include/nuttx/wqueue.h
index d353772..ea7563c 100644
--- a/include/nuttx/wqueue.h
+++ b/include/nuttx/wqueue.h
@@ -280,7 +280,8 @@ enum work_evtype_e
WORK_TCP_DISCONNECT, /* Notify loss of TCP connection */
WORK_UDP_READAHEAD, /* Notify that UDP read-ahead data is available */
WORK_UDP_WRITEBUFFER, /* Notify that UDP write buffer is empty */
- WORK_NETLINK_RESPONSE /* Notify that Netlink response is available */
+ WORK_NETLINK_RESPONSE, /* Notify that Netlink response is available */
+ WORK_CAN_READAHEAD /* Notify that CAN read-ahead data is available */
};
/* This structure describes one notification and is provided as input to
diff --git a/include/sys/socket.h b/include/sys/socket.h
index b940126..e8eca51 100644
--- a/include/sys/socket.h
+++ b/include/sys/socket.h
@@ -62,6 +62,7 @@
#define PF_NETLINK 16 /* Netlink IPC socket */
#define PF_ROUTE PF_NETLINK /* 4.4BSD Compatibility*/
#define PF_PACKET 17 /* Low level packet interface */
+#define PF_CAN 29 /* Controller Area Network (SocketCAN) */
#define PF_BLUETOOTH 31 /* Bluetooth sockets */
#define PF_IEEE802154 36 /* Low level IEEE 802.15.4 radio frame interface */
#define PF_PKTRADIO 64 /* Low level packet radio interface */
@@ -78,6 +79,7 @@
#define AF_NETLINK PF_NETLINK
#define AF_ROUTE PF_ROUTE
#define AF_PACKET PF_PACKET
+#define AF_CAN PF_CAN
#define AF_BLUETOOTH PF_BLUETOOTH
#define AF_IEEE802154 PF_IEEE802154
#define AF_PKTRADIO PF_PKTRADIO
@@ -199,6 +201,16 @@
#define SO_TYPE 15 /* Reports the socket type (get only).
* return: int
*/
+#define SO_TIMESTAMP 16 /* Generates a timestamp for each incoming packet
+ * arg: integer value
+ */
+
+/* The options are unsupported but included for compatibility
+ * and portability
+ */
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
+#define SO_RXQ_OVFL 40
/* Protocol-level socket operations. */
@@ -210,6 +222,7 @@
#define SOL_L2CAP 6 /* See options in include/netpacket/bluetooth.h */
#define SOL_SCO 7 /* See options in include/netpacket/bluetooth.h */
#define SOL_RFCOMM 8 /* See options in include/netpacket/bluetooth.h */
+#define SOL_CAN_RAW 9 /* See options in include/netpacket/can.h */
/* Protocol-level socket options may begin with this value */
diff --git a/libs/libc/net/lib_recvmsg.c b/libs/libc/net/lib_recvmsg.c
index 984a16f..071c189 100644
--- a/libs/libc/net/lib_recvmsg.c
+++ b/libs/libc/net/lib_recvmsg.c
@@ -39,7 +39,7 @@
#include <nuttx/config.h>
-#ifdef CONFIG_NET
+#if defined(CONFIG_NET) && !defined(CONFIG_NET_CMSG)
#include <sys/types.h>
#include <sys/socket.h>
@@ -53,7 +53,8 @@
* Function: recvmsg
*
* Description:
- * The recvmsg() call is identical to recvfrom() with a NULL from parameter.
+ * The recvmsg() call is identical to recvfrom() with a NULL from
+ * parameter.
*
* Parameters:
* sockfd Socket descriptor of socket
@@ -86,4 +87,4 @@ ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
}
}
-#endif /* CONFIG_NET */
+#endif /* CONFIG_NET && !CONFIG_NET_CMSG */
diff --git a/libs/libc/net/lib_sendmsg.c b/libs/libc/net/lib_sendmsg.c
index 0d09faa..9f98e51 100644
--- a/libs/libc/net/lib_sendmsg.c
+++ b/libs/libc/net/lib_sendmsg.c
@@ -39,7 +39,7 @@
#include <nuttx/config.h>
-#ifdef CONFIG_NET
+#if defined(CONFIG_NET) && !defined(CONFIG_NET_CMSG)
#include <sys/types.h>
#include <sys/socket.h>
@@ -86,4 +86,4 @@ ssize_t sendmsg(int sockfd, FAR struct msghdr *msg, int flags)
}
}
-#endif /* CONFIG_NET */
+#endif /* CONFIG_NET && !CONFIG_NET_CMSG */
diff --git a/net/Kconfig b/net/Kconfig
index bedf933..80fe919 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -349,6 +349,7 @@ source "net/socket/Kconfig"
source "net/inet/Kconfig"
source "net/pkt/Kconfig"
source "net/local/Kconfig"
+source "net/can/Kconfig"
source "net/netlink/Kconfig"
source "net/tcp/Kconfig"
source "net/udp/Kconfig"
diff --git a/net/Makefile b/net/Makefile
index 077d035..f8ffe85 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -52,6 +52,7 @@ include igmp/Make.defs
include pkt/Make.defs
include local/Make.defs
include mld/Make.defs
+include can/Make.defs
include netlink/Make.defs
include tcp/Make.defs
include udp/Make.defs
diff --git a/net/bluetooth/bluetooth_sockif.c b/net/bluetooth/bluetooth_sockif.c
index 41bcafa..4057d93 100644
--- a/net/bluetooth/bluetooth_sockif.c
+++ b/net/bluetooth/bluetooth_sockif.c
@@ -106,9 +106,13 @@ const struct sock_intf_s g_bluetooth_sockif =
bluetooth_send, /* si_send */
bluetooth_sendto, /* si_sendto */
#ifdef CONFIG_NET_SENDFILE
- NULL, /* si_sendfile */
+ NULL, /* si_sendfile */
#endif
bluetooth_recvfrom, /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+ NULL, /* si_recvmsg */
+ NULL, /* si_sendmsg */
+#endif
bluetooth_close /* si_close */
};
@@ -243,10 +247,10 @@ static void bluetooth_addref(FAR struct socket *psock)
* Name: bluetooth_connect
*
* Description:
- * bluetooth_connect() connects the local socket referred to by the structure
- * 'psock' to the address specified by 'addr'. The addrlen argument
- * specifies the size of 'addr'. The format of the address in 'addr' is
- * determined by the address space of the socket 'psock'.
+ * bluetooth_connect() connects the local socket referred to by the
+ * structure 'psock' to the address specified by 'addr'. The addrlen
+ * argument specifies the size of 'addr'. The format of the address in
+ * 'addr' is determined by the address space of the socket 'psock'.
*
* Generally, connection-based protocol sockets may successfully
* bluetooth_connect() only once; connectionless protocol sockets may use
@@ -330,7 +334,8 @@ static int bluetooth_connect(FAR struct socket *psock,
* Input Parameters:
* psock Reference to the listening socket structure
* addr Receives the address of the connecting client
- * addrlen Input: allocated size of 'addr', Return: returned size of 'addr'
+ * addrlen Input: allocated size of 'addr',
+ * Return: returned size of 'addr'
* newsock Location to return the accepted socket information.
*
* Returned Value:
@@ -372,7 +377,7 @@ static int bluetooth_accept(FAR struct socket *psock,
****************************************************************************/
static int bluetooth_bind(FAR struct socket *psock,
- FAR const struct sockaddr *addr, socklen_t addrlen)
+ FAR const struct sockaddr *addr, socklen_t addrlen)
{
FAR const struct sockaddr_bt_s *iaddr;
FAR struct radio_driver_s *radio;
@@ -439,10 +444,10 @@ static int bluetooth_bind(FAR struct socket *psock,
* Name: bluetooth_getsockname
*
* Description:
- * The bluetooth_getsockname() function retrieves the locally-bound name of the
- * specified packet socket, stores this address in the sockaddr structure
- * pointed to by the 'addr' argument, and stores the length of this
- * address in the object pointed to by the 'addrlen' argument.
+ * The bluetooth_getsockname() function retrieves the locally-bound name of
+ * the specified packet socket, stores this address in the sockaddr
+ * structure pointed to by the 'addr' argument, and stores the length of
+ * this address in the object pointed to by the 'addrlen' argument.
*
* If the actual length of the address is greater than the length of the
* supplied sockaddr structure, the stored address will be truncated.
@@ -501,8 +506,8 @@ static int bluetooth_getsockname(FAR struct socket *psock,
* Name: bluetooth_getpeername
*
* Description:
- * The bluetooth_getpeername() function retrieves the remote-connected name of
- * the specified local socket, stores this address in the sockaddr
+ * The bluetooth_getpeername() function retrieves the remote-connected name
+ * of the specified local socket, stores this address in the sockaddr
* structure pointed to by the 'addr' argument, and stores the length of
* this address in the object pointed to by the 'addrlen' argument.
*
@@ -705,9 +710,10 @@ static ssize_t bluetooth_send(FAR struct socket *psock, FAR const void *buf,
*
****************************************************************************/
-static ssize_t bluetooth_sendto(FAR struct socket *psock, FAR const void *buf,
- size_t len, int flags,
- FAR const struct sockaddr *to, socklen_t tolen)
+static ssize_t bluetooth_sendto(FAR struct socket *psock,
+ FAR const void *buf, size_t len, int flags,
+ FAR const struct sockaddr *to,
+ socklen_t tolen)
{
ssize_t ret;
diff --git a/net/can/Kconfig b/net/can/Kconfig
new file mode 100644
index 0000000..e84c99d
--- /dev/null
+++ b/net/can/Kconfig
@@ -0,0 +1,97 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+menu "SocketCAN Support"
+
+config NET_CAN
+ bool "SocketCAN support"
+ default n
+ select NET_READAHEAD
+ depends on NET
+ ---help---
+ Enable support for SocketCAN sockets that will permit.
+
+ This logic is a WIP. Currently only fragmentary support is
+ available, not enough to actually do anything of consequence.
+
+if NET_CAN
+
+config NET_CAN_HAVE_TX_DEADLINE
+ bool
+ default n
+
+config NET_CAN_HAVE_CANFD
+ bool
+ default n
+
+config CAN_CONNS
+ int "Number of CAN connections"
+ default 4
+ ---help---
+ Maximum number of CAN connections (all tasks).
+
+config NET_CAN_CANFD
+ bool "Enable CAN FD support"
+ default y
+ depends on NET_CAN_HAVE_CANFD
+ ---help---
+ Enable CAN FD support in SocketCAN stack
+
+config NET_CAN_SOCK_OPTS
+ bool "sockopt support"
+ default n
+ select NET_SOCKOPTS
+ select NET_CANPROTO_OPTIONS
+ ---help---
+ Enable support for the CAN socket options
+
+config NET_CAN_RAW_TX_DEADLINE
+ bool "TX deadline sockopt"
+ default n
+ depends on NET_CAN_SOCK_OPTS && NET_CAN_HAVE_TX_DEADLINE
+ select NET_CMSG
+ ---help---
+ Note: Non-standard SocketCAN sockopt, but this options helps us in
+ real-time use cases.
+
+ When the CAN_RAW_TX_DEADLINE sockopt is enabled. The user can send
+ CAN frames using sendmsg() function and add a deadline timespec
+ value in the CMSG data. When the deadline has been passed and the
+ CAN frame is still in the HW TX mailbox then the CAN driver will
+ discard the CAN frame automatically.
+
+config NET_CAN_RAW_DEFAULT_TX_DEADLINE
+ int "Default TX deadline when no deadline is given (us)"
+ default 0
+ depends on NET_CAN_RAW_TX_DEADLINE
+ ---help---
+ Some applications may not use the NET_CAN_RAW_TX_DEADLINE flag.
+ By default their deadline becomes 0 which means it becomes infinite.
+ This would mean that packets from applications without the
+ NET_CAN_RAW_TX_DEADLINE flag, can block the TX mailboxes forever.
+ This config can set the default deadline when no deadline has been
+ given.
+
+config NET_CAN_RAW_FILTER_MAX
+ int "CAN_RAW_FILTER max filter count"
+ default 32
+ depends on NET_CAN_SOCK_OPTS
+ ---help---
+ Maximum number of CAN_RAW filters that can be set per CAN connection.
+
+config NET_CAN_NOTIFIER
+ bool "Support CAN notifications"
+ default n
+ depends on SCHED_WORKQUEUE
+ select WQUEUE_NOTIFIER
+ ---help---
+ Enable building of CAN notifier logic that will execute a worker
+ function on the low priority work queue when read-ahead data
+ is available or when a CAN connection is lost. This is is a general
+ purpose notifier, but was developed specifically to support poll()
+ logic where the poll must wait for these events.
+
+endif # NET_CAN
+endmenu # CAN Socket Support
diff --git a/net/can/Make.defs b/net/can/Make.defs
new file mode 100644
index 0000000..3204b3b
--- /dev/null
+++ b/net/can/Make.defs
@@ -0,0 +1,48 @@
+############################################################################
+# net/can/Make.defs
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+# Logic specific to SocketCAN socket support
+
+ifeq ($(CONFIG_NET_CAN),y)
+
+# Socket layer
+
+SOCK_CSRCS += can_sockif.c
+SOCK_CSRCS += can_send.c
+SOCK_CSRCS += can_recvfrom.c
+
+ifeq ($(CONFIG_NET_CAN_NOTIFIER),y)
+SOCK_CSRCS += can_notifier.c
+endif
+
+ifeq ($(CONFIG_NET_CANPROTO_OPTIONS),y)
+SOCK_CSRCS += can_setsockopt.c can_getsockopt.c
+endif
+
+NET_CSRCS += can_conn.c
+NET_CSRCS += can_input.c
+NET_CSRCS += can_callback.c
+NET_CSRCS += can_poll.c
+
+# Include can build support
+
+DEPPATH += --dep-path can
+VPATH += :can
+endif # CONFIG_NET_CAN
diff --git a/net/can/can.h b/net/can/can.h
new file mode 100644
index 0000000..cae3eb4
--- /dev/null
+++ b/net/can/can.h
@@ -0,0 +1,385 @@
+/****************************************************************************
+ * net/can/can.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __NET_CAN_CAN_H
+#define __NET_CAN_CAN_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <poll.h>
+
+#include <netpacket/can.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/can.h>
+#include <nuttx/net/netdev.h>
+
+#include "devif/devif.h"
+#include "socket/socket.h"
+
+#ifdef CONFIG_NET_CAN_NOTIFIER
+# include <nuttx/wqueue.h>
+#endif
+
+#ifdef CONFIG_NET_CAN
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Allocate a new packet socket data callback */
+
+#define can_callback_alloc(dev,conn) \
+ devif_callback_alloc(dev, &conn->list)
+#define can_callback_free(dev,conn,cb) \
+ devif_conn_callback_free(dev, cb, &conn->list)
+
+/****************************************************************************
+ * Public Type Definitions
+ ****************************************************************************/
+
+/* This is a container that holds the poll-related information */
+
+struct can_poll_s
+{
+ FAR struct socket *psock; /* Needed to handle loss of connection */
+ FAR struct net_driver_s *dev; /* Needed to free the callback structure */
+ struct pollfd *fds; /* Needed to handle poll events */
+ FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
+};
+
+/* This "connection" structure describes the underlying state of the socket */
+
+struct can_conn_s
+{
+ /* Common prologue of all connection structures. */
+
+ dq_entry_t node; /* Supports a doubly linked list */
+
+ /* This is a list of NetLink connection callbacks. Each callback
+ * represents a thread that is stalled, waiting for a device-specific
+ * event.
+ */
+
+ FAR struct devif_callback_s *list; /* NetLink callbacks */
+
+ FAR struct net_driver_s *dev; /* Reference to CAN device */
+
+ /* Read-ahead buffering.
+ *
+ * readahead - A singly linked list of type struct iob_qentry_s
+ * where the CAN/IP read-ahead data is retained.
+ */
+
+ struct iob_queue_s readahead; /* remove Read-ahead buffering */
+
+ /* CAN-specific content follows */
+
+ uint8_t protocol; /* Selected CAN protocol */
+ int16_t crefs; /* Reference count */
+
+ /* The following is a list of poll structures of threads waiting for
+ * socket events.
+ */
+
+ struct can_poll_s pollinfo[4]; /* FIXME make dynamic */
+
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+ int32_t loopback;
+ int32_t recv_own_msgs;
+#ifdef CONFIG_NET_CAN_CANFD
+ int32_t fd_frames;
+#endif
+ struct can_filter filters[CONFIG_NET_CAN_RAW_FILTER_MAX];
+ int32_t filter_count;
+# ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+ int32_t tx_deadline;
+# endif
+#endif
+
+#ifdef CONFIG_NET_TIMESTAMP
+ FAR struct socket *psock; /* Needed to get SO_TIMESTAMP value */
+#endif
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+# define EXTERN extern "C"
+extern "C"
+{
+#else
+# define EXTERN extern
+#endif
+
+EXTERN const struct sock_intf_s g_can_sockif;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+struct sockaddr_can; /* Forward reference */
+
+/****************************************************************************
+ * Name: can_initialize()
+ *
+ * Description:
+ * Initialize the NetLink connection structures. Called once and only
+ * from the networking layer.
+ *
+ ****************************************************************************/
+
+void can_initialize(void);
+
+/****************************************************************************
+ * Name: can_alloc()
+ *
+ * Description:
+ * Allocate a new, uninitialized NetLink connection structure. This is
+ * normally something done by the implementation of the socket() API
+ *
+ ****************************************************************************/
+
+FAR struct can_conn_s *can_alloc(void);
+
+/****************************************************************************
+ * Name: can_free()
+ *
+ * Description:
+ * Free a NetLink connection structure that is no longer in use. This
+ * should be done by the implementation of close().
+ *
+ ****************************************************************************/
+
+void can_free(FAR struct can_conn_s *conn);
+
+/****************************************************************************
+ * Name: can_nextconn()
+ *
+ * Description:
+ * Traverse the list of allocated NetLink connections
+ *
+ * Assumptions:
+ * This function is called from NetLink device logic.
+ *
+ ****************************************************************************/
+
+FAR struct can_conn_s *can_nextconn(FAR struct can_conn_s *conn);
+
+/****************************************************************************
+ * Name: can_callback
+ *
+ * Description:
+ * Inform the application holding the packet socket of a change in state.
+ *
+ * Returned Value:
+ * OK if packet has been processed, otherwise ERROR.
+ *
+ * Assumptions:
+ * This function is called from network logic at with the network locked.
+ *
+ ****************************************************************************/
+
+uint16_t can_callback(FAR struct net_driver_s *dev,
+ FAR struct can_conn_s *conn, uint16_t flags);
+
+/****************************************************************************
+ * Name: can_datahandler
+ *
+ * Description:
+ * Handle data that is not accepted by the application. This may be called
+ * either (1) from the data receive logic if it cannot buffer the data, or
+ * (2) from the CAN event logic is there is no listener in place ready to
+ * receive the data.
+ *
+ * Input Parameters:
+ * conn - A pointer to the CAN connection structure
+ * buffer - A pointer to the buffer to be copied to the read-ahead
+ * buffers
+ * buflen - The number of bytes to copy to the read-ahead buffer.
+ *
+ * Returned Value:
+ * The number of bytes actually buffered is returned. This will be either
+ * zero or equal to buflen; partial packets are not buffered.
+ *
+ * Assumptions:
+ * - The caller has checked that CAN_NEWDATA is set in flags and that is no
+ * other handler available to process the incoming data.
+ * - Called from network stack logic with the network stack locked
+ *
+ ****************************************************************************/
+
+uint16_t can_datahandler(FAR struct can_conn_s *conn, FAR uint8_t *buffer,
+ uint16_t buflen);
+
+/****************************************************************************
+ * Name: can_recvfrom
+ *
+ * Description:
+ * Implements the socket recvfrom interface pkt_recvfrom() receives
+ * messages from a socket, and may be used to receive data on a socket
+ * whether or not it is connection-oriented.
+ *
+ * Input Parameters:
+ * psock A pointer to a NuttX-specific, internal socket structure
+ * buf Buffer to receive data
+ * len Length of buffer
+ * flags Receive flags
+ * from Address of source (may be NULL)
+ * fromlen The length of the address structure
+ *
+ * Returned Value:
+ * On success, returns the number of characters received. If no data is
+ * available to be received and the peer has performed an orderly shutdown,
+ * recv() will return 0. Otherwise, on errors, a negated errno value is
+ * returned (see recvfrom() for the list of appropriate error values).
+ *
+ ****************************************************************************/
+
+ssize_t can_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
+ int flags, FAR struct sockaddr *from,
+ FAR socklen_t *fromlen);
+
+/****************************************************************************
+ * Name: can_recvmsg
+ *
+ * Description:
+ * recvmsg() receives messages from a socket, and may be used to receive
+ * data on a socket whether or not it is connection-oriented.
+ *
+ * If from is not NULL, and the underlying protocol provides the source
+ * address, this source address is filled in. The argument 'fromlen'
+ * initialized to the size of the buffer associated with from, and modified
+ * on return to indicate the actual size of the address stored there.
+ *
+ * Input Parameters:
+ * psock A pointer to a NuttX-specific, internal socket structure
+ * msg Buffer to receive msg
+ * flags Receive flags (ignored)
+ *
+ ****************************************************************************/
+#ifdef CONFIG_NET_CMSG
+ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+ int flags);
+#endif
+
+/****************************************************************************
+ * Name: can_poll
+ *
+ * Description:
+ * Poll a CAN connection structure for availability of TX data
+ *
+ * Input Parameters:
+ * dev - The device driver structure to use in the send operation
+ * conn - The CAN "connection" to poll for TX data
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called from network stack logic with the network stack locked
+ *
+ ****************************************************************************/
+
+void can_poll(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn);
+
+/****************************************************************************
+ * Name: psock_can_send
+ *
+ * Description:
+ * The psock_can_send() call may be used only when the packet socket is in
+ * a connected state (so that the intended recipient is known).
+ *
+ * Input Parameters:
+ * psock An instance of the internal socket structure.
+ * buf Data to send
+ * len Length of data to send
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. On error,
+ * a negated errno value is returned. See send() for the complete list
+ * of return values.
+ *
+ ****************************************************************************/
+
+struct socket;
+ssize_t psock_can_send(FAR struct socket *psock, FAR const void *buf,
+ size_t len);
+
+/****************************************************************************
+ * Name: psock_can_sendmsg
+ *
+ * Description:
+ * The psock_can_sendmsg() call may be used only when the packet socket is
+ * in a connected state (so that the intended recipient is known).
+ *
+ * Input Parameters:
+ * psock An instance of the internal socket structure.
+ * msg msg to send
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. On error,
+ * a negated errno value is returned. See send() for the complete list
+ * of return values.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CMSG
+ssize_t psock_can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg);
+#endif
+
+/****************************************************************************
+ * Name: can_readahead_signal
+ *
+ * Description:
+ * Read-ahead data has been buffered. Signal all threads waiting for
+ * read-ahead data to become available.
+ *
+ * When read-ahead data becomes available, *all* of the workers waiting
+ * for read-ahead data will be executed. If there are multiple workers
+ * waiting for read-ahead data then only the first to execute will get the
+ * data. Others will need to call can_readahead_notifier_setup() once
+ * again.
+ *
+ * Input Parameters:
+ * conn - The CAN connection where read-ahead data was just buffered.
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CAN_NOTIFIER
+void can_readahead_signal(FAR struct can_conn_s *conn);
+#endif
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_NET_CAN */
+#endif /* __NET_CAN_CAN_H */
diff --git a/net/can/can_callback.c b/net/can/can_callback.c
new file mode 100644
index 0000000..f8f0fae
--- /dev/null
+++ b/net/can/can_callback.c
@@ -0,0 +1,242 @@
+/****************************************************************************
+ * net/pkt/pkt_callback.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
+
+#include <stdint.h>
+#include <debug.h>
+
+#include <nuttx/net/netconfig.h>
+#include <nuttx/net/netdev.h>
+#include <nuttx/mm/iob.h>
+
+#include "devif/devif.h"
+#include "can/can.h"
+
+#ifdef CONFIG_NET_TIMESTAMP
+#include <sys/time.h>
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_data_event
+ *
+ * Description:
+ * Handle data that is not accepted by the application because there is no
+ * listener in place ready to receive the data.
+ *
+ * Assumptions:
+ * - The caller has checked that CAN_NEWDATA is set in flags and that is no
+ * other handler available to process the incoming data.
+ * - This function must be called with the network locked.
+ *
+ ****************************************************************************/
+
+static inline uint16_t
+can_data_event(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn,
+ uint16_t flags)
+{
+ uint16_t ret;
+ FAR uint8_t *buffer = dev->d_appdata;
+ int buflen = dev->d_len;
+ uint16_t recvlen;
+
+ ret = (flags & ~CAN_NEWDATA);
+
+ /* Save as the packet data as in the read-ahead buffer. NOTE that
+ * partial packets will not be buffered.
+ */
+
+ recvlen = can_datahandler(conn, buffer, buflen);
+ if (recvlen < buflen)
+ {
+ /* There is no handler to receive new data and there are no free
+ * read-ahead buffers to retain the data -- drop the packet.
+ */
+
+ ninfo("Dropped %d bytes\n", dev->d_len);
+
+#ifdef CONFIG_NET_STATISTICS
+ /* No support CAN net statistics yet */
+
+ /* g_netstats.tcp.drop++; */
+
+#endif
+ }
+
+ /* In any event, the new data has now been handled */
+
+ dev->d_len = 0;
+ return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_callback
+ *
+ * Description:
+ * Inform the application holding the packet socket of a change in state.
+ *
+ * Returned Value:
+ * OK if packet has been processed, otherwise ERROR.
+ *
+ * Assumptions:
+ * This function can be called from an interrupt.
+ *
+ ****************************************************************************/
+
+uint16_t can_callback(FAR struct net_driver_s *dev,
+ FAR struct can_conn_s *conn, uint16_t flags)
+{
+ /* Some sanity checking */
+
+ if (conn)
+ {
+#ifdef CONFIG_NET_TIMESTAMP
+ /* TIMESTAMP sockopt is activated, create timestamp and copy to iob */
+
+ if (conn->psock->s_timestamp)
+ {
+ struct timespec *ts = (struct timespec *)
+ &dev->d_appdata[dev->d_len];
+ struct timeval *tv = (struct timeval *)
+ &dev->d_appdata[dev->d_len];
+ dev->d_len += sizeof(struct timeval);
+ clock_systime_timespec(ts);
+ tv->tv_usec = ts->tv_nsec / 1000;
+ }
+#endif
+
+ /* Try to lock the network when successfull send data to the listener */
+
+ if (net_trylock() == OK)
+ {
+ flags = devif_conn_event(dev, conn, flags, conn->list);
+ net_unlock();
+ }
+
+ /* Either we did not get the lock or there is no application listening
+ * If we did not get a lock we store the frame in the read-ahead buffer
+ */
+
+ if ((flags & CAN_NEWDATA) != 0)
+ {
+ /* Data was not handled.. dispose of it appropriately */
+
+ flags = can_data_event(dev, conn, flags);
+ }
+ }
+
+ return flags;
+}
+
+/****************************************************************************
+ * Name: can_datahandler
+ *
+ * Description:
+ * Handle data that is not accepted by the application. This may be called
+ * either (1) from the data receive logic if it cannot buffer the data, or
+ * (2) from the CAN event logic is there is no listener in place ready to
+ * receive the data.
+ *
+ * Input Parameters:
+ * conn - A pointer to the CAN connection structure
+ * buffer - A pointer to the buffer to be copied to the read-ahead
+ * buffers
+ * buflen - The number of bytes to copy to the read-ahead buffer.
+ *
+ * Returned Value:
+ * The number of bytes actually buffered is returned. This will be either
+ * zero or equal to buflen; partial packets are not buffered.
+ *
+ * Assumptions:
+ * - The caller has checked that CAN_NEWDATA is set in flags and that is no
+ * other handler available to process the incoming data.
+ * - This function must be called with the network locked.
+ *
+ ****************************************************************************/
+
+uint16_t can_datahandler(FAR struct can_conn_s *conn, FAR uint8_t *buffer,
+ uint16_t buflen)
+{
+ FAR struct iob_s *iob;
+ int ret;
+
+ /* Try to allocate on I/O buffer to start the chain without waiting (and
+ * throttling as necessary). If we would have to wait, then drop the
+ * packet.
+ */
+
+ iob = iob_tryalloc(true, IOBUSER_NET_CAN_READAHEAD);
+ if (iob == NULL)
+ {
+ nerr("ERROR: Failed to create new I/O buffer chain\n");
+ return 0;
+ }
+
+ /* Copy the new appdata into the I/O buffer chain (without waiting) */
+
+ ret = iob_trycopyin(iob, buffer, buflen, 0, true,
+ IOBUSER_NET_CAN_READAHEAD);
+ if (ret < 0)
+ {
+ /* On a failure, iob_copyin return a negated error value but does
+ * not free any I/O buffers.
+ */
+
+ nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret);
+ iob_free_chain(iob, IOBUSER_NET_CAN_READAHEAD);
+ return 0;
+ }
+
+ /* Add the new I/O buffer chain to the tail of the read-ahead queue (again
+ * without waiting).
+ */
+
+ ret = iob_tryadd_queue(iob, &conn->readahead);
+ if (ret < 0)
+ {
+ nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
+ iob_free_chain(iob, IOBUSER_NET_CAN_READAHEAD);
+ return 0;
+ }
+
+#ifdef CONFIG_NET_CAN_NOTIFIER
+ /* Provide notification(s) that additional CAN read-ahead data is
+ * available.
+ */
+
+ can_readahead_signal(conn);
+#endif
+ return buflen;
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_CAN */
diff --git a/net/can/can_conn.c b/net/can/can_conn.c
new file mode 100644
index 0000000..574796c
--- /dev/null
+++ b/net/can/can_conn.c
@@ -0,0 +1,223 @@
+/****************************************************************************
+ * net/can/can_conn.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <string.h>
+#include <queue.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/net/netconfig.h>
+#include <nuttx/net/net.h>
+
+#include "utils/utils.h"
+#include "can/can.h"
+
+#ifdef CONFIG_NET_CAN
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The array containing all NetLink connections. */
+
+static struct can_conn_s g_can_connections[CONFIG_CAN_CONNS];
+
+/* A list of all free NetLink connections */
+
+static dq_queue_t g_free_can_connections;
+static sem_t g_free_sem;
+
+/* A list of all allocated NetLink connections */
+
+static dq_queue_t g_active_can_connections;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: _can_semtake() and _can_semgive()
+ *
+ * Description:
+ * Take/give semaphore
+ *
+ ****************************************************************************/
+
+static void _can_semtake(FAR sem_t *sem)
+{
+ net_lockedwait_uninterruptible(sem);
+}
+
+static void _can_semgive(FAR sem_t *sem)
+{
+ nxsem_post(sem);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_initialize()
+ *
+ * Description:
+ * Initialize the User Socket connection structures. Called once and only
+ * from the networking layer.
+ *
+ ****************************************************************************/
+
+void can_initialize(void)
+{
+ int i;
+
+ /* Initialize the queues */
+
+ dq_init(&g_free_can_connections);
+ dq_init(&g_active_can_connections);
+ nxsem_init(&g_free_sem, 0, 1);
+
+ for (i = 0; i < CONFIG_CAN_CONNS; i++)
+ {
+ FAR struct can_conn_s *conn = &g_can_connections[i];
+
+ /* Mark the connection closed and move it to the free list */
+
+ memset(conn, 0, sizeof(*conn));
+ dq_addlast(&conn->node, &g_free_can_connections);
+ }
+}
+
+/****************************************************************************
+ * Name: can_alloc()
+ *
+ * Description:
+ * Allocate a new, uninitialized NetLink connection structure. This is
+ * normally something done by the implementation of the socket() API
+ *
+ ****************************************************************************/
+
+FAR struct can_conn_s *can_alloc(void)
+{
+ FAR struct can_conn_s *conn;
+
+ /* The free list is protected by a semaphore (that behaves like a mutex). */
+
+ _can_semtake(&g_free_sem);
+ conn = (FAR struct can_conn_s *)dq_remfirst(&g_free_can_connections);
+ if (conn != NULL)
+ {
+ /* Make sure that the connection is marked as uninitialized */
+
+ memset(conn, 0, sizeof(*conn));
+
+ /* FIXME SocketCAN default behavior enables loopback */
+
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+ /* By default the filter is configured to catch all,
+ * this is done in commented filter code below:
+ *
+ * struct can_filter_t catchall_filter;
+ * filter.can_id = 0;
+ * filter.can_mask = 0;
+ * conn->filters[0] = catchall_filter;
+ *
+ * However memset already sets the filter to 0
+ * therefore we only have to set the filter count to 1
+ */
+
+ conn->filter_count = 1;
+#endif
+
+ /* Enqueue the connection into the active list */
+
+ dq_addlast(&conn->node, &g_active_can_connections);
+ }
+
+ _can_semgive(&g_free_sem);
+ return conn;
+}
+
+/****************************************************************************
+ * Name: can_free()
+ *
+ * Description:
+ * Free a NetLink connection structure that is no longer in use. This
+ * should be done by the implementation of close().
+ *
+ ****************************************************************************/
+
+void can_free(FAR struct can_conn_s *conn)
+{
+ /* The free list is protected by a semaphore (that behaves like a mutex). */
+
+ DEBUGASSERT(conn->crefs == 0);
+
+ _can_semtake(&g_free_sem);
+
+ /* Remove the connection from the active list */
+
+ dq_rem(&conn->node, &g_active_can_connections);
+
+ /* Reset structure */
+
+ memset(conn, 0, sizeof(*conn));
+
+ /* Free the connection */
+
+ dq_addlast(&conn->node, &g_free_can_connections);
+ _can_semgive(&g_free_sem);
+}
+
+/****************************************************************************
+ * Name: can_nextconn()
+ *
+ * Description:
+ * Traverse the list of allocated NetLink connections
+ *
+ * Assumptions:
+ * This function is called from NetLink device logic.
+ *
+ ****************************************************************************/
+
+FAR struct can_conn_s *can_nextconn(FAR struct can_conn_s *conn)
+{
+ if (conn == NULL)
+ {
+ return (FAR struct can_conn_s *)g_active_can_connections.head;
+ }
+ else
+ {
+ return (FAR struct can_conn_s *)conn->node.flink;
+ }
+}
+
+#endif /* CONFIG_NET_CAN */
diff --git a/net/can/can_getsockopt.c b/net/can/can_getsockopt.c
new file mode 100644
index 0000000..df6d0c9
--- /dev/null
+++ b/net/can/can_getsockopt.c
@@ -0,0 +1,220 @@
+/****************************************************************************
+ * net/can/can_setsockopt.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/time.h>
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <netpacket/can.h>
+
+#include <nuttx/net/net.h>
+#include <nuttx/net/can.h>
+
+#include "socket/socket.h"
+#include "utils/utils.h"
+#include "can/can.h"
+
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_getsockopt
+ *
+ * Description:
+ * can_getsockopt() retrieves the value for the option specified by the
+ * 'option' argument for the socket specified by the 'psock' argument. If
+ * the size of the option value is greater than 'value_len', the value
+ * stored in the object pointed to by the 'value' argument will be silently
+ * truncated. Otherwise, the length pointed to by the 'value_len' argument
+ * will be modified to indicate the actual length of the 'value'.
+ *
+ * See <sys/socket.h> a complete list of values for the socket-level
+ * 'option' argument. Protocol-specific options are are protocol specific
+ * header files (such as netpacket/can.h for the case of the CAN protocol).
+ *
+ * Input Parameters:
+ * psock Socket structure of the socket to query
+ * level Protocol level to set the option
+ * option identifies the option to get
+ * value Points to the argument value
+ * value_len The length of the argument value
+ *
+ * Returned Value:
+ * Returns zero (OK) on success. On failure, it returns a negated errno
+ * value to indicate the nature of the error. See psock_getsockopt() for
+ * the complete list of appropriate return error codes.
+ *
+ ****************************************************************************/
+
+int can_getsockopt(FAR struct socket *psock, int option,
+ FAR void *value, FAR socklen_t *value_len)
+{
+ FAR struct can_conn_s *conn;
+ int ret;
+
+ DEBUGASSERT(psock != NULL && value != NULL && value_len != NULL &&
+ psock->s_conn != NULL);
+ conn = (FAR struct can_conn_s *)psock->s_conn;
+
+ if (psock->s_type != SOCK_RAW)
+ {
+ nerr("ERROR: Not a RAW CAN socket\n");
+ return -ENOTCONN;
+ }
+
+ switch (option)
+ {
+ case CAN_RAW_FILTER:
+ if (*value_len % sizeof(struct can_filter) != 0)
+ {
+ ret = -EINVAL;
+ }
+ else if (*value_len > CONFIG_NET_CAN_RAW_FILTER_MAX *
+ sizeof(struct can_filter))
+ {
+ ret = -EINVAL;
+ }
+ else
+ {
+ int count = conn->filter_count;
+
+ if (*value_len < count * sizeof(struct can_filter))
+ {
+ count = *value_len / sizeof(struct can_filter);
+ }
+ else
+ {
+ *value_len = count * sizeof(struct can_filter);
+ }
+
+ for (int i = 0; i < count; i++)
+ {
+ ((struct can_filter *)value)[i] = conn->filters[i];
+ }
+
+ ret = OK;
+ }
+ break;
+
+ case CAN_RAW_ERR_FILTER:
+ break;
+
+ case CAN_RAW_LOOPBACK:
+ if (*value_len < sizeof(conn->loopback))
+ {
+ /* REVISIT: POSIX says that we should truncate the value if it
+ * is larger than value_len. That just doesn't make sense
+ * to me in this case.
+ */
+
+ ret = -EINVAL;
+ }
+ else
+ {
+ FAR int *loopback = (FAR int32_t *)value;
+ *loopback = conn->loopback;
+ *value_len = sizeof(conn->loopback);
+ ret = OK;
+ }
+ break;
+
+ case CAN_RAW_RECV_OWN_MSGS:
+ if (*value_len < sizeof(conn->recv_own_msgs))
+ {
+ /* REVISIT: POSIX says that we should truncate the value if it
+ * is larger than value_len. That just doesn't make sense
+ * to me in this case.
+ */
+
+ ret = -EINVAL;
+ }
+ else
+ {
+ FAR int *recv_own_msgs = (FAR int32_t *)value;
+ *recv_own_msgs = conn->recv_own_msgs;
+ *value_len = sizeof(conn->recv_own_msgs);
+ ret = OK;
+ }
+ break;
+
+ case CAN_RAW_FD_FRAMES:
+ if (*value_len < sizeof(conn->fd_frames))
+ {
+ /* REVISIT: POSIX says that we should truncate the value if it
+ * is larger than value_len. That just doesn't make sense
+ * to me in this case.
+ */
+
+ ret = -EINVAL;
+ }
+ else
+ {
+ FAR int *fd_frames = (FAR int32_t *)value;
+ *fd_frames = conn->fd_frames;
+ *value_len = sizeof(conn->fd_frames);
+ ret = OK;
+ }
+ break;
+
+ case CAN_RAW_JOIN_FILTERS:
+ break;
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+ case CAN_RAW_TX_DEADLINE:
+ if (*value_len < sizeof(conn->tx_deadline))
+ {
+ /* REVISIT: POSIX says that we should truncate the value if it
+ * is larger than value_len. That just doesn't make sense
+ * to me in this case.
+ */
+
+ ret = -EINVAL;
+ }
+ else
+ {
+ FAR int *tx_deadline = (FAR int32_t *)value;
+ *tx_deadline = conn->tx_deadline;
+ *value_len = sizeof(conn->tx_deadline);
+ ret = OK;
+ }
+ break;
+#endif
+
+ default:
+ nerr("ERROR: Unrecognized RAW CAN socket option: %d\n", option);
+ ret = -ENOPROTOOPT;
+ break;
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_NET_CANPROTO_OPTIONS */
diff --git a/net/can/can_input.c b/net/can/can_input.c
new file mode 100644
index 0000000..024bb9a
--- /dev/null
+++ b/net/can/can_input.c
@@ -0,0 +1,204 @@
+/****************************************************************************
+ * net/can/can_input.c
+ * Handling incoming packet input
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
+
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/net/netdev.h>
+#include <nuttx/net/can.h>
+
+#include "devif/devif.h"
+#include "can/can.h"
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+const uint8_t can_dlc_to_len[16] =
+{
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 12,
+ 16,
+ 20,
+ 24,
+ 32,
+ 48,
+ 64,
+};
+const uint8_t len_to_can_dlc[65] =
+{
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 9,
+ 9,
+ 9,
+ 10,
+ 10,
+ 10,
+ 10,
+ 11,
+ 11,
+ 11,
+ 11,
+ 12,
+ 12,
+ 12,
+ 12,
+ 13,
+ 13,
+ 13,
+ 13,
+ 13,
+ 13,
+ 13,
+ 13,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 14,
+ 15,
+ 15,
+ 15,
+ 15,
+ 15,
+ 15,
+ 15,
+ 15,
+ 15,
+ 15,
+ 15,
+ 15,
+ 15,
+ 15,
+ 15,
+ 15,
+};
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_input
+ *
+ * Description:
+ * Handle incoming packet input
+ *
+ * Input Parameters:
+ * dev - The device driver structure containing the received packet
+ *
+ * Returned Value:
+ * OK The packet has been processed and can be deleted
+ * -EAGAIN There is a matching connection, but could not dispatch the packet
+ * yet. Useful when a packet arrives before a recv call is in
+ * place.
+ *
+ * Assumptions:
+ * This function can be called from an interrupt.
+ *
+ ****************************************************************************/
+
+int can_input(struct net_driver_s *dev)
+{
+ FAR struct can_conn_s *conn = NULL;
+ int ret = OK;
+
+ do
+ {
+ /* FIXME Support for multiple sockets??? */
+
+ conn = can_nextconn(conn);
+ }
+ while (conn && conn->dev != 0 && dev != conn->dev);
+
+ if (conn)
+ {
+ uint16_t flags;
+
+ /* Setup for the application callback */
+
+ dev->d_appdata = dev->d_buf;
+ dev->d_sndlen = 0;
+
+ /* Perform the application callback */
+
+ flags = can_callback(dev, conn, CAN_NEWDATA);
+
+ /* If the operation was successful, the CAN_NEWDATA flag is removed
+ * and thus the packet can be deleted (OK will be returned).
+ */
+
+ if ((flags & CAN_NEWDATA) != 0)
+ {
+ /* No.. the packet was not processed now. Return -EAGAIN so
+ * that the driver may retry again later. We still need to
+ * set d_len to zero so that the driver is aware that there
+ * is nothing to be sent.
+ */
+
+ nwarn("WARNING: Packet not processed\n");
+ ret = -EAGAIN;
+ }
+ }
+ else
+ {
+ ninfo("No CAN listener\n");
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_CAN */
diff --git a/libs/libc/net/lib_recvmsg.c b/net/can/can_notifier.c
similarity index 70%
copy from libs/libc/net/lib_recvmsg.c
copy to net/can/can_notifier.c
index 984a16f..f4c7b1e 100644
--- a/libs/libc/net/lib_recvmsg.c
+++ b/net/can/can_notifier.c
@@ -1,7 +1,7 @@
/****************************************************************************
- * libc/net/lib_recvmsg.c
+ * net/can/can_notifier.c
*
- * Copyright (C) 2007, 2008, 2012, 2008 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gn...@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -39,51 +39,45 @@
#include <nuttx/config.h>
-#ifdef CONFIG_NET
-
#include <sys/types.h>
-#include <sys/socket.h>
-#include <errno.h>
+#include <assert.h>
+
+#include <nuttx/wqueue.h>
+
+#include "can/can.h"
+
+#ifdef CONFIG_NET_CAN_NOTIFIER
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
- * Function: recvmsg
+ * Name: can_readahead_signal
*
* Description:
- * The recvmsg() call is identical to recvfrom() with a NULL from parameter.
+ * Read-ahead data has been buffered. Signal all threads waiting for
+ * read-ahead data to become available.
*
- * Parameters:
- * sockfd Socket descriptor of socket
- * buf Buffer to receive data
- * len Length of buffer
- * flags Receive flags
+ * When read-ahead data becomes available, *all* of the workers waiting
+ * for read-ahead data will be executed. If there are multiple workers
+ * waiting for read-ahead data then only the first to execute will get the
+ * data. Others will need to call can_readahead_notifier_setup() once
+ * again.
*
- * Returned Value:
- * (see recvfrom)
+ * Input Parameters:
+ * conn - The CAN connection where read-ahead data was just buffered.
*
- * Assumptions:
+ * Returned Value:
+ * None.
*
****************************************************************************/
-ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
+void can_readahead_signal(FAR struct can_conn_s *conn)
{
- FAR void *buf = msg->msg_iov->iov_base;
- FAR struct sockaddr *from = msg->msg_name;
- FAR socklen_t *fromlen = (FAR socklen_t *)&msg->msg_namelen;
- size_t len = msg->msg_iov->iov_len;
+ /* This is just a simple wrapper around work_notifier_signal(). */
- if (msg->msg_iovlen == 1)
- {
- return recvfrom(sockfd, buf, len, flags, from, fromlen);
- }
- else
- {
- set_errno(ENOTSUP);
- return ERROR;
- }
+ work_notifier_signal(WORK_CAN_READAHEAD, conn);
}
-#endif /* CONFIG_NET */
+#endif /* CONFIG_NET_CAN_NOTIFIER */
diff --git a/net/can/can_poll.c b/net/can/can_poll.c
new file mode 100644
index 0000000..2163242
--- /dev/null
+++ b/net/can/can_poll.c
@@ -0,0 +1,88 @@
+/****************************************************************************
+ * net/pkt/pkt_poll.c
+ * Poll for the availability of packet TX data
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
+
+#include <debug.h>
+
+#include <nuttx/net/netconfig.h>
+#include <nuttx/net/netdev.h>
+
+#include "devif/devif.h"
+#include "can/can.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_poll
+ *
+ * Description:
+ * Poll a packet "connection" structure for availability of TX data
+ *
+ * Input Parameters:
+ * dev - The device driver structure to use in the send operation
+ * conn - The packet "connection" to poll for TX data
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+void can_poll(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn)
+{
+ /* Verify that the packet connection is valid */
+
+ if (conn != NULL)
+ {
+ /* Setup for the application callback */
+
+ dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN(dev)];
+ dev->d_len = 0;
+ dev->d_sndlen = 0;
+
+ /* Perform the application callback */
+
+ can_callback(dev, conn, CAN_POLL);
+
+ /* Check if the application has data to send */
+
+ if (dev->d_sndlen > 0)
+ {
+ return;
+ }
+ }
+
+ /* Make sure that d_len is zero meaning that there is nothing to be sent */
+
+ dev->d_len = 0;
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_CAN */
diff --git a/net/can/can_recvfrom.c b/net/can/can_recvfrom.c
new file mode 100644
index 0000000..bbea9c3
--- /dev/null
+++ b/net/can/can_recvfrom.c
@@ -0,0 +1,838 @@
+/****************************************************************************
+ * net/can/can_recvfrom.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifdef CONFIG_NET_CAN
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+#include <assert.h>
+
+#include <arch/irq.h>
+
+#include <nuttx/semaphore.h>
+#include <nuttx/net/net.h>
+#include <nuttx/net/netdev.h>
+
+#include "netdev/netdev.h"
+#include "devif/devif.h"
+#include "can/can.h"
+#include "socket/socket.h"
+#include <netpacket/packet.h>
+
+#ifdef CONFIG_NET_TIMESTAMP
+#include <sys/time.h>
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct can_recvfrom_s
+{
+ FAR struct socket *pr_sock; /* The parent socket structure */
+ FAR struct devif_callback_s *pr_cb; /* Reference to callback instance */
+ sem_t pr_sem; /* Semaphore signals recv completion */
+ size_t pr_buflen; /* Length of receive buffer */
+ FAR uint8_t *pr_buffer; /* Pointer to receive buffer */
+ ssize_t pr_recvlen; /* The received length */
+#ifdef CONFIG_NET_CMSG
+ size_t pr_msglen; /* Length of msg buffer */
+ FAR uint8_t *pr_msgbuf; /* Pointer to msg buffer */
+#endif
+ int pr_result; /* Success:OK, failure:negated errno */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_add_recvlen
+ *
+ * Description:
+ * Update information about space available for new data and update size
+ * of data in buffer, This logic accounts for the case where
+ * recvfrom_udpreadahead() sets state.pr_recvlen == -1 .
+ *
+ * Input Parameters:
+ * pstate recvfrom state structure
+ * recvlen size of new data appended to buffer
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static inline void can_add_recvlen(FAR struct can_recvfrom_s *pstate,
+ size_t recvlen)
+{
+ if (pstate->pr_recvlen < 0)
+ {
+ pstate->pr_recvlen = 0;
+ }
+
+ pstate->pr_recvlen += recvlen;
+ pstate->pr_buffer += recvlen;
+ pstate->pr_buflen -= recvlen;
+}
+
+/****************************************************************************
+ * Name: can_recvfrom_newdata
+ *
+ * Description:
+ * Copy the read data from the packet
+ *
+ * Input Parameters:
+ * dev The structure of the network driver that caused the event.
+ * pstate recvfrom state structure
+ *
+ * Returned Value:
+ * None.
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static size_t can_recvfrom_newdata(FAR struct net_driver_s *dev,
+ FAR struct can_recvfrom_s *pstate)
+{
+ size_t recvlen;
+
+ if (dev->d_len > pstate->pr_buflen)
+ {
+ recvlen = pstate->pr_buflen;
+ }
+ else
+ {
+ recvlen = dev->d_len;
+ }
+
+ /* Copy the new packet data into the user buffer */
+
+ memcpy(pstate->pr_buffer, dev->d_buf, recvlen);
+
+ /* Update the accumulated size of the data read */
+
+ can_add_recvlen(pstate, recvlen);
+
+ return recvlen;
+}
+
+/****************************************************************************
+ * Name: can_newdata
+ *
+ * Description:
+ * Copy the read data from the packet
+ *
+ * Input Parameters:
+ * dev The structure of the network driver that generated the event
+ * pstate recvfrom state structure
+ *
+ * Returned Value:
+ * None.
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static inline void can_newdata(FAR struct net_driver_s *dev,
+ FAR struct can_recvfrom_s *pstate)
+{
+ /* Take as much data from the packet as we can */
+
+ size_t recvlen = can_recvfrom_newdata(dev, pstate);
+
+ /* If there is more data left in the packet that we could not buffer, then
+ * add it to the read-ahead buffers.
+ */
+
+ if (recvlen < dev->d_len)
+ {
+ FAR struct can_conn_s *conn =
+ (FAR struct can_conn_s *)pstate->pr_sock->s_conn;
+ FAR uint8_t *buffer = (FAR uint8_t *)dev->d_appdata + recvlen;
+ uint16_t buflen = dev->d_len - recvlen;
+#ifdef CONFIG_DEBUG_NET
+ uint16_t nsaved;
+
+ nsaved = can_datahandler(conn, buffer, buflen);
+#else
+ can_datahandler(conn, buffer, buflen);
+#endif
+
+ /* There are complicated buffering issues that are not addressed fully
+ * here. For example, what if up_datahandler() cannot buffer the
+ * remainder of the packet? In that case, the data will be dropped but
+ * still ACKed. Therefore it would not be resent.
+ *
+ * This is probably not an issue here because we only get here if the
+ * read-ahead buffers are empty and there would have to be something
+ * serioulsy wrong with the configuration not to be able to buffer a
+ * partial packet in this context.
+ */
+
+#ifdef CONFIG_DEBUG_NET
+ if (nsaved < buflen)
+ {
+ nerr("ERROR: packet data not saved (%d bytes)\n", buflen - nsaved);
+ }
+#endif
+ }
+
+ /* Indicate no data in the buffer */
+
+ dev->d_len = 0;
+}
+
+/****************************************************************************
+ * Name: can_readahead
+ *
+ * Description:
+ * Copy the read-ahead data from the packet
+ *
+ * Input Parameters:
+ * pstate recvfrom state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static inline int can_readahead(struct can_recvfrom_s *pstate)
+{
+ FAR struct can_conn_s *conn =
+ (FAR struct can_conn_s *) pstate->pr_sock->s_conn;
+ FAR struct iob_s *iob;
+ int recvlen;
+
+ /* Check there is any CAN data already buffered in a read-ahead
+ * buffer.
+ */
+
+ pstate->pr_recvlen = -1;
+
+ if ((iob = iob_peek_queue(&conn->readahead)) != NULL &&
+ pstate->pr_buflen > 0)
+ {
+ DEBUGASSERT(iob->io_pktlen > 0);
+
+ /* Transfer that buffered data from the I/O buffer chain into
+ * the user buffer.
+ */
+
+ recvlen = iob_copyout(pstate->pr_buffer, iob, pstate->pr_buflen, 0);
+
+ /* If we took all of the data from the I/O buffer chain is empty, then
+ * release it. If there is still data available in the I/O buffer
+ * chain, then just trim the data that we have taken from the
+ * beginning of the I/O buffer chain.
+ */
+
+ if (recvlen >= iob->io_pktlen)
+ {
+ FAR struct iob_s *tmp;
+
+ /* Remove the I/O buffer chain from the head of the read-ahead
+ * buffer queue.
+ */
+
+ tmp = iob_remove_queue(&conn->readahead);
+ DEBUGASSERT(tmp == iob);
+ UNUSED(tmp);
+
+ /* And free the I/O buffer chain */
+
+ iob_free_chain(iob, IOBUSER_NET_CAN_READAHEAD);
+ }
+ else
+ {
+ /* The bytes that we have received from the head of the I/O
+ * buffer chain (probably changing the head of the I/O
+ * buffer queue).
+ */
+
+ iob_trimhead_queue(&conn->readahead, recvlen,
+ IOBUSER_NET_CAN_READAHEAD);
+ }
+
+ /* do not pass frames with DLC > 8 to a legacy socket */
+#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)
+ if (!conn->fd_frames)
+#endif
+ {
+ if (recvlen > sizeof(struct can_frame))
+ {
+ return 0;
+ }
+ }
+
+ return recvlen;
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ * Name: can_readahead
+ *
+ * Description:
+ * Copy the read-ahead data from the packet
+ *
+ * Input Parameters:
+ * pstate recvfrom state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_TIMESTAMP
+static inline int can_readahead_timestamp(struct can_conn_s *conn,
+ FAR uint8_t *buffer)
+{
+ FAR struct iob_s *iob;
+ int recvlen;
+
+ if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
+ {
+ DEBUGASSERT(iob->io_pktlen > 0);
+
+ /* Transfer that buffered data from the I/O buffer chain into
+ * the user buffer.
+ */
+
+ recvlen = iob_copyout(buffer, iob, sizeof(struct timeval), 0);
+
+ /* If we took all of the data from the I/O buffer chain is empty, then
+ * release it. If there is still data available in the I/O buffer
+ * chain, then just trim the data that we have taken from the
+ * beginning of the I/O buffer chain.
+ */
+
+ if (recvlen >= iob->io_pktlen)
+ {
+ FAR struct iob_s *tmp;
+
+ /* Remove the I/O buffer chain from the head of the read-ahead
+ * buffer queue.
+ */
+
+ tmp = iob_remove_queue(&conn->readahead);
+ DEBUGASSERT(tmp == iob);
+ UNUSED(tmp);
+
+ /* And free the I/O buffer chain */
+
+ iob_free_chain(iob, IOBUSER_NET_CAN_READAHEAD);
+ }
+ else
+ {
+ /* The bytes that we have received from the head of the I/O
+ * buffer chain (probably changing the head of the I/O
+ * buffer queue).
+ */
+
+ iob_trimhead_queue(&conn->readahead, recvlen,
+ IOBUSER_NET_CAN_READAHEAD);
+ }
+
+ return recvlen;
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+static int can_recv_filter(struct can_conn_s *conn, canid_t id)
+{
+ for (int i = 0; i < conn->filter_count; i++)
+ {
+ if (conn->filters[i].can_id & CAN_INV_FILTER)
+ {
+ if ((id & conn->filters[i].can_mask) !=
+ ((conn->filters[i].can_id & ~CAN_INV_FILTER) &
+ conn->filters[i].can_mask))
+ {
+ return 1;
+ }
+ }
+ else
+ {
+ if ((id & conn->filters[i].can_mask) ==
+ (conn->filters[i].can_id & conn->filters[i].can_mask))
+ {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static uint16_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev,
+ FAR void *pvconn,
+ FAR void *pvpriv, uint16_t flags)
+{
+ struct can_recvfrom_s *pstate = (struct can_recvfrom_s *)pvpriv;
+ struct can_conn_s *conn = (struct can_conn_s *)pstate->pr_sock->s_conn;
+
+ /* 'priv' might be null in some race conditions (?) */
+
+ if (pstate)
+ {
+ if ((flags & CAN_NEWDATA) != 0)
+ {
+ /* If a new packet is available, check receive filters
+ * when is valid then complete the read action.
+ */
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+ if (can_recv_filter(conn, (canid_t) *dev->d_appdata) == 0)
+ {
+ flags &= ~CAN_NEWDATA;
+ return flags;
+ }
+#endif
+
+ /* do not pass frames with DLC > 8 to a legacy socket */
+#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)
+ if (!conn->fd_frames)
+#endif
+ {
+ if (dev->d_len > sizeof(struct can_frame))
+ {
+ /* DO WE NEED TO CLEAR FLAGS?? */
+
+ flags &= ~CAN_NEWDATA;
+ return flags;
+ }
+ }
+
+ /* Copy the packet */
+
+ can_newdata(dev, pstate);
+
+#ifdef CONFIG_NET_TIMESTAMP
+ if (pstate->pr_sock->s_timestamp)
+ {
+ if (pstate->pr_msglen == sizeof(struct timeval))
+ {
+ can_readahead_timestamp(conn, pstate->pr_msgbuf);
+ }
+ else
+ {
+ /* We still have to consume the data
+ * otherwise IOB gets full
+ */
+
+ uint8_t dummy_buf[sizeof(struct timeval)];
+ can_readahead_timestamp(conn, (uint8_t *)&dummy_buf);
+ }
+ }
+#endif
+
+ /* We are finished. */
+
+ /* Don't allow any further call backs. */
+
+ pstate->pr_cb->flags = 0;
+ pstate->pr_cb->priv = NULL;
+ pstate->pr_cb->event = NULL;
+
+ /* indicate that the data has been consumed */
+
+ flags &= ~CAN_NEWDATA;
+
+ /* Wake up the waiting thread, returning the number of bytes
+ * actually read.
+ */
+
+ nxsem_post(&pstate->pr_sem);
+ }
+ }
+
+ return flags;
+}
+
+/****************************************************************************
+ * Name: can_recvfrom_result
+ *
+ * Description:
+ * Evaluate the result of the recv operations
+ *
+ * Input Parameters:
+ * result The result of the net_lockedwait operation (may indicate EINTR)
+ * pstate A pointer to the state structure to be initialized
+ *
+ * Returned Value:
+ * The result of the recv operation with errno set appropriately
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static ssize_t can_recvfrom_result(int result,
+ FAR struct can_recvfrom_s *pstate)
+{
+ /* Check for a error/timeout detected by the event handler. Errors are
+ * signaled by negative errno values for the rcv length
+ */
+
+ if (pstate->pr_result < 0)
+ {
+ /* This might return EAGAIN on a timeout */
+
+ return pstate->pr_result;
+ }
+
+ /* If net_lockedwait failed, then we were probably reawakened by a signal.
+ * In this case, net_lockedwait will have returned negated errno
+ * appropriately.
+ */
+
+ if (result < 0)
+ {
+ return result;
+ }
+
+ return pstate->pr_recvlen;
+}
+
+/****************************************************************************
+ * Name: can_recvfrom
+ *
+ * Description:
+ * recvfrom() receives messages from a socket, and may be used to receive
+ * data on a socket whether or not it is connection-oriented.
+ *
+ * If from is not NULL, and the underlying protocol provides the source
+ * address, this source address is filled in. The argument 'fromlen'
+ * initialized to the size of the buffer associated with from, and modified
+ * on return to indicate the actual size of the address stored there.
+ *
+ * Input Parameters:
+ * psock A pointer to a NuttX-specific, internal socket structure
+ * buf Buffer to receive data
+ * len Length of buffer
+ * flags Receive flags (ignored)
+ * from Address of source (may be NULL)
+ * fromlen The length of the address structure
+ *
+ ****************************************************************************/
+
+ssize_t can_recvfrom(FAR struct socket *psock, FAR void *buf,
+ size_t len, int flags,
+ FAR struct sockaddr *from,
+ FAR socklen_t *fromlen)
+{
+ FAR struct can_conn_s *conn;
+ FAR struct net_driver_s *dev;
+ struct can_recvfrom_s state;
+ int ret;
+
+ DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL);
+ DEBUGASSERT(from == NULL ||
+ (fromlen != NULL && *fromlen >= sizeof(struct sockaddr_can)));
+
+ conn = (FAR struct can_conn_s *)psock->s_conn;
+
+ if (psock->s_type != SOCK_RAW)
+ {
+ nerr("ERROR: Unsupported socket type: %d\n", psock->s_type);
+ ret = -ENOSYS;
+ }
+
+ net_lock();
+
+ /* Initialize the state structure. */
+
+ memset(&state, 0, sizeof(struct can_recvfrom_s));
+
+ /* This semaphore is used for signaling and, hence, should not have
+ * priority inheritance enabled.
+ */
+
+ nxsem_init(&state.pr_sem, 0, 0); /* Doesn't really fail */
+ nxsem_set_protocol(&state.pr_sem, SEM_PRIO_NONE);
+
+ state.pr_buflen = len;
+ state.pr_buffer = buf;
+ state.pr_sock = psock;
+
+ /* Handle any any CAN data already buffered in a read-ahead buffer. NOTE
+ * that there may be read-ahead data to be retrieved even after the
+ * socket has been disconnected.
+ */
+
+ ret = can_readahead(&state);
+ if (ret > 0)
+ {
+ goto errout_with_state;
+ }
+
+ ret = state.pr_recvlen;
+
+ /* Handle non-blocking CAN sockets */
+
+ if (_SS_ISNONBLOCK(psock->s_flags) || (flags & MSG_DONTWAIT) != 0)
+ {
+ /* Return the number of bytes read from the read-ahead buffer if
+ * something was received (already in 'ret'); EAGAIN if not.
+ */
+
+ if (ret < 0)
+ {
+ /* Nothing was received */
+
+ ret = -EAGAIN;
+ goto errout_with_state;
+ }
+ }
+
+ /* Get the device driver that will service this transfer */
+
+ dev = conn->dev;
+ if (dev == NULL)
+ {
+ ret = -ENODEV;
+ goto errout_with_state;
+ }
+
+ /* Set up the callback in the connection */
+
+ state.pr_cb = can_callback_alloc(dev, conn);
+ if (state.pr_cb)
+ {
+ state.pr_cb->flags = (CAN_NEWDATA | CAN_POLL);
+ state.pr_cb->priv = (FAR void *)&state;
+ state.pr_cb->event = can_recvfrom_eventhandler;
+
+ /* Wait for either the receive to complete or for an error/timeout to
+ * occur. NOTES: (1) net_lockedwait will also terminate if a signal
+ * is received, (2) the network is locked! It will be un-locked while
+ * the task sleeps and automatically re-locked when the task restarts.
+ */
+
+ ret = net_lockedwait(&state.pr_sem);
+
+ /* Make sure that no further events are processed */
+
+ can_callback_free(dev, conn, state.pr_cb);
+ ret = can_recvfrom_result(ret, &state);
+ }
+ else
+ {
+ ret = -EBUSY;
+ }
+
+errout_with_state:
+ net_unlock();
+ nxsem_destroy(&state.pr_sem);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: can_recvmsg
+ *
+ * Description:
+ * recvmsg() receives messages from a socket, and may be used to receive
+ * data on a socket whether or not it is connection-oriented.
+ *
+ * If from is not NULL, and the underlying protocol provides the source
+ * address, this source address is filled in. The argument 'fromlen'
+ * initialized to the size of the buffer associated with from, and modified
+ * on return to indicate the actual size of the address stored there.
+ *
+ * Input Parameters:
+ * psock A pointer to a NuttX-specific, internal socket structure
+ * msg Buffer to receive msg
+ * flags Receive flags (ignored)
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CMSG
+ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+ int flags)
+{
+ FAR struct can_conn_s *conn;
+ FAR struct net_driver_s *dev;
+ struct can_recvfrom_s state;
+ int ret;
+
+ DEBUGASSERT(psock != NULL && psock->s_conn != NULL && msg != NULL);
+
+ conn = (FAR struct can_conn_s *)psock->s_conn;
+
+ if (psock->s_type != SOCK_RAW)
+ {
+ nerr("ERROR: Unsupported socket type: %d\n", psock->s_type);
+ ret = -ENOSYS;
+ }
+
+ net_lock();
+
+ /* Initialize the state structure. */
+
+ memset(&state, 0, sizeof(struct can_recvfrom_s));
+
+ /* This semaphore is used for signaling and, hence, should not have
+ * priority inheritance enabled.
+ */
+
+ nxsem_init(&state.pr_sem, 0, 0); /* Doesn't really fail */
+ nxsem_set_protocol(&state.pr_sem, SEM_PRIO_NONE);
+
+ state.pr_buflen = msg->msg_iov->iov_len;
+ state.pr_buffer = msg->msg_iov->iov_base;
+
+#ifdef CONFIG_NET_TIMESTAMP
+ if (psock->s_timestamp && msg->msg_controllen >=
+ (sizeof(struct cmsghdr) + sizeof(struct timeval)))
+ {
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
+ state.pr_msglen = sizeof(struct timeval);
+ state.pr_msgbuf = CMSG_DATA(cmsg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SO_TIMESTAMP;
+ cmsg->cmsg_len = state.pr_msglen;
+ msg->msg_controllen = sizeof(struct cmsghdr) + sizeof(struct timeval);
+ }
+ else
+ {
+ /* Expected behavior is that the msg_controllen becomes 0,
+ * otherwise CMSG_NXTHDR will go into a infinite loop
+ */
+
+ msg->msg_controllen = 0;
+ }
+#endif
+
+ state.pr_sock = psock;
+
+ /* Handle any any CAN data already buffered in a read-ahead buffer. NOTE
+ * that there may be read-ahead data to be retrieved even after the
+ * socket has been disconnected.
+ */
+
+ ret = can_readahead(&state);
+ if (ret > 0)
+ {
+#ifdef CONFIG_NET_TIMESTAMP
+ if (psock->s_timestamp)
+ {
+ if (state.pr_msglen == sizeof(struct timeval))
+ {
+ can_readahead_timestamp(conn, state.pr_msgbuf);
+ }
+ else
+ {
+ /* We still have to consume the data otherwise IOB gets full */
+
+ uint8_t dummy_buf[sizeof(struct timeval)];
+ can_readahead_timestamp(conn, (uint8_t *)&dummy_buf);
+ }
+ }
+#endif
+
+ goto errout_with_state;
+ }
+
+ ret = state.pr_recvlen;
+
+ /* Handle non-blocking CAN sockets */
+
+ if (_SS_ISNONBLOCK(psock->s_flags) || (flags & MSG_DONTWAIT) != 0)
+ {
+ /* Return the number of bytes read from the read-ahead buffer if
+ * something was received (already in 'ret'); EAGAIN if not.
+ */
+
+ if (ret < 0)
+ {
+ /* Nothing was received */
+
+ ret = -EAGAIN;
+ goto errout_with_state;
+ }
+ }
+
+ /* Get the device driver that will service this transfer */
+
+ dev = conn->dev;
+ if (dev == NULL)
+ {
+ ret = -ENODEV;
+ goto errout_with_state;
+ }
+
+ /* Set up the callback in the connection */
+
+ state.pr_cb = can_callback_alloc(dev, conn);
+ if (state.pr_cb)
+ {
+ state.pr_cb->flags = (CAN_NEWDATA | CAN_POLL);
+ state.pr_cb->priv = (FAR void *)&state;
+ state.pr_cb->event = can_recvfrom_eventhandler;
+
+ /* Wait for either the receive to complete or for an error/timeout to
+ * occur. NOTES: (1) net_lockedwait will also terminate if a signal
+ * is received, (2) the network is locked! It will be un-locked while
+ * the task sleeps and automatically re-locked when the task restarts.
+ */
+
+ ret = net_lockedwait(&state.pr_sem);
+
+ /* Make sure that no further events are processed */
+
+ can_callback_free(dev, conn, state.pr_cb);
+ ret = can_recvfrom_result(ret, &state);
+ }
+ else
+ {
+ ret = -EBUSY;
+ }
+
+errout_with_state:
+ net_unlock();
+ nxsem_destroy(&state.pr_sem);
+ return ret;
+}
+#endif
+
+#endif /* CONFIG_NET_CAN */
diff --git a/net/can/can_send.c b/net/can/can_send.c
new file mode 100644
index 0000000..3c01684
--- /dev/null
+++ b/net/can/can_send.c
@@ -0,0 +1,441 @@
+/****************************************************************************
+ * net/can/can_send.c
+ *
+ * Copyright (C) 2014, 2016-2017 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN)
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <arch/irq.h>
+
+#include <nuttx/semaphore.h>
+#include <nuttx/net/netdev.h>
+#include <nuttx/net/net.h>
+#include <nuttx/net/ip.h>
+
+#include "netdev/netdev.h"
+#include "devif/devif.h"
+#include "socket/socket.h"
+#include "can/can.h"
+
+#ifdef CONFIG_NET_CMSG
+#include <sys/time.h>
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure holds the state of the send operation until it can be
+ * operated upon by the event handler.
+ */
+
+struct send_s
+{
+ FAR struct socket *snd_sock; /* Points to the parent socket structure */
+ FAR struct devif_callback_s *snd_cb; /* Reference to callback instance */
+ sem_t snd_sem; /* Used to wake up the waiting thread */
+ FAR const uint8_t *snd_buffer; /* Points to the buffer of data to send */
+ size_t snd_buflen; /* Number of bytes in the buffer to send */
+#ifdef CONFIG_NET_CMSG
+ size_t pr_msglen; /* Length of msg buffer */
+ FAR uint8_t *pr_msgbuf; /* Pointer to msg buffer */
+#endif
+ ssize_t snd_sent; /* The number of bytes sent */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: psock_send_eventhandler
+ ****************************************************************************/
+
+static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
+ FAR void *pvconn,
+ FAR void *pvpriv, uint16_t flags)
+{
+ FAR struct send_s *pstate = (FAR struct send_s *)pvpriv;
+
+ if (pstate)
+ {
+ /* Check if the outgoing packet is available. It may have been claimed
+ * by a send event handler serving a different thread -OR- if the
+ * output buffer currently contains unprocessed incoming data. In
+ * these cases we will just have to wait for the next polling cycle.
+ */
+
+ if (dev->d_sndlen > 0 || (flags & CAN_NEWDATA) != 0)
+ {
+ /* Another thread has beat us sending data or the buffer is busy,
+ * Check for a timeout. If not timed out, wait for the next
+ * polling cycle and check again.
+ */
+
+ /* No timeout. Just wait for the next polling cycle */
+
+ return flags;
+ }
+
+ /* It looks like we are good to send the data */
+
+ else
+ {
+ /* Copy the packet data into the device packet buffer and send it */
+
+ devif_can_send(dev, pstate->snd_buffer, pstate->snd_buflen);
+ pstate->snd_sent = pstate->snd_buflen;
+#ifdef CONFIG_NET_CMSG
+ if (pstate->pr_msglen > 0) /* concat cmsg data after packet */
+ {
+ memcpy(dev->d_buf + pstate->snd_buflen, pstate->pr_msgbuf,
+ pstate->pr_msglen);
+ dev->d_sndlen = pstate->snd_buflen + pstate->pr_msglen;
+ }
+#endif
+ }
+
+ /* Don't allow any further call backs. */
+
+ pstate->snd_cb->flags = 0;
+ pstate->snd_cb->priv = NULL;
+ pstate->snd_cb->event = NULL;
+
+ /* Wake up the waiting thread */
+
+ nxsem_post(&pstate->snd_sem);
+ }
+
+ return flags;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: psock_can_send
+ *
+ * Description:
+ * The psock_can_send() call may be used only when the packet socket is in
+ * a connected state (so that the intended recipient is known).
+ *
+ * Input Parameters:
+ * psock An instance of the internal socket structure.
+ * buf Data to send
+ * len Length of data to send
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. On error,
+ * a negated errno value is retruend. See send() for the complete list
+ * of return values.
+ *
+ ****************************************************************************/
+
+ssize_t psock_can_send(FAR struct socket *psock, FAR const void *buf,
+ size_t len)
+{
+ FAR struct net_driver_s *dev;
+ FAR struct can_conn_s *conn;
+ struct send_s state;
+ int ret = OK;
+
+ conn = (FAR struct can_conn_s *)psock->s_conn;
+
+ /* Verify that the sockfd corresponds to valid, allocated socket */
+
+ if (!psock || psock->s_crefs <= 0)
+ {
+ return -EBADF;
+ }
+
+ /* Get the device driver that will service this transfer */
+
+ dev = conn->dev;
+ if (dev == NULL)
+ {
+ return -ENODEV;
+ }
+#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)
+
+ if (conn->fd_frames)
+ {
+ if (len != CANFD_MTU && len != CAN_MTU)
+ {
+ return -EINVAL;
+ }
+ }
+#endif
+ else
+ {
+ if (len != CAN_MTU)
+ {
+ return -EINVAL;
+ }
+ }
+
+ /* Perform the send operation */
+
+ /* Initialize the state structure. This is done with the network locked
+ * because we don't want anything to happen until we are ready.
+ */
+
+ net_lock();
+ memset(&state, 0, sizeof(struct send_s));
+
+ /* This semaphore is used for signaling and, hence, should not have
+ * priority inheritance enabled.
+ */
+
+ nxsem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */
+ nxsem_set_protocol(&state.snd_sem, SEM_PRIO_NONE);
+
+ state.snd_sock = psock; /* Socket descriptor to use */
+ state.snd_buflen = len; /* Number of bytes to send */
+ state.snd_buffer = buf; /* Buffer to send from */
+
+ /* Allocate resource to receive a callback */
+
+ state.snd_cb = can_callback_alloc(dev, conn);
+ if (state.snd_cb)
+ {
+ /* Set up the callback in the connection */
+
+ state.snd_cb->flags = CAN_POLL;
+ state.snd_cb->priv = (FAR void *)&state;
+ state.snd_cb->event = psock_send_eventhandler;
+
+ /* Notify the device driver that new TX data is available. */
+
+ netdev_txnotify_dev(dev);
+
+ /* Wait for the send to complete or an error to occur.
+ * net_lockedwait will also terminate if a signal is received.
+ */
+
+ ret = net_lockedwait(&state.snd_sem);
+
+ /* Make sure that no further events are processed */
+
+ can_callback_free(dev, conn, state.snd_cb);
+ }
+
+ nxsem_destroy(&state.snd_sem);
+ net_unlock();
+
+ /* Check for a errors, Errors are signalled by negative errno values
+ * for the send length
+ */
+
+ if (state.snd_sent < 0)
+ {
+ return state.snd_sent;
+ }
+
+ /* If net_lockedwait failed, then we were probably reawakened by a signal.
+ * In this case, net_lockedwait will have returned negated errno
+ * appropriately.
+ */
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Return the number of bytes actually sent */
+
+ return state.snd_sent;
+}
+
+/****************************************************************************
+ * Name: psock_can_sendmsg
+ *
+ * Description:
+ * The psock_can_sendmsg() call may be used only when the packet socket is
+ * in a connected state (so that the intended recipient is known).
+ *
+ * Input Parameters:
+ * psock An instance of the internal socket structure.
+ * msg msg to send
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. On error,
+ * a negated errno value is retruend. See send() for the complete list
+ * of return values.
+ *
+ ****************************************************************************/
+
+ssize_t psock_can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg)
+{
+ FAR struct net_driver_s *dev;
+ FAR struct can_conn_s *conn;
+ struct send_s state;
+ int ret = OK;
+
+ conn = (FAR struct can_conn_s *)psock->s_conn;
+
+ /* Verify that the sockfd corresponds to valid, allocated socket */
+
+ if (!psock || psock->s_crefs <= 0)
+ {
+ return -EBADF;
+ }
+
+ /* Get the device driver that will service this transfer */
+
+ dev = conn->dev;
+ if (dev == NULL)
+ {
+ return -ENODEV;
+ }
+
+#if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD)
+ if (conn->fd_frames)
+ {
+ if (msg->msg_iov->iov_len != CANFD_MTU
+ && msg->msg_iov->iov_len != CAN_MTU)
+ {
+ return -EINVAL;
+ }
+ }
+ else
+#endif
+ {
+ if (msg->msg_iov->iov_len != CAN_MTU)
+ {
+ return -EINVAL;
+ }
+ }
+
+ /* Perform the send operation */
+
+ /* Initialize the state structure. This is done with the network locked
+ * because we don't want anything to happen until we are ready.
+ */
+
+ net_lock();
+ memset(&state, 0, sizeof(struct send_s));
+
+ /* This semaphore is used for signaling and, hence, should not have
+ * priority inheritance enabled.
+ */
+
+ nxsem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */
+ nxsem_set_protocol(&state.snd_sem, SEM_PRIO_NONE);
+
+ state.snd_sock = psock; /* Socket descriptor */
+ state.snd_buflen = msg->msg_iov->iov_len; /* bytes to send */
+ state.snd_buffer = msg->msg_iov->iov_base; /* Buffer to send from */
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+ if (msg->msg_controllen > sizeof(struct cmsghdr))
+ {
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
+ if (conn->tx_deadline && cmsg->cmsg_level == SOL_CAN_RAW
+ && cmsg->cmsg_type == CAN_RAW_TX_DEADLINE
+ && cmsg->cmsg_len == sizeof(struct timeval))
+ {
+ state.pr_msgbuf = CMSG_DATA(cmsg); /* Buffer to cmsg data */
+ state.pr_msglen = cmsg->cmsg_len; /* len of cmsg data */
+ }
+ }
+#endif
+
+ /* Allocate resource to receive a callback */
+
+ state.snd_cb = can_callback_alloc(dev, conn);
+ if (state.snd_cb)
+ {
+ /* Set up the callback in the connection */
+
+ state.snd_cb->flags = CAN_POLL;
+ state.snd_cb->priv = (FAR void *)&state;
+ state.snd_cb->event = psock_send_eventhandler;
+
+ /* Notify the device driver that new TX data is available. */
+
+ netdev_txnotify_dev(dev);
+
+ /* Wait for the send to complete or an error to occur.
+ * net_lockedwait will also terminate if a signal is received.
+ */
+
+ ret = net_lockedwait(&state.snd_sem);
+
+ /* Make sure that no further events are processed */
+
+ can_callback_free(dev, conn, state.snd_cb);
+ }
+
+ nxsem_destroy(&state.snd_sem);
+ net_unlock();
+
+ /* Check for a errors, Errors are signalled by negative errno values
+ * for the send length
+ */
+
+ if (state.snd_sent < 0)
+ {
+ return state.snd_sent;
+ }
+
+ /* If net_lockedwait failed, then we were probably reawakened by a signal.
+ * In this case, net_lockedwait will have returned negated errno
+ * appropriately.
+ */
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Return the number of bytes actually sent */
+
+ return state.snd_sent;
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_CAN */
diff --git a/net/can/can_setsockopt.c b/net/can/can_setsockopt.c
new file mode 100644
index 0000000..3359e40
--- /dev/null
+++ b/net/can/can_setsockopt.c
@@ -0,0 +1,177 @@
+/****************************************************************************
+ * net/can/can_setsockopt.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/time.h>
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <netpacket/can.h>
+
+#include <nuttx/net/net.h>
+#include <nuttx/net/can.h>
+
+#include "socket/socket.h"
+#include "utils/utils.h"
+#include "can/can.h"
+
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: can_setsockopt
+ *
+ * Description:
+ * can_setsockopt() sets the CAN-protocol option specified by the
+ * 'option' argument to the value pointed to by the 'value' argument for
+ * the socket specified by the 'psock' argument.
+ *
+ * See <netinet/can.h> for the a complete list of values of CAN protocol
+ * options.
+ *
+ * Input Parameters:
+ * psock Socket structure of socket to operate on
+ * option identifies the option to set
+ * value Points to the argument value
+ * value_len The length of the argument value
+ *
+ * Returned Value:
+ * Returns zero (OK) on success. On failure, it returns a negated errno
+ * value to indicate the nature of the error. See psock_setcockopt() for
+ * the list of possible error values.
+ *
+ ****************************************************************************/
+
+int can_setsockopt(FAR struct socket *psock, int option,
+ FAR const void *value, socklen_t value_len)
+{
+ FAR struct can_conn_s *conn;
+ int ret;
+ int count = 0;
+
+ DEBUGASSERT(psock != NULL && value != NULL && psock->s_conn != NULL);
+ conn = (FAR struct can_conn_s *)psock->s_conn;
+
+ if (psock->s_type != SOCK_RAW)
+ {
+ nerr("ERROR: Not a RAW CAN socket\n");
+ return -ENOTCONN;
+ }
+
+ switch (option)
+ {
+ case CAN_RAW_FILTER:
+ if (value_len == 0)
+ {
+ conn->filter_count = 0;
+ ret = OK;
+ }
+ else if (value_len % sizeof(struct can_filter) != 0)
+ {
+ ret = -EINVAL;
+ }
+ else if (value_len > CONFIG_NET_CAN_RAW_FILTER_MAX *
+ sizeof(struct can_filter))
+ {
+ ret = -EINVAL;
+ }
+ else
+ {
+ count = value_len / sizeof(struct can_filter);
+
+ for (int i = 0; i < count; i++)
+ {
+ conn->filters[i] = ((struct can_filter *)value)[i];
+ }
+
+ conn->filter_count = count;
+
+ ret = OK;
+ }
+ break;
+
+ case CAN_RAW_ERR_FILTER:
+ break;
+
+ case CAN_RAW_LOOPBACK:
+ if (value_len != sizeof(conn->loopback))
+ {
+ return -EINVAL;
+ }
+
+ conn->loopback = *(FAR int32_t *)value;
+
+ break;
+
+ case CAN_RAW_RECV_OWN_MSGS:
+ if (value_len != sizeof(conn->recv_own_msgs))
+ {
+ return -EINVAL;
+ }
+
+ conn->recv_own_msgs = *(FAR int32_t *)value;
+
+ break;
+
+ case CAN_RAW_FD_FRAMES:
+ if (value_len != sizeof(conn->fd_frames))
+ {
+ return -EINVAL;
+ }
+
+ conn->fd_frames = *(FAR int32_t *)value;
+
+ break;
+
+ case CAN_RAW_JOIN_FILTERS:
+ break;
+
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+ case CAN_RAW_TX_DEADLINE:
+ if (value_len != sizeof(conn->tx_deadline))
+ {
+ return -EINVAL;
+ }
+
+ conn->tx_deadline = *(FAR int32_t *)value;
+
+ break;
+#endif
+
+ default:
+ nerr("ERROR: Unrecognized CAN option: %d\n", option);
+ ret = -ENOPROTOOPT;
+ break;
+ }
+
+ return ret;
+}
+
+#endif /* CONFIG_NET_CANPROTO_OPTIONS */
diff --git a/net/netlink/netlink_sockif.c b/net/can/can_sockif.c
similarity index 52%
copy from net/netlink/netlink_sockif.c
copy to net/can/can_sockif.c
index 577d520..d39934f 100644
--- a/net/netlink/netlink_sockif.c
+++ b/net/can/can_sockif.c
@@ -1,35 +1,20 @@
/****************************************************************************
- * net/netlink/netlink_sockif.c
- *
- * Copyright (C) 2018-2019 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gn...@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * net/can/can_sockif.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
*
****************************************************************************/
@@ -54,64 +39,69 @@
#include <nuttx/wqueue.h>
#include <nuttx/net/net.h>
-#include "netlink/netlink.h"
+#include "can/can.h"
+#include "netdev/netdev.h"
-#ifdef CONFIG_NET_NETLINK
+#ifdef CONFIG_NET_CAN
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
-static int netlink_setup(FAR struct socket *psock, int protocol);
-static sockcaps_t netlink_sockcaps(FAR struct socket *psock);
-static void netlink_addref(FAR struct socket *psock);
-static int netlink_bind(FAR struct socket *psock,
+static int can_setup(FAR struct socket *psock, int protocol);
+static sockcaps_t can_sockcaps(FAR struct socket *psock);
+static void can_addref(FAR struct socket *psock);
+static int can_bind(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
-static int netlink_getsockname(FAR struct socket *psock,
+static int can_getsockname(FAR struct socket *psock,
FAR struct sockaddr *addr, FAR socklen_t *addrlen);
-static int netlink_getpeername(FAR struct socket *psock,
+static int can_getpeername(FAR struct socket *psock,
FAR struct sockaddr *addr, FAR socklen_t *addrlen);
-static int netlink_listen(FAR struct socket *psock, int backlog);
-static int netlink_connect(FAR struct socket *psock,
+static int can_listen(FAR struct socket *psock, int backlog);
+static int can_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
-static int netlink_accept(FAR struct socket *psock,
- FAR struct sockaddr *addr, FAR socklen_t *addrlen,
- FAR struct socket *newsock);
-static int netlink_poll(FAR struct socket *psock, FAR struct pollfd *fds,
+static int can_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
+ FAR socklen_t *addrlen, FAR struct socket *newsock);
+static int can_poll_local(FAR struct socket *psock, FAR struct pollfd *fds,
bool setup);
-static ssize_t netlink_send(FAR struct socket *psock,
+static ssize_t can_send(FAR struct socket *psock,
FAR const void *buf, size_t len, int flags);
-static ssize_t netlink_sendto(FAR struct socket *psock, FAR const void *buf,
+static ssize_t can_sendto(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags, FAR const struct sockaddr *to,
socklen_t tolen);
-static ssize_t netlink_recvfrom(FAR struct socket *psock, FAR void *buf,
- size_t len, int flags, FAR struct sockaddr *from,
- FAR socklen_t *fromlen);
-static int netlink_close(FAR struct socket *psock);
+#ifdef CONFIG_NET_CMSG
+static ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+ int flags);
+#endif
+static int can_close(FAR struct socket *psock);
/****************************************************************************
* Public Data
****************************************************************************/
-const struct sock_intf_s g_netlink_sockif =
+const struct sock_intf_s g_can_sockif =
{
- netlink_setup, /* si_setup */
- netlink_sockcaps, /* si_sockcaps */
- netlink_addref, /* si_addref */
- netlink_bind, /* si_bind */
- netlink_getsockname, /* si_getsockname */
- netlink_getpeername, /* si_getpeername */
- netlink_listen, /* si_listen */
- netlink_connect, /* si_connect */
- netlink_accept, /* si_accept */
- netlink_poll, /* si_poll */
- netlink_send, /* si_send */
- netlink_sendto, /* si_sendto */
+ can_setup, /* si_setup */
+ can_sockcaps, /* si_sockcaps */
+ can_addref, /* si_addref */
+ can_bind, /* si_bind */
+ can_getsockname, /* si_getsockname */
+ can_getpeername, /* si_getpeername */
+ can_listen, /* si_listen */
+ can_connect, /* si_connect */
+ can_accept, /* si_accept */
+ can_poll_local, /* si_poll */
+ can_send, /* si_send */
+ can_sendto, /* si_sendto */
#ifdef CONFIG_NET_SENDFILE
- NULL, /* si_sendfile */
+ NULL, /* si_sendfile */
+#endif
+ can_recvfrom, /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+ can_recvmsg, /* si_recvmsg */
+ can_sendmsg, /* si_sendmsg */
#endif
- netlink_recvfrom, /* si_recvfrom */
- netlink_close /* si_close */
+ can_close /* si_close */
};
/****************************************************************************
@@ -119,7 +109,77 @@ const struct sock_intf_s g_netlink_sockif =
****************************************************************************/
/****************************************************************************
- * Name: netlink_setup
+ * Name: can_poll_eventhandler
+ *
+ * Description:
+ * This function is called to perform the actual CAN receive operation
+ * via the device interface layer. from can_input()
+ *
+ * Input Parameters:
+ * dev The structure of the network driver that caused the event
+ * conn The connection structure associated with the socket
+ * flags Set of events describing why the callback was invoked
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * This function must be called with the network locked.
+ *
+ ****************************************************************************/
+
+static uint16_t can_poll_eventhandler(FAR struct net_driver_s *dev,
+ FAR void *conn,
+ FAR void *pvpriv, uint16_t flags)
+{
+ FAR struct can_poll_s *info = (FAR struct can_poll_s *)pvpriv;
+
+ DEBUGASSERT(!info || (info->psock && info->fds));
+
+ /* 'priv' might be null in some race conditions (?) */
+
+ if (info)
+ {
+ pollevent_t eventset = 0;
+
+ /* Check for data or connection availability events. */
+
+ if ((flags & CAN_NEWDATA) != 0)
+ {
+ eventset |= (POLLIN & info->fds->events);
+ }
+
+ /* Check for loss of connection events. */
+
+ if ((flags & NETDEV_DOWN) != 0)
+ {
+ eventset |= (POLLHUP | POLLERR);
+ }
+
+#if 0
+ /* A poll is a sign that we are free to send data. */
+
+ else if ((flags & CAN_POLL) != 0 &&
+ psock_udp_cansend(info->psock) >= 0)
+ {
+ eventset |= (POLLOUT & info->fds->events);
+ }
+#endif
+
+ /* Awaken the caller of poll() is requested event occurred. */
+
+ if (eventset)
+ {
+ info->fds->revents |= eventset;
+ nxsem_post(info->fds->sem);
+ }
+ }
+
+ return flags;
+}
+
+/****************************************************************************
+ * Name: can_setup
*
* Description:
* Called for socket() to verify that the provided socket type and
@@ -137,7 +197,7 @@ const struct sock_intf_s g_netlink_sockif =
*
****************************************************************************/
-static int netlink_setup(FAR struct socket *psock, int protocol)
+static int can_setup(FAR struct socket *psock, int protocol)
{
int domain = psock->s_domain;
int type = psock->s_type;
@@ -148,24 +208,29 @@ static int netlink_setup(FAR struct socket *psock, int protocol)
switch (protocol)
{
-#ifdef CONFIG_NETLINK_ROUTE
- case NETLINK_ROUTE:
+ case 0: /* INET subsystem for netlib_ifup */
+ case CAN_RAW: /* RAW sockets */
+ case CAN_BCM: /* Broadcast Manager */
+ case CAN_TP16: /* VAG Transport Protocol v1.6 */
+ case CAN_TP20: /* VAG Transport Protocol v2.0 */
+ case CAN_MCNET: /* Bosch MCNet */
+ case CAN_ISOTP: /* ISO 15765-2 Transport Protocol */
+ case CAN_J1939: /* SAE J1939 */
break;
-#endif
default:
return -EPROTONOSUPPORT;
}
- /* Verify the socket type (domain should always be PF_NETLINK here) */
+ /* Verify the socket type (domain should always be PF_CAN here) */
- if (domain == PF_NETLINK && (type == SOCK_RAW || type == SOCK_DGRAM))
+ if (domain == PF_CAN && (type == SOCK_RAW || type == SOCK_DGRAM))
{
/* Allocate the NetLink socket connection structure and save it in the
* new socket instance.
*/
- FAR struct netlink_conn_s *conn = netlink_alloc();
+ FAR struct can_conn_s *conn = can_alloc();
if (conn == NULL)
{
/* Failed to reserve a connection structure */
@@ -173,6 +238,12 @@ static int netlink_setup(FAR struct socket *psock, int protocol)
return -ENOMEM;
}
+#ifdef CONFIG_NET_TIMESTAMP
+ /* Store psock in conn se we can read the SO_TIMESTAMP value */
+
+ conn->psock = psock;
+#endif
+
/* Initialize the connection instance */
conn->protocol = (uint8_t)protocol;
@@ -194,7 +265,7 @@ static int netlink_setup(FAR struct socket *psock, int protocol)
}
/****************************************************************************
- * Name: netlink_sockcaps
+ * Name: can_sockcaps
*
* Description:
* Return the bit encoded capabilities of this socket.
@@ -208,7 +279,7 @@ static int netlink_setup(FAR struct socket *psock, int protocol)
*
****************************************************************************/
-static sockcaps_t netlink_sockcaps(FAR struct socket *psock)
+static sockcaps_t can_sockcaps(FAR struct socket *psock)
{
/* Permit vfcntl to set socket to non-blocking */
@@ -216,7 +287,7 @@ static sockcaps_t netlink_sockcaps(FAR struct socket *psock)
}
/****************************************************************************
- * Name: netlink_addref
+ * Name: can_addref
*
* Description:
* Increment the reference count on the underlying connection structure.
@@ -230,9 +301,9 @@ static sockcaps_t netlink_sockcaps(FAR struct socket *psock)
*
****************************************************************************/
-static void netlink_addref(FAR struct socket *psock)
+static void can_addref(FAR struct socket *psock)
{
- FAR struct netlink_conn_s *conn;
+ FAR struct can_conn_s *conn;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
@@ -242,10 +313,10 @@ static void netlink_addref(FAR struct socket *psock)
}
/****************************************************************************
- * Name: netlink_bind
+ * Name: can_bind
*
* Description:
- * netlink_bind() gives the socket 'conn' the local address 'addr'. 'addr'
+ * can_bind() gives the socket 'conn' the local address 'addr'. 'addr'
* is 'addrlen' bytes long. Traditionally, this is called "assigning a name
* to a socket." When a socket is created with socket, it exists in a name
* space (address family) but has no name assigned.
@@ -271,28 +342,34 @@ static void netlink_addref(FAR struct socket *psock)
*
****************************************************************************/
-static int netlink_bind(FAR struct socket *psock,
- FAR const struct sockaddr *addr, socklen_t addrlen)
+static int can_bind(FAR struct socket *psock,
+ FAR const struct sockaddr *addr, socklen_t addrlen)
{
- FAR struct sockaddr_nl *nladdr;
- FAR struct netlink_conn_s *conn;
-
+ FAR struct sockaddr_can *canaddr;
+ FAR struct can_conn_s *conn;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL && addr != NULL &&
- addrlen >= sizeof(struct sockaddr_nl));
+ addrlen >= sizeof(struct sockaddr_can));
/* Save the address information in the connection structure */
- nladdr = (FAR struct sockaddr_nl *)addr;
- conn = (FAR struct netlink_conn_s *)psock->s_conn;
+ canaddr = (FAR struct sockaddr_can *)addr;
+ conn = (FAR struct can_conn_s *)psock->s_conn;
+
+ /* Bind CAN device to socket */
- conn->pid = nladdr->nl_pid ? nladdr->nl_pid : getpid();
- conn->groups = nladdr->nl_groups;
+#ifdef CONFIG_NETDEV_IFINDEX
+ conn->dev = netdev_findbyindex(canaddr->can_ifindex);
+#else
+ char netdev_name[5] = "can0";
+ netdev_name[3] += canaddr->can_ifindex;
+ conn->dev = netdev_findbyname((const char *)&netdev_name);
+#endif
return OK;
}
/****************************************************************************
- * Name: netlink_getsockname
+ * Name: can_getsockname
*
* Description:
* The getsockname() function retrieves the locally-bound name of the
@@ -313,36 +390,18 @@ static int netlink_bind(FAR struct socket *psock,
*
****************************************************************************/
-static int netlink_getsockname(FAR struct socket *psock,
- FAR struct sockaddr *addr,
- FAR socklen_t *addrlen)
+static int can_getsockname(FAR struct socket *psock,
+ FAR struct sockaddr *addr,
+ FAR socklen_t *addrlen)
{
- FAR struct sockaddr_nl *nladdr;
- FAR struct netlink_conn_s *conn;
-
- DEBUGASSERT(psock != NULL && psock->s_conn != NULL && addr != NULL &&
- addrlen != NULL && *addrlen >= sizeof(struct sockaddr_nl));
-
- conn = (FAR struct netlink_conn_s *)psock->s_conn;
-
- /* Return the address information in the address structure */
-
- nladdr = (FAR struct sockaddr_nl *)addr;
- memset(nladdr, 0, sizeof(struct sockaddr_nl));
-
- nladdr->nl_family = AF_NETLINK;
- nladdr->nl_pid = conn->pid;
- nladdr->nl_groups = conn->groups;
-
- *addrlen = sizeof(struct sockaddr_nl);
- return OK;
+ return -EAFNOSUPPORT;
}
/****************************************************************************
- * Name: netlink_getpeername
+ * Name: can_getpeername
*
* Description:
- * The netlink_getpeername() function retrieves the remote-connected name
+ * The can_getpeername() function retrieves the remote-connected name
* of the specified packet socket, stores this address in the sockaddr
* structure pointed to by the 'addr' argument, and stores the length of
* this address in the object pointed to by the 'addrlen' argument.
@@ -366,33 +425,15 @@ static int netlink_getsockname(FAR struct socket *psock,
*
****************************************************************************/
-static int netlink_getpeername(FAR struct socket *psock,
- FAR struct sockaddr *addr,
- FAR socklen_t *addrlen)
+static int can_getpeername(FAR struct socket *psock,
+ FAR struct sockaddr *addr,
+ FAR socklen_t *addrlen)
{
- FAR struct sockaddr_nl *nladdr;
- FAR struct netlink_conn_s *conn;
-
- DEBUGASSERT(psock != NULL && psock->s_conn != NULL && addr != NULL &&
- addrlen != NULL && *addrlen >= sizeof(struct sockaddr_nl));
-
- conn = (FAR struct netlink_conn_s *)psock->s_conn;
-
- /* Return the address information in the address structure */
-
- nladdr = (FAR struct sockaddr_nl *)addr;
- memset(nladdr, 0, sizeof(struct sockaddr_nl));
-
- nladdr->nl_family = AF_NETLINK;
- nladdr->nl_pid = conn->dst_pid;
- nladdr->nl_groups = conn->dst_groups;
-
- *addrlen = sizeof(struct sockaddr_nl);
- return OK;
+ return -EOPNOTSUPP;
}
/****************************************************************************
- * Name: netlink_listen
+ * Name: can_listen
*
* Description:
* To accept connections, a socket is first created with psock_socket(), a
@@ -417,19 +458,20 @@ static int netlink_getpeername(FAR struct socket *psock,
*
****************************************************************************/
-static int netlink_listen(FAR struct socket *psock, int backlog)
+static int can_listen(FAR struct socket *psock, int backlog)
{
return -EOPNOTSUPP;
}
/****************************************************************************
- * Name: netlink_connect
+ * Name: can_connect
*
* Description:
- * Perform a netlink connection
+ * Perform a can connection
*
* Input Parameters:
- * psock A reference to the structure of the socket to be connected
+ * psock A reference to the socket structure of the socket
+ * to be connected
* addr The address of the remote server to connect to
* addrlen Length of address buffer
*
@@ -440,32 +482,18 @@ static int netlink_listen(FAR struct socket *psock, int backlog)
*
****************************************************************************/
-static int netlink_connect(FAR struct socket *psock,
- FAR const struct sockaddr *addr,
- socklen_t addrlen)
+static int can_connect(FAR struct socket *psock,
+ FAR const struct sockaddr *addr,
+ socklen_t addrlen)
{
- FAR struct sockaddr_nl *nladdr;
- FAR struct netlink_conn_s *conn;
-
- DEBUGASSERT(psock != NULL && psock->s_conn != NULL && addr != NULL &&
- addrlen >= sizeof(struct sockaddr_nl));
-
- /* Save the address information in the connection structure */
-
- nladdr = (FAR struct sockaddr_nl *)addr;
- conn = (FAR struct netlink_conn_s *)psock->s_conn;
-
- conn->dst_pid = nladdr->nl_pid;
- conn->dst_groups = nladdr->nl_groups;
-
- return OK;
+ return -EOPNOTSUPP;
}
/****************************************************************************
- * Name: netlink_accept
+ * Name: can_accept
*
* Description:
- * The netlink_accept function is used with connection-based socket
+ * The can_accept function is used with connection-based socket
* types (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first
* connection request on the queue of pending connections, creates a new
* connected socket with mostly the same properties as 'sockfd', and
@@ -484,7 +512,7 @@ static int netlink_connect(FAR struct socket *psock,
* actual length of the address returned.
*
* If no pending connections are present on the queue, and the socket is
- * not marked as non-blocking, accept blocks the caller until a
+ * not marked as non-blocking, inet_accept blocks the caller until a
* connection is present. If the socket is marked non-blocking and no
* pending connections are present on the queue, inet_accept returns
* EAGAIN.
@@ -505,63 +533,14 @@ static int netlink_connect(FAR struct socket *psock,
*
****************************************************************************/
-static int netlink_accept(FAR struct socket *psock,
- FAR struct sockaddr *addr, FAR socklen_t *addrlen,
- FAR struct socket *newsock)
+static int can_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
+ FAR socklen_t *addrlen, FAR struct socket *newsock)
{
return -EOPNOTSUPP;
}
/****************************************************************************
- * Name: netlink_response_available
- *
- * Description:
- * Handle a Netlink response available notification.
- *
- * Input Parameters:
- * Standard work handler parameters
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
-
-static void netlink_response_available(FAR void *arg)
-{
- FAR struct netlink_conn_s *conn = arg;
-
- DEBUGASSERT(conn != NULL);
-
- /* The following should always be true ... but maybe not in some race
- * condition?
- */
-
- sched_lock();
- net_lock();
-
- if (conn->pollsem != NULL && conn->pollevent != NULL)
- {
- /* Wake up the poll() with POLLIN */
-
- *conn->pollevent |= POLLIN;
- nxsem_post(conn->pollsem);
- }
- else
- {
- nwarn("WARNING: Missing references in connection.\n");
- }
-
- /* Allow another poll() */
-
- conn->pollsem = NULL;
- conn->pollevent = NULL;
-
- net_unlock();
- sched_unlock();
-}
-
-/****************************************************************************
- * Name: netlink_poll
+ * Name: can_poll_local
*
* Description:
* The standard poll() operation redirects operations on socket descriptors
@@ -583,97 +562,124 @@ static void netlink_response_available(FAR void *arg)
*
****************************************************************************/
-static int netlink_poll(FAR struct socket *psock, FAR struct pollfd *fds,
- bool setup)
+static int can_poll_local(FAR struct socket *psock, FAR struct pollfd *fds,
+ bool setup)
{
- FAR struct netlink_conn_s *conn;
+ FAR struct can_conn_s *conn;
+ FAR struct can_poll_s *info;
+ FAR struct devif_callback_s *cb;
int ret = OK;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
- conn = (FAR struct netlink_conn_s *)psock->s_conn;
+ conn = (FAR struct can_conn_s *)psock->s_conn;
+ info = conn->pollinfo;
+
+ /* FIXME add NETDEV_DOWN support */
/* Check if we are setting up or tearing down the poll */
if (setup)
{
- /* If POLLOUT is selected, return immediately (maybe) */
+ net_lock();
+
+ info->dev = conn->dev;
+
+ cb = can_callback_alloc(info->dev, conn);
+ if (cb == NULL)
+ {
+ ret = -EBUSY;
+ goto errout_with_lock;
+ }
+
+ /* Initialize the poll info container */
- pollevent_t revents = POLLOUT;
+ info->psock = psock;
+ info->fds = fds;
+ info->cb = cb;
- /* If POLLIN is selected and a response is available, return
- * immediately (maybe).
+ /* Initialize the callback structure. Save the reference to the info
+ * structure as callback private data so that it will be available
+ * during callback processing.
*/
- net_lock();
- if (netlink_check_response(conn))
+ cb->flags = NETDEV_DOWN;
+ cb->priv = (FAR void *)info;
+ cb->event = can_poll_eventhandler;
+
+ if ((fds->events & POLLOUT) != 0)
+ {
+ cb->flags |= CAN_POLL;
+ }
+
+ if ((fds->events & POLLIN) != 0)
{
- revents |= POLLIN;
+ cb->flags |= CAN_NEWDATA;
}
- /* But return ONLY if POLLIN and/or POLLIN are included in the
- * requested event set.
+ /* Save the reference in the poll info structure as fds private as well
+ * for use during poll teardown as well.
*/
- revents &= fds->events;
- if (revents != 0)
+ fds->priv = (FAR void *)info;
+
+ /* Check for read data availability now */
+
+ if (!IOB_QEMPTY(&conn->readahead))
{
- fds->revents = revents;
- nxsem_post(fds->sem);
- net_unlock();
- return OK;
+ /* Normal data may be read without blocking. */
+
+ fds->revents |= (POLLRDNORM & fds->events);
}
- /* Set up to be notified when a response is available if POLLIN is
- * requested.
- */
+ #if 0
+ if (psock_udp_cansend(psock) >= 0)
+ {
+ /* Normal data may be sent without blocking (at least one byte). */
- if ((fds->events & POLLIN) != 0)
+ fds->revents |= (POLLWRNORM & fds->events);
+ }
+ #endif
+
+ /* Check if any requested events are already in effect */
+
+ if (fds->revents != 0)
{
- /* Some limitations: There can be only a single outstanding POLLIN
- * on the Netlink connection.
- */
-
- if (conn->pollsem != NULL || conn->pollevent != NULL)
- {
- nerr("ERROR: Multiple polls() on socket not supported.\n");
- net_unlock();
- return -EBUSY;
- }
-
- /* Set up the notification */
-
- conn->pollsem = fds->sem;
- conn->pollevent = &fds->revents;
-
- ret = netlink_notifier_setup(netlink_response_available,
- conn, conn);
- if (ret < 0)
- {
- nerr("ERROR: netlink_notifier_setup() failed: %d\n", ret);
- conn->pollsem = NULL;
- conn->pollevent = NULL;
- }
+ /* Yes.. then signal the poll logic */
+
+ nxsem_post(fds->sem);
}
+errout_with_lock:
net_unlock();
}
else
{
- /* Cancel any response notifications */
+ info = (FAR struct can_poll_s *)fds->priv;
- ret = netlink_notifier_teardown(conn);
- conn->pollsem = NULL;
- conn->pollevent = NULL;
+ if (info != NULL)
+ {
+ /* Cancel any response notifications */
+
+ can_callback_free(info->dev, conn, info->cb);
+
+ /* Release the poll/select data slot */
+
+ info->fds->priv = NULL;
+
+ /* Then free the poll info container */
+
+ info->psock = NULL;
+ }
}
return ret;
}
/****************************************************************************
- * Name: netlink_send
+ * Name: can_send
*
* Description:
- * The netlink_send() call may be used only when the socket is in
+ * The can_send() call may be used only when the socket is in
* a connected state (so that the intended recipient is known).
*
* Input Parameters:
@@ -689,34 +695,33 @@ static int netlink_poll(FAR struct socket *psock, FAR struct pollfd *fds,
*
****************************************************************************/
-static ssize_t netlink_send(FAR struct socket *psock, FAR const void *buf,
- size_t len, int flags)
+static ssize_t can_send(FAR struct socket *psock, FAR const void *buf,
+ size_t len, int flags)
{
- FAR struct netlink_conn_s *conn;
- struct sockaddr_nl nladdr;
-
- DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL);
-
- /* Get the underlying connection structure */
+ ssize_t ret;
- conn = (FAR struct netlink_conn_s *)psock->s_conn;
+ /* Only SOCK_RAW is supported */
- /* Format the address */
+ if (psock->s_type == SOCK_RAW)
+ {
+ /* Raw packet send */
- nladdr.nl_family = AF_NETLINK;
- nladdr.nl_pad = 0;
- nladdr.nl_pid = conn->dst_pid;
- nladdr.nl_groups = conn->dst_groups;
+ ret = psock_can_send(psock, buf, len);
+ }
+ else
+ {
+ /* EDESTADDRREQ. Signifies that the socket is not connection-mode and
+ * no peer address is set.
+ */
- /* Then let sendto() perform the actual send operation */
+ ret = -EDESTADDRREQ;
+ }
- return netlink_sendto(psock, buf, len, flags,
- (FAR const struct sockaddr *)&nladdr,
- sizeof(struct sockaddr_nl));
+ return ret;
}
/****************************************************************************
- * Name: netlink_sendto
+ * Name: can_sendto
*
* Description:
* If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET)
@@ -725,7 +730,8 @@ static ssize_t netlink_send(FAR struct socket *psock, FAR const void *buf,
* returned when the socket was not actually connected.
*
* Input Parameters:
- * psock A reference to the structure of the socket to be connected
+ * psock A reference to the socket structure of the socket
+ * to be connected
* buf Data to send
* len Length of data to send
* flags Send flags (ignored)
@@ -739,119 +745,60 @@ static ssize_t netlink_send(FAR struct socket *psock, FAR const void *buf,
*
****************************************************************************/
-static ssize_t netlink_sendto(FAR struct socket *psock, FAR const void *buf,
- size_t len, int flags,
- FAR const struct sockaddr *to, socklen_t tolen)
+static ssize_t can_sendto(FAR struct socket *psock, FAR const void *buf,
+ size_t len, int flags,
+ FAR const struct sockaddr *to, socklen_t tolen)
{
- FAR struct netlink_conn_s *conn;
- FAR struct nlmsghdr *nlmsg;
- int ret;
-
- DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL &&
- to != NULL && tolen >= sizeof(struct sockaddr_nl));
-
- conn = (FAR struct netlink_conn_s *)psock->s_conn;
-
- /* Get a reference to the netlink message */
-
- nlmsg = (FAR struct nlmsghdr *)buf;
- DEBUGASSERT(nlmsg->nlmsg_len >= sizeof(struct nlmsghdr));
-
- switch (conn->protocol)
- {
-#ifdef CONFIG_NETLINK_ROUTE
- case NETLINK_ROUTE:
- ret = netlink_route_sendto(conn, nlmsg, len, flags,
- (FAR struct sockaddr_nl *)to,
- tolen);
- break;
-#endif
-
- default:
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
+ nerr("ERROR: sendto() not supported for raw packet sockets\n");
+ return -EAFNOSUPPORT;
}
/****************************************************************************
- * Name: netlink_recvfrom
+ * Name: can_sendmsg
*
* Description:
- * recvfrom() receives messages from a socket, and may be used to receive
- * data on a socket whether or not it is connection-oriented.
- *
- * If from is not NULL, and the underlying protocol provides the source
- * address, this source address is filled in. The argument 'fromlen'
- * initialized to the size of the buffer associated with from, and modified
- * on return to indicate the actual size of the address stored there.
+ * The can_sendmsg() send a CAN frame to psock
*
* Input Parameters:
- * psock A pointer to a NuttX-specific, internal socket structure
- * buf Buffer to receive data
- * len Length of buffer
- * flags Receive flags (ignored)
- * from Address of source (may be NULL)
- * fromlen The length of the address structure
+ * psock - An instance of the internal socket structure.
+ * msg - CAN frame and optional CMSG
+ * flags - Send flags (ignored)
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. On error, a negated
+ * errno value is returned (see send() for the list of appropriate error
+ * values.
*
****************************************************************************/
-
-static ssize_t netlink_recvfrom(FAR struct socket *psock, FAR void *buf,
- size_t len, int flags,
- FAR struct sockaddr *from,
- FAR socklen_t *fromlen)
+#ifdef CONFIG_NET_CMSG
+static ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+ int flags)
{
- FAR struct netlink_response_s *entry;
-
- DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL);
- DEBUGASSERT(from == NULL ||
- (fromlen != NULL && *fromlen >= sizeof(struct sockaddr_nl)));
+ ssize_t ret;
- /* Find the response to this message. The return value */
+ /* Only SOCK_RAW is supported */
- entry = netlink_tryget_response(psock->s_conn);
- if (entry == NULL)
+ if (psock->s_type == SOCK_RAW)
{
- /* No response is variable, but presumably, one is expected. Check
- * if the socket has been configured for non-blocking operation.
- */
+ /* Raw packet send */
- if (_SS_ISNONBLOCK(psock->s_flags) || (flags & MSG_DONTWAIT) != 0)
- {
- return -EAGAIN;
- }
-
- /* Wait for the response. This should always succeed. */
-
- entry = netlink_get_response(psock->s_conn);
- DEBUGASSERT(entry != NULL);
- if (entry == NULL)
- {
- return -EPIPE;
- }
+ ret = psock_can_sendmsg(psock, msg);
}
-
- if (len > entry->msg.nlmsg_len)
+ else
{
- len = entry->msg.nlmsg_len;
- }
-
- /* Copy the payload to the user buffer */
-
- memcpy(buf, &entry->msg, len);
- kmm_free(entry);
+ /* EDESTADDRREQ. Signifies that the socket is not connection-mode and
+ * no peer address is set.
+ */
- if (from != NULL)
- {
- netlink_getpeername(psock, from, fromlen);
+ ret = -EDESTADDRREQ;
}
- return len;
+ return ret;
}
+#endif
/****************************************************************************
- * Name: netlink_close
+ * Name: can_close
*
* Description:
* Performs the close operation on a NetLink socket instance
@@ -866,12 +813,12 @@ static ssize_t netlink_recvfrom(FAR struct socket *psock, FAR void *buf,
*
****************************************************************************/
-static int netlink_close(FAR struct socket *psock)
+static int can_close(FAR struct socket *psock)
{
- FAR struct netlink_conn_s *conn = psock->s_conn;
+ FAR struct can_conn_s *conn = psock->s_conn;
int ret = OK;
- /* Perform some pre-close operations for the NETLINK socket type. */
+ /* Perform some pre-close operations for the CAN socket type. */
/* Is this the last reference to the connection structure (there
* could be more if the socket was dup'ed).
@@ -879,16 +826,20 @@ static int netlink_close(FAR struct socket *psock)
if (conn->crefs <= 1)
{
+ /* Yes... inform user-space daemon of socket close. */
+
+#warning Missing logic
+
/* Free the connection structure */
conn->crefs = 0;
- netlink_free(psock->s_conn);
+ can_free(psock->s_conn);
if (ret < 0)
{
/* Return with error code, but free resources. */
- nerr("ERROR: netlink_close failed: %d\n", ret);
+ nerr("ERROR: can_close failed: %d\n", ret);
return ret;
}
}
@@ -902,4 +853,4 @@ static int netlink_close(FAR struct socket *psock)
return ret;
}
-#endif /* CONFIG_NET_NETLINK */
+#endif /* CONFIG_NET_CAN */
diff --git a/net/devif/Make.defs b/net/devif/Make.defs
index 714a0ce..492c7d8 100644
--- a/net/devif/Make.defs
+++ b/net/devif/Make.defs
@@ -66,6 +66,10 @@ ifeq ($(CONFIG_NET_PKT),y)
NET_CSRCS += devif_pktsend.c
endif
+ifeq ($(CONFIG_NET_CAN),y)
+NET_CSRCS += devif_cansend.c
+endif
+
# Include network device interface build support
DEPPATH += --dep-path devif
diff --git a/net/devif/devif.h b/net/devif/devif.h
index cbe1a00..1a95011 100644
--- a/net/devif/devif.h
+++ b/net/devif/devif.h
@@ -68,31 +68,32 @@
*
* TCP_ACKDATA IN: Signifies that the outstanding data was ACKed and
* the socket layer should send out new data instead
- * of retransmitting the last data (TCP only)
+ * of retransmitting the last data. (TCP only)
* OUT: Input state must be preserved on output.
*
* TCP_NEWDATA IN: Set to indicate that the peer has sent us new data.
- * UDP_NEWDATA OUT: Cleared (only) by the socket layer logic to indicate
- * ICMP_NEWDATA that the new data was consumed, suppressing further
- * ICMPv6_NEWDATA attempts to process the new data.
- * PKT_NEWDATA
+ * UDP_NEWDATA OUT: Cleared (only) by the socket layer logic to
+ * ICMP_NEWDATA indicate that the new data was consumed,
+ * ICMPv6_NEWDATA suppressing further attempts to process the new
+ * PKT_NEWDATA data.
* BLUETOOTH_NEWDATA
* IEEE802154_NEWDATA
*
* TCP_SNDACK IN: Not used; always zero
- * OUT: Set by the socket layer if the new data was consumed
- * and an ACK should be sent in the response. (TCP only)
+ * OUT: Set by the socket layer if the new data was
+ * consumed and an ACK should be sent in the response.
+ * (TCP only)
*
* TCP_REXMIT IN: Tells the socket layer to retransmit the data that
* was last sent. (TCP only)
* OUT: Not used
*
- * TCP_POLL IN: Used for polling the socket layer. This is provided
- * UDP_POLL periodically from the drivers to support (1) timed
- * PKT_POLL operations, and (2) to check if the socket layer has
- * BLUETOOTH_POLL data that it wants to send. These are socket oriented
- * IEEE802154_POLL callbacks where the context depends on the specific
- * set
+ * TCP_POLL IN: Used for polling the socket layer. This is
+ * UDP_POLL provided periodically from the drivers to support
+ * PKT_POLL (1) timed operations, and (2) to check if the
+ * BLUETOOTH_POLL socket layer has data that it wants to send.
+ * IEEE802154_POLL These are socket oriented callbacks where the
+ * context depends on the specific set.
* OUT: Not used
*
* TCP_BACKLOG IN: There is a new connection in the backlog list set
@@ -104,14 +105,15 @@
* OUT: The socket layer signals that it wants to close the
* connection. (TCP only)
*
- * TCP_ABORT IN: The remote host has aborted the connection, thus the
- * connection has gone away. (TCP only)
+ * TCP_ABORT IN: The remote host has aborted the connection, thus
+ * the connection has gone away. (TCP only)
* OUT: The socket layer signals that it wants to abort the
* connection. (TCP only)
*
- * TCP_CONNECTED IN: We have got a connection from a remote host and have
- * set up a new connection for it, or an active connection
- * has been successfully established. (TCP only)
+ * TCP_CONNECTED IN: We have got a connection from a remote host and
+ * have set up a new connection for it, or an active
+ * connection has been successfully established.
+ * (TCP only)
* OUT: Not used
*
* TCP_TIMEDOUT IN: The connection has been aborted due to too many
@@ -121,37 +123,38 @@
* Device Specific Events: These are events that may be notified through
* callback lists residing in the network device structure.
*
- * ARP_POLL IN: Used for polling the socket layer. This is provided
- * periodically from the drivers to support (1) timed
- * operations, and (2) to check if the ARP layer needs
- * to send an ARP request. This is a device oriented
- * event, not associated with a socket.
+ * ARP_POLL IN: Used for polling the socket layer. This is
+ * provided periodically from the drivers to support
+ * (1) timed operations, and (2) to check if the ARP
+ * layer needs to send an ARP request. This is a
+ * device oriented event, not associated with a
+ * socket.
* OUT: Not used
*
- * ICMP_POLL IN: Used for polling the socket layer. This is provided
- * periodically from the drivers to support (1) timed
- * operations, and (2) to check if the ICMP layer needs
- * to send an ARP request. This is a device oriented
- * event, not associated with a socket. This differs
- * from ICMPv6_POLL only in that the appdata pointer
- * is set differently
+ * ICMP_POLL IN: Used for polling the socket layer. This is
+ * provided periodically from the drivers to support
+ * (1) timed operations, and (2) to check if the ICMP
+ * layer needs to send an ARP request. This is a
+ * device oriented event, not associated with a
+ * socket. This differs from ICMPv6_POLL only in that
+ * the appdata pointer is set differently.
* OUT: Not used
*
- * ICMPv6_POLL IN: Used for polling the socket layer. This is provided
- * periodically from the drivers to support (1) timed
- * operations, and (2) to check if the ICMP layer needs
- * to send an ARP request. This is a device oriented
- * event, not associated with a socket. This differs
- * from ICMP_POLL only in that the appdata pointer
- * is set differently
+ * ICMPv6_POLL IN: Used for polling the socket layer. This is
+ * provided periodically from the drivers to support
+ * (1) timed operations, and (2) to check if the ICMP
+ * layer needs to send an ARP request. This is a
+ * device oriented event, not associated with a
+ * socket. This differs from ICMP_POLL only in that
+ * the appdata pointer is set differently.
* OUT: Not used
*
* IPFWD_POLL IN: Used for polling for forwarded packets layer. This
- * is provided periodically from the drivers to support
- * to check if there is a packet waiting to be forward
- * on the device. This is a device oriented event,
- * not associated with a socket. The appdata pointer
- * The appdata pointer is not used in this case.
+ * is provided periodically from the drivers to
+ * support to check if there is a packet waiting to be
+ * forward on the device. This is a device oriented
+ * event, not associated with a socket. The appdata
+ * pointer is not used in this case.
* OUT: Not used
*
* NETDEV_DOWN: IN: The network device has been taken down.
@@ -168,6 +171,7 @@
#define BLUETOOTH_NEWDATA TCP_NEWDATA
#define IEEE802154_NEWDATA TCP_NEWDATA
#define PKT_NEWDATA TCP_NEWDATA
+#define CAN_NEWDATA TCP_NEWDATA
#define WPAN_NEWDATA TCP_NEWDATA
#define IPFWD_NEWDATA TCP_NEWDATA
#define TCP_SNDACK (1 << 2)
@@ -175,6 +179,7 @@
#define TCP_POLL (1 << 4)
#define UDP_POLL TCP_POLL
#define PKT_POLL TCP_POLL
+#define CAN_POLL TCP_POLL
#define BLUETOOTH_POLL TCP_POLL
#define IEEE802154_POLL TCP_POLL
#define WPAN_POLL TCP_POLL
@@ -492,11 +497,32 @@ void devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *buf,
*
****************************************************************************/
-#ifdef CONFIG_NET_PKT
+#if defined(CONFIG_NET_PKT)
void devif_pkt_send(FAR struct net_driver_s *dev, FAR const void *buf,
unsigned int len);
#endif
+/****************************************************************************
+ * Name: devif_can_send
+ *
+ * Description:
+ * Called from socket logic in order to send a raw packet in response to
+ * an xmit or poll request from the network interface driver.
+ *
+ * This is almost identical to calling devif_send() except that the data to
+ * be sent is copied into dev->d_buf (vs. dev->d_appdata), since there is
+ * no header on the data.
+ *
+ * Assumptions:
+ * This function must be called with the network locked.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_CAN)
+void devif_can_send(FAR struct net_driver_s *dev, FAR const void *buf,
+ unsigned int len);
+#endif
+
#undef EXTERN
#ifdef __cplusplus
}
diff --git a/net/local/local_sendpacket.c b/net/devif/devif_cansend.c
similarity index 55%
copy from net/local/local_sendpacket.c
copy to net/devif/devif_cansend.c
index 68dfac6..43570f2 100644
--- a/net/local/local_sendpacket.c
+++ b/net/devif/devif_cansend.c
@@ -1,7 +1,7 @@
/****************************************************************************
- * net/local/local_sendpacket.c
+ * net/devif/devif_cansend.c
*
- * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gn...@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -39,131 +39,75 @@
#include <nuttx/config.h>
-#include <sys/types.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <errno.h>
+#include <string.h>
#include <assert.h>
#include <debug.h>
-#include <nuttx/fs/fs.h>
+#include <nuttx/net/netdev.h>
-#include "local/local.h"
-
-#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL)
+#if defined(CONFIG_NET_CAN)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
-#define LOCAL_PREAMBLE_SIZE 8
+/****************************************************************************
+ * Private Type Declarations
+ ****************************************************************************/
/****************************************************************************
- * Private Data
+ * Private Function Prototypes
****************************************************************************/
-static const uint8_t g_preamble[LOCAL_PREAMBLE_SIZE] =
-{
- LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE,
- LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE, LOCAL_SYNC_BYTE, LOCAL_END_BYTE
-};
+/****************************************************************************
+ * Public Constant Data
+ ****************************************************************************/
/****************************************************************************
- * Private Functions
+ * Public Data
****************************************************************************/
/****************************************************************************
- * Name: local_fifo_write
- *
- * Description:
- * Write a data on the write-only FIFO.
- *
- * Input Parameters:
- * filep File structure of write-only FIFO.
- * buf Data to send
- * len Length of data to send
- *
- * Returned Value:
- * Zero is returned on success; a negated errno value is returned on any
- * failure.
- *
+ * Private Constant Data
****************************************************************************/
-static int local_fifo_write(FAR struct file *filep, FAR const uint8_t *buf,
- size_t len)
-{
- ssize_t nwritten;
-
- while (len > 0)
- {
- nwritten = file_write(filep, buf, len);
- if (nwritten < 0)
- {
- if (nwritten != -EINTR)
- {
- nerr("ERROR: nx_write failed: %d\n", nwritten);
- return (int)nwritten;
- }
-
- ninfo("Ignoring signal\n");
- }
- else
- {
- DEBUGASSERT(nwritten > 0 && nwritten <= len);
- len -= nwritten;
- buf += nwritten;
- }
- }
-
- return OK;
-}
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
- * Name: local_send_packet
+ * Name: devif_can_send
*
* Description:
- * Send a packet on the write-only FIFO.
+ * Called from socket logic in order to send a can packet in response to
+ * an xmit or poll request from the network interface driver.
*
- * Input Parameters:
- * filep File structure of write-only FIFO.
- * buf Data to send
- * len Length of data to send
+ * This is almost identical to calling devif_send() except that the data to
+ * be sent is copied into dev->d_buf (vs. dev->d_appdata), since there is
+ * no header on the data.
*
- * Returned Value:
- * Zero is returned on success; a negated errno value is returned on any
- * failure.
+ * Assumptions:
+ * Called with the network locked.
*
****************************************************************************/
-int local_send_packet(FAR struct file *filep, FAR const uint8_t *buf,
- size_t len)
+void devif_can_send(FAR struct net_driver_s *dev, FAR const void *buf,
+ unsigned int len)
{
- uint16_t len16;
- int ret;
-
- /* Send the packet preamble */
+ DEBUGASSERT(dev && len > 0 && len < NETDEV_PKTSIZE(dev));
- ret = local_fifo_write(filep, g_preamble, LOCAL_PREAMBLE_SIZE);
- if (ret == OK)
- {
- /* Send the packet length */
+ /* Copy the data into the device packet buffer */
- len16 = len;
- ret = local_fifo_write(filep, (FAR const uint8_t *)&len16,
- sizeof(uint16_t));
- if (ret == OK)
- {
- /* Send the packet data */
+ memcpy(dev->d_buf, buf, len);
- ret = local_fifo_write(filep, buf, len);
- }
- }
+ /* Set the number of bytes to send */
- return ret;
+ dev->d_len = len;
+ dev->d_sndlen = len;
}
-#endif /* CONFIG_NET && CONFIG_NET_LOCAL */
+#endif /* CONFIG_NET_CAN */
diff --git a/net/devif/devif_poll.c b/net/devif/devif_poll.c
index 7c4fd04..ffffed4 100644
--- a/net/devif/devif_poll.c
+++ b/net/devif/devif_poll.c
@@ -50,6 +50,7 @@
#include "devif/devif.h"
#include "arp/arp.h"
+#include "can/can.h"
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "pkt/pkt.h"
@@ -233,6 +234,44 @@ static int devif_poll_pkt_connections(FAR struct net_driver_s *dev,
#endif /* CONFIG_NET_PKT */
/****************************************************************************
+ * Name: devif_poll_pkt_connections
+ *
+ * Description:
+ * Poll all packet connections for available packets to send.
+ *
+ * Assumptions:
+ * This function is called from the MAC device driver with the network
+ * locked.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_CAN
+static int devif_poll_can_connections(FAR struct net_driver_s *dev,
+ devif_poll_callback_t callback)
+{
+ FAR struct can_conn_s *can_conn = NULL;
+ int bstop = 0;
+
+ /* Traverse all of the allocated packet connections and
+ * perform the poll action
+ */
+
+ while (!bstop && (can_conn = can_nextconn(can_conn)))
+ {
+ /* Perform the packet TX poll */
+
+ can_poll(dev, can_conn);
+
+ /* Call back into the driver */
+
+ bstop = callback(dev);
+ }
+
+ return bstop;
+}
+#endif /* CONFIG_NET_PKT */
+
+/****************************************************************************
* Name: devif_poll_bluetooth_connections
*
* Description:
@@ -646,6 +685,15 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback)
if (!bstop)
#endif
+#ifdef CONFIG_NET_CAN
+ {
+ /* Check for pending packet socket transfer */
+
+ bstop = devif_poll_can_connections(dev, callback);
+ }
+
+ if (!bstop)
+#endif
#ifdef CONFIG_NET_BLUETOOTH
{
/* Check for pending PF_BLUETOOTH socket transfer */
diff --git a/net/icmp/icmp_sockif.c b/net/icmp/icmp_sockif.c
index 983eb71..2b1e179 100644
--- a/net/icmp/icmp_sockif.c
+++ b/net/icmp/icmp_sockif.c
@@ -102,6 +102,10 @@ const struct sock_intf_s g_icmp_sockif =
NULL, /* si_sendfile */
#endif
icmp_recvfrom, /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+ NULL, /* si_recvmsg */
+ NULL, /* si_sendmsg */
+#endif
icmp_close /* si_close */
};
@@ -280,7 +284,8 @@ static int icmp_connect(FAR struct socket *psock,
* Input Parameters:
* psock Reference to the listening socket structure
* addr Receives the address of the connecting client
- * addrlen Input: allocated size of 'addr', Return: returned size of 'addr'
+ * addrlen Input: allocated size of 'addr',
+ * Return: returned size of 'addr'
* newsock Location to return the accepted socket information.
*
* Returned Value:
@@ -318,7 +323,8 @@ static int icmp_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
*
****************************************************************************/
-static int icmp_bind(FAR struct socket *psock, FAR const struct sockaddr *addr,
+static int icmp_bind(FAR struct socket *psock,
+ FAR const struct sockaddr *addr,
socklen_t addrlen)
{
/* An ICMP socket cannot be bound to a local address */
@@ -364,10 +370,10 @@ static int icmp_getsockname(FAR struct socket *psock,
* Name: icmp_getpeername
*
* Description:
- * The icmp_getpeername() function retrieves the remote-connected name of the
- * specified packet socket, stores this address in the sockaddr structure
- * pointed to by the 'addr' argument, and stores the length of this
- * address in the object pointed to by the 'addrlen' argument.
+ * The icmp_getpeername() function retrieves the remote-connected name of
+ * the specified packet socket, stores this address in the sockaddr
+ * structure pointed to by the 'addr' argument, and stores the length of
+ * this address in the object pointed to by the 'addrlen' argument.
*
* If the actual length of the address is greater than the length of the
* supplied sockaddr structure, the stored address will be truncated.
diff --git a/net/icmpv6/icmpv6_sockif.c b/net/icmpv6/icmpv6_sockif.c
index c99d184..3dbb5c8 100644
--- a/net/icmpv6/icmpv6_sockif.c
+++ b/net/icmpv6/icmpv6_sockif.c
@@ -102,6 +102,10 @@ const struct sock_intf_s g_icmpv6_sockif =
NULL, /* si_sendfile */
#endif
icmpv6_recvfrom, /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+ NULL, /* si_recvmsg */
+ NULL, /* si_sendmsg */
+#endif
icmpv6_close /* si_close */
};
@@ -280,7 +284,8 @@ static int icmpv6_connect(FAR struct socket *psock,
* Input Parameters:
* psock Reference to the listening socket structure
* addr Receives the address of the connecting client
- * addrlen Input: allocated size of 'addr', Return: returned size of 'addr'
+ * addrlen Input: allocated size of 'addr',
+ * Return: returned size of 'addr'
* newsock Location to return the accepted socket information.
*
* Returned Value:
@@ -318,8 +323,9 @@ static int icmpv6_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
*
****************************************************************************/
-static int icmpv6_bind(FAR struct socket *psock, FAR const struct sockaddr *addr,
- socklen_t addrlen)
+static int icmpv6_bind(FAR struct socket *psock,
+ FAR const struct sockaddr *addr,
+ socklen_t addrlen)
{
/* An ICMPv6 socket cannot be bound to a local address */
@@ -330,10 +336,10 @@ static int icmpv6_bind(FAR struct socket *psock, FAR const struct sockaddr *addr
* Name: icmpv6_getsockname
*
* Description:
- * The icmpv6_getsockname() function retrieves the locally-bound name of the
- * specified packet socket, stores this address in the sockaddr structure
- * pointed to by the 'addr' argument, and stores the length of this
- * address in the object pointed to by the 'addrlen' argument.
+ * The icmpv6_getsockname() function retrieves the locally-bound name of
+ * the specified packet socket, stores this address in the sockaddr
+ * structure pointed to by the 'addr' argument, and stores the length of
+ * this address in the object pointed to by the 'addrlen' argument.
*
* If the actual length of the address is greater than the length of the
* supplied sockaddr structure, the stored address will be truncated.
@@ -364,10 +370,10 @@ static int icmpv6_getsockname(FAR struct socket *psock,
* Name: icmpv6_getpeername
*
* Description:
- * The icmpv6_getpeername() function retrieves the remote-connected name of the
- * specified packet socket, stores this address in the sockaddr structure
- * pointed to by the 'addr' argument, and stores the length of this
- * address in the object pointed to by the 'addrlen' argument.
+ * The icmpv6_getpeername() function retrieves the remote-connected name of
+ * the specified packet socket, stores this address in the sockaddr
+ * structure pointed to by the 'addr' argument, and stores the length of
+ * this address in the object pointed to by the 'addrlen' argument.
*
* If the actual length of the address is greater than the length of the
* supplied sockaddr structure, the stored address will be truncated.
@@ -483,8 +489,8 @@ static int icmpv6_netpoll(FAR struct socket *psock, FAR struct pollfd *fds,
static ssize_t icmpv6_send(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags)
{
- /* ICMPv6 sockets cannot be bound and, hence, cannot support any connection-
- * oriented data transfer.
+ /* ICMPv6 sockets cannot be bound and, hence, cannot support any
+ * connection-oriented data transfer.
*/
return -EDESTADDRREQ;
diff --git a/net/ieee802154/ieee802154_sockif.c b/net/ieee802154/ieee802154_sockif.c
index 216264a..eb5d6e5 100644
--- a/net/ieee802154/ieee802154_sockif.c
+++ b/net/ieee802154/ieee802154_sockif.c
@@ -107,6 +107,10 @@ const struct sock_intf_s g_ieee802154_sockif =
NULL, /* si_sendfile */
#endif
ieee802154_recvfrom, /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+ NULL, /* si_recvmsg */
+ NULL, /* si_sendmsg */
+#endif
ieee802154_close /* si_close */
};
@@ -241,10 +245,10 @@ static void ieee802154_addref(FAR struct socket *psock)
* Name: ieee802154_connect
*
* Description:
- * ieee802154_connect() connects the local socket referred to by the structure
- * 'psock' to the address specified by 'addr'. The addrlen argument
- * specifies the size of 'addr'. The format of the address in 'addr' is
- * determined by the address space of the socket 'psock'.
+ * ieee802154_connect() connects the local socket referred to by the
+ * structure 'psock' to the address specified by 'addr'. The addrlen
+ * argument specifies the size of 'addr'. The format of the address in
+ * 'addr' is determined by the address space of the socket 'psock'.
*
* If the socket 'psock' is of type SOCK_DGRAM then 'addr' is the address
* to which datagrams are sent by default, and the only address from which
@@ -307,8 +311,8 @@ static int ieee802154_connect(FAR struct socket *psock,
* Name: ieee802154_accept
*
* Description:
- * The ieee802154_accept function is used with connection-based socket types
- * (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first
+ * The ieee802154_accept function is used with connection-based socket
+ * types (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first
* connection request on the queue of pending connections, creates a new
* connected socket with mostly the same properties as 'sockfd', and
* allocates a new socket descriptor for the socket, which is returned. The
@@ -334,7 +338,8 @@ static int ieee802154_connect(FAR struct socket *psock,
* Input Parameters:
* psock Reference to the listening socket structure
* addr Receives the address of the connecting client
- * addrlen Input: allocated size of 'addr', Return: returned size of 'addr'
+ * addrlen Input: allocated size of 'addr',
+ * Return: returned size of 'addr'
* newsock Location to return the accepted socket information.
*
* Returned Value:
@@ -376,7 +381,8 @@ static int ieee802154_accept(FAR struct socket *psock,
****************************************************************************/
static int ieee802154_bind(FAR struct socket *psock,
- FAR const struct sockaddr *addr, socklen_t addrlen)
+ FAR const struct sockaddr *addr,
+ socklen_t addrlen)
{
FAR const struct sockaddr_ieee802154_s *iaddr;
FAR struct radio_driver_s *radio;
@@ -446,10 +452,10 @@ static int ieee802154_bind(FAR struct socket *psock,
* Name: ieee802154_getsockname
*
* Description:
- * The ieee802154_getsockname() function retrieves the locally-bound name of the
- * specified packet socket, stores this address in the sockaddr structure
- * pointed to by the 'addr' argument, and stores the length of this
- * address in the object pointed to by the 'addrlen' argument.
+ * The ieee802154_getsockname() function retrieves the locally-bound name
+ * of the specified packet socket, stores this address in the sockaddr
+ * structure pointed to by the 'addr' argument, and stores the length of
+ * this address in the object pointed to by the 'addrlen' argument.
*
* If the actual length of the address is greater than the length of the
* supplied sockaddr structure, the stored address will be truncated.
@@ -508,10 +514,10 @@ static int ieee802154_getsockname(FAR struct socket *psock,
* Name: ieee802154_getpeername
*
* Description:
- * The ieee802154_getpeername() function retrieves the remote-connectd name of the
- * specified packet socket, stores this address in the sockaddr structure
- * pointed to by the 'addr' argument, and stores the length of this
- * address in the object pointed to by the 'addrlen' argument.
+ * The ieee802154_getpeername() function retrieves the remote-connectd name
+ * of the specified packet socket, stores this address in the sockaddr
+ * structure pointed to by the 'addr' argument, and stores the length of
+ * this address in the object pointed to by the 'addrlen' argument.
*
* If the actual length of the address is greater than the length of the
* supplied sockaddr structure, the stored address will be truncated.
@@ -676,7 +682,8 @@ static ssize_t ieee802154_send(FAR struct socket *psock, FAR const void *buf,
ret = psock_ieee802154_sendto(psock, buf, len, flags,
(FAR const struct sockaddr *)&to,
- sizeof(struct sockaddr_ieee802154_s));
+ sizeof(
+ struct sockaddr_ieee802154_s));
}
}
else
@@ -713,9 +720,11 @@ static ssize_t ieee802154_send(FAR struct socket *psock, FAR const void *buf,
*
****************************************************************************/
-static ssize_t ieee802154_sendto(FAR struct socket *psock, FAR const void *buf,
+static ssize_t ieee802154_sendto(FAR struct socket *psock,
+ FAR const void *buf,
size_t len, int flags,
- FAR const struct sockaddr *to, socklen_t tolen)
+ FAR const struct sockaddr *to,
+ socklen_t tolen)
{
ssize_t ret;
diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c
index 9456510..488f2d1 100644
--- a/net/inet/inet_sockif.c
+++ b/net/inet/inet_sockif.c
@@ -117,6 +117,10 @@ static const struct sock_intf_s g_inet_sockif =
inet_sendfile, /* si_sendfile */
#endif
inet_recvfrom, /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+ NULL, /* si_recvmsg */
+ NULL, /* si_sendmsg */
+#endif
inet_close /* si_close */
};
diff --git a/net/local/local_sendpacket.c b/net/local/local_sendpacket.c
index 68dfac6..644dd31 100644
--- a/net/local/local_sendpacket.c
+++ b/net/local/local_sendpacket.c
@@ -47,6 +47,7 @@
#include <debug.h>
#include <nuttx/fs/fs.h>
+#include "devif/devif.h"
#include "local/local.h"
diff --git a/net/local/local_sockif.c b/net/local/local_sockif.c
index f2bbcb1..c4f7531 100644
--- a/net/local/local_sockif.c
+++ b/net/local/local_sockif.c
@@ -110,6 +110,10 @@ const struct sock_intf_s g_local_sockif =
NULL, /* si_sendfile */
#endif
local_recvfrom, /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+ NULL, /* si_recvmsg */
+ NULL, /* si_sendmsg */
+#endif
local_close /* si_close */
};
@@ -161,7 +165,8 @@ static int local_sockif_alloc(FAR struct socket *psock)
* specific socket fields.
*
* Input Parameters:
- * psock A pointer to a user allocated socket structure to be initialized.
+ * psock A pointer to a user allocated socket structure
+ * to be initialized.
* protocol (see sys/socket.h)
*
* Returned Value:
@@ -590,7 +595,8 @@ static int local_connect(FAR struct socket *psock,
* Input Parameters:
* psock Reference to the listening socket structure
* addr Receives the address of the connecting client
- * addrlen Input: allocated size of 'addr', Return: returned size of 'addr'
+ * addrlen Input: allocated size of 'addr',
+ * Return: returned size of 'addr'
* newsock Location to return the accepted socket information.
*
* Returned Value:
@@ -717,7 +723,7 @@ static ssize_t local_send(FAR struct socket *psock, FAR const void *buf,
* Name: local_sendto
*
* Description:
- * Implements the sendto() operation for the case of the local, Unix socket.
+ * Implements the sendto() operation for the case of the local Unix socket.
*
* Input Parameters:
* psock A pointer to a NuttX-specific, internal socket structure
diff --git a/net/net_initialize.c b/net/net_initialize.c
index eb82777..bedc4e3 100644
--- a/net/net_initialize.c
+++ b/net/net_initialize.c
@@ -59,6 +59,7 @@
#include "bluetooth/bluetooth.h"
#include "ieee802154/ieee802154.h"
#include "local/local.h"
+#include "can/can.h"
#include "netlink/netlink.h"
#include "igmp/igmp.h"
#include "route/route.h"
@@ -158,6 +159,12 @@ void net_initialize(void)
local_initialize();
#endif
+#ifdef CONFIG_NET_CAN
+ /* Initialize SocketCAN support */
+
+ can_initialize();
+#endif
+
#ifdef CONFIG_NET_NETLINK
/* Initialize the Netlink IPC support */
diff --git a/net/netdev/Kconfig b/net/netdev/Kconfig
index 2b3f905..ce51c1f 100644
--- a/net/netdev/Kconfig
+++ b/net/netdev/Kconfig
@@ -16,6 +16,14 @@ config NETDEV_PHY_IOCTL
---help---
Enable support for ioctl() commands to access PHY registers
+config NETDEV_CAN_BITRATE_IOCTL
+ bool "Enable CAN bitrate ioctl()"
+ default n
+ select NETDEV_IOCTL
+ depends on NET_CAN
+ ---help---
+ Enable support for ioctl() commands to change CAN bitrate
+
config NETDEV_WIRELESS_IOCTL
bool "Enable Wireless ioctl()"
default n
diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c
index 04c9b51..c169503 100644
--- a/net/netdev/netdev_ioctl.c
+++ b/net/netdev/netdev_ioctl.c
@@ -1088,6 +1088,54 @@ static int netdev_ifr_ioctl(FAR struct socket *psock, int cmd,
}
}
break;
+#endif
+
+#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_NETDEV_CAN_BITRATE_IOCTL)
+ case SIOCGCANBITRATE: /* Get bitrate from a CAN controller */
+ case SIOCSCANBITRATE: /* Set bitrate of a CAN controller */
+ {
+ dev = netdev_ifr_dev(req);
+ if (dev && dev->d_ioctl)
+ {
+ struct can_ioctl_data_s *can_bitrate_data =
+ &req->ifr_ifru.ifru_can_data;
+ ret = dev->d_ioctl(dev, cmd,
+ (unsigned long)(uintptr_t)can_bitrate_data);
+ }
+ }
+ break;
+#endif
+
+#ifdef CONFIG_NETDEV_IFINDEX
+ case SIOCGIFNAME: /* Get interface name */
+ {
+ struct net_driver_s *dev = netdev_findbyindex(req->ifr_ifindex);
+ if (dev != NULL)
+ {
+ strncpy(req->ifr_name, dev->d_ifname, IFNAMSIZ);
+ ret = OK;
+ }
+ else
+ {
+ ret = -ENODEV;
+ }
+ }
+ break;
+
+ case SIOCGIFINDEX: /* Index to name mapping */
+ {
+ struct net_driver_s *dev = netdev_findbyname(req->ifr_name);
+ if (dev != NULL)
+ {
+ req->ifr_ifindex = dev->d_ifindex;
+ ret = OK;
+ }
+ else
+ {
+ ret = -ENODEV;
+ }
+ }
+ break;
#endif
default:
diff --git a/net/netdev/netdev_register.c b/net/netdev/netdev_register.c
index 4b08efa..3694db5 100644
--- a/net/netdev/netdev_register.c
+++ b/net/netdev/netdev_register.c
@@ -37,6 +37,7 @@
#include <nuttx/net/netdev.h>
#include <nuttx/net/ethernet.h>
#include <nuttx/net/bluetooth.h>
+#include <nuttx/net/can.h>
#include "utils/utils.h"
#include "igmp/igmp.h"
@@ -56,6 +57,7 @@
#define NETDEV_WLAN_FORMAT "wlan%d"
#define NETDEV_WPAN_FORMAT "wpan%d"
#define NETDEV_WWAN_FORMAT "wwan%d"
+#define NETDEV_CAN_FORMAT "can%d"
#if defined(CONFIG_DRIVERS_IEEE80211) /* Usually also has CONFIG_NET_ETHERNET */
# define NETDEV_DEFAULT_FORMAT NETDEV_WLAN_FORMAT
@@ -67,6 +69,8 @@
# define NETDEV_DEFAULT_FORMAT NETDEV_SLIP_FORMAT
#elif defined(CONFIG_NET_TUN)
# define NETDEV_DEFAULT_FORMAT NETDEV_TUN_FORMAT
+#elif defined(CONFIG_NET_CAN)
+# define NETDEV_DEFAULT_FORMAT NETDEV_CAN_FORMAT
#else /* if defined(CONFIG_NET_LOOPBACK) */
# define NETDEV_DEFAULT_FORMAT NETDEV_LO_FORMAT
#endif
@@ -277,6 +281,14 @@ int netdev_register(FAR struct net_driver_s *dev, enum net_lltype_e lltype)
break;
#endif
+#ifdef CONFIG_NET_CAN
+ case NET_LL_CAN: /* CAN bus */
+ dev->d_llhdrlen = 0;
+ dev->d_pktsize = NET_CAN_PKTSIZE;
+ devfmt = NETDEV_CAN_FORMAT;
+ break;
+#endif
+
#ifdef CONFIG_NET_BLUETOOTH
case NET_LL_BLUETOOTH: /* Bluetooth */
llhdrlen = BLUETOOTH_MAX_HDRLEN; /* Determined at runtime */
diff --git a/net/netlink/netlink_sockif.c b/net/netlink/netlink_sockif.c
index 577d520..34b011a 100644
--- a/net/netlink/netlink_sockif.c
+++ b/net/netlink/netlink_sockif.c
@@ -111,6 +111,10 @@ const struct sock_intf_s g_netlink_sockif =
NULL, /* si_sendfile */
#endif
netlink_recvfrom, /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+ NULL, /* si_recvmsg */
+ NULL, /* si_sendmsg */
+#endif
netlink_close /* si_close */
};
diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c
index e189ddc..dbf3e3c 100644
--- a/net/pkt/pkt_sockif.c
+++ b/net/pkt/pkt_sockif.c
@@ -108,6 +108,10 @@ const struct sock_intf_s g_pkt_sockif =
NULL, /* si_sendfile */
#endif
pkt_recvfrom, /* si_recvfrom */
+#ifdef CONFIG_NET_CMSG
+ NULL, /* si_recvmsg */
+ NULL, /* si_sendmsg */
+#endif
pkt_close /* si_close */
};
diff --git a/net/socket/Kconfig b/net/socket/Kconfig
index c627ea5..f13e22d 100644
--- a/net/socket/Kconfig
+++ b/net/socket/Kconfig
@@ -37,6 +37,12 @@ config NET_UDPPROTO_OPTIONS
---help---
Enable or disable support for UDP protocol level socket options.
+config NET_CANPROTO_OPTIONS
+ bool
+ default n
+ ---help---
+ Enable or disable support for CAN protocol level socket option
+
if NET_SOCKOPTS
config NET_SOLINGER
@@ -49,5 +55,23 @@ config NET_SOLINGER
Enable or disable support for the SO_LINGER socket option. Requires
write buffer support.
+config NET_TIMESTAMP
+ bool "SO_TIMESTAMP socket option"
+ default n
+ depends on NET_CAN
+ select NET_CMSG
+ ---help---
+ Enable or disable support for the SO_TIMESTAMP socket option. Currently only tested & implemented in SocketCAN but should work on all sockets
+
endif # NET_SOCKOPTS
+
+config NET_CMSG
+ bool "Control messages (CMSG) support"
+ default n
+ ---help---
+ Enable or disable support for control messages in the recvmsg() and
+ sendmsg() function. Control messages (also defined in POSIX 1003.1g
+ as ancillary data object information). Includes additional
+ information on the packet received or to be transmitted.
+
endmenu # Socket Support
diff --git a/net/socket/Make.defs b/net/socket/Make.defs
index 47fb4d2..6bf79ed 100644
--- a/net/socket/Make.defs
+++ b/net/socket/Make.defs
@@ -74,3 +74,9 @@ endif
DEPPATH += --dep-path socket
VPATH += :socket
+
+# Support for control messages (CMSG)
+ifeq ($(CONFIG_NET_CMSG),y)
+SOCK_CSRCS += recvmsg.c
+SOCK_CSRCS += sendmsg.c
+endif
diff --git a/net/socket/getsockopt.c b/net/socket/getsockopt.c
index e7474ad..581edc0 100644
--- a/net/socket/getsockopt.c
+++ b/net/socket/getsockopt.c
@@ -278,6 +278,19 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
}
break;
+#ifdef CONFIG_NET_TIMESTAMP
+ case SO_TIMESTAMP:
+ {
+ if (*value_len != sizeof(int))
+ {
+ return -EINVAL;
+ }
+
+ *(FAR int *)value = (int)psock->s_timestamp;
+ }
+ break;
+#endif
+
/* The following are not yet implemented
* (return values other than {0,1})
*/
@@ -371,6 +384,12 @@ int psock_getsockopt(FAR struct socket *psock, int level, int option,
break;
#endif
+ case SOL_CAN_RAW:/* CAN protocol socket options (see include/netpacket/can.h) */
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+ ret = can_getsockopt(psock, option, value, value_len);
+#endif
+ break;
+
/* These levels are defined in sys/socket.h, but are not yet
* implemented.
*/
diff --git a/net/socket/net_sockif.c b/net/socket/net_sockif.c
index 01e8368..cc956d8 100644
--- a/net/socket/net_sockif.c
+++ b/net/socket/net_sockif.c
@@ -47,6 +47,7 @@
#include "inet/inet.h"
#include "local/local.h"
+#include "can/can.h"
#include "netlink/netlink.h"
#include "pkt/pkt.h"
#include "bluetooth/bluetooth.h"
@@ -104,6 +105,12 @@ net_sockif(sa_family_t family, int type, int protocol)
break;
#endif
+#ifdef CONFIG_NET_CAN
+ case PF_CAN:
+ sockif = &g_can_sockif;
+ break;
+#endif
+
#ifdef CONFIG_NET_NETLINK
case PF_NETLINK:
sockif = &g_netlink_sockif;
diff --git a/net/socket/recvmsg.c b/net/socket/recvmsg.c
new file mode 100644
index 0000000..9ba5de3
--- /dev/null
+++ b/net/socket/recvmsg.c
@@ -0,0 +1,244 @@
+/****************************************************************************
+ * net/socket/recvmsg.c
+ *
+ * Copyright (C) 2007-2009, 2011-2017, 2019 Gregory Nutt. All rights
+ * reserved.
+ * Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <errno.h>
+
+#include <nuttx/cancelpt.h>
+#include <nuttx/net/net.h>
+
+#include "socket/socket.h"
+
+#ifdef CONFIG_NET_CMSG
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: psock_recvmsg
+ *
+ * Description:
+ * psock_recvfrom() receives messages from a socket, and may be used to
+ * receive data on a socket whether or not it is connection-oriented.
+ * This is an internal OS interface. It is functionally equivalent to
+ * recvfrom() except that:
+ *
+ * - It is not a cancellation point,
+ * - It does not modify the errno variable, and
+ * - I accepts the internal socket structure as an input rather than an
+ * task-specific socket descriptor.
+ *
+ * Input Parameters:
+ * psock - A pointer to a NuttX-specific, internal socket structure
+ * msg Buffer to receive msg
+ * len - Length of buffer
+ * flags - Receive flags
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. If no data is
+ * available to be received and the peer has performed an orderly shutdown,
+ * recv() will return 0. Otherwise, on any failure, a negated errno value
+ * is returned (see comments with send() for a list of appropriate errno
+ * values).
+ *
+ ****************************************************************************/
+
+ssize_t psock_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+ int flags)
+{
+ /* Verify that non-NULL pointers were passed */
+
+ if (msg == NULL)
+ {
+ return -EINVAL;
+ }
+
+ if (msg->msg_iovlen != 1)
+ {
+ return -ENOTSUP;
+ }
+
+ /* Verify that the sockfd corresponds to valid, allocated socket */
+
+ if (psock == NULL || psock->s_crefs <= 0)
+ {
+ return -EBADF;
+ }
+
+ /* Let logic specific to this address family handle the recvfrom()
+ * operation.
+ */
+
+ DEBUGASSERT(psock->s_sockif != NULL &&
+ (psock->s_sockif->si_recvmsg != NULL ||
+ psock->s_sockif->si_recvfrom != NULL));
+
+ if (psock->s_sockif->si_recvmsg != NULL)
+ {
+ return psock->s_sockif->si_recvmsg(psock, msg, flags);
+ }
+ else
+ {
+ /* Socket doesn't implement si_recvmsg fallback to si_recvfrom */
+
+ FAR void *buf = msg->msg_iov->iov_base;
+ FAR struct sockaddr *from = msg->msg_name;
+ FAR socklen_t *fromlen = (FAR socklen_t *)&msg->msg_namelen;
+ size_t len = msg->msg_iov->iov_len;
+
+ return psock->s_sockif->si_recvfrom(psock, buf, len, flags, from,
+ fromlen);
+ }
+}
+
+/****************************************************************************
+ * Name: nx_recvfrom
+ *
+ * Description:
+ * nx_recvfrom() receives messages from a socket, and may be used to
+ * receive data on a socket whether or not it is connection-oriented.
+ * This is an internal OS interface. It is functionally equivalent to
+ * recvfrom() except that:
+ *
+ * - It is not a cancellation point, and
+ * - It does not modify the errno variable.
+ *
+ * Input Parameters:
+ * sockfd - Socket descriptor of socket
+ * msg Buffer to receive msg
+ * len - Length of buffer
+ * flags - Receive flags
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. If no data is
+ * available to be received and the peer has performed an orderly shutdown,
+ * recv() will return 0. Otherwise, on any failure, a negated errno value
+ * is returned (see comments with send() for a list of appropriate errno
+ * values).
+ *
+ ****************************************************************************/
+
+ssize_t nx_recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
+{
+ FAR struct socket *psock;
+
+ /* Get the underlying socket structure */
+
+ psock = sockfd_socket(sockfd);
+
+ /* Then let psock_recvmsg() do all of the work */
+
+ return psock_recvmsg(psock, msg, flags);
+}
+
+/****************************************************************************
+ * Function: recvmsg
+ *
+ * Description:
+ * The recvmsg() call is identical to recvfrom() with a NULL from
+ * parameter.
+ *
+ * Parameters:
+ * sockfd Socket descriptor of socket
+ * msg Buffer to receive msg
+ * len Length of buffer
+ * flags Receive flags
+ *
+ * Returned Value:
+ * On success, returns the number of characters received. On error,
+ * -1 is returned, and errno is set appropriately:
+ *
+ * EAGAIN
+ * The socket is marked non-blocking and the receive operation would
+ * block, or a receive timeout had been set and the timeout expired
+ * before data was received.
+ * EBADF
+ * The argument sockfd is an invalid descriptor.
+ * ECONNREFUSED
+ * A remote host refused to allow the network connection (typically
+ * because it is not running the requested service).
+ * EFAULT
+ * The receive buffer pointer(s) point outside the process's address
+ * space.
+ * EINTR
+ * The receive was interrupted by delivery of a signal before any data
+ * were available.
+ * EINVAL
+ * Invalid argument passed.
+ * ENOMEM
+ * Could not allocate memory.
+ * ENOTCONN
+ * The socket is associated with a connection-oriented protocol and has
+ * not been connected.
+ * ENOTSOCK
+ * The argument sockfd does not refer to a socket.
+ *
+ ****************************************************************************/
+
+ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
+{
+ FAR struct socket *psock;
+ ssize_t ret;
+
+ /* recvfrom() is a cancellation point */
+
+ enter_cancellation_point();
+
+ /* Get the underlying socket structure */
+
+ psock = sockfd_socket(sockfd);
+
+ /* Let psock_recvfrom() do all of the work */
+
+ ret = psock_recvmsg(psock, msg, flags);
+ if (ret < 0)
+ {
+ _SO_SETERRNO(psock, -ret);
+ ret = ERROR;
+ }
+
+ leave_cancellation_point();
+ return ret;
+}
+
+#endif /* CONFIG_NET_CMSG */
diff --git a/net/socket/sendmsg.c b/net/socket/sendmsg.c
new file mode 100644
index 0000000..a188b3a
--- /dev/null
+++ b/net/socket/sendmsg.c
@@ -0,0 +1,243 @@
+/****************************************************************************
+ * net/socket/sendmsg.c
+ *
+ * Copyright (C) 2007-2009, 2011-2017, 2019 Gregory Nutt. All rights
+ * reserved.
+ * Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <errno.h>
+
+#include <nuttx/cancelpt.h>
+#include <nuttx/net/net.h>
+
+#include "socket/socket.h"
+
+#ifdef CONFIG_NET_CMSG
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: psock_sendmsg
+ *
+ * Description:
+ * psock_sendfrom() sends messages to a socket, and may be used to
+ * send data on a socket whether or not it is connection-oriented.
+ * This is an internal OS interface. It is functionally equivalent to
+ * sendfrom() except that:
+ *
+ * - It is not a cancellation point,
+ * - It does not modify the errno variable, and
+ * - I accepts the internal socket structure as an input rather than an
+ * task-specific socket descriptor.
+ *
+ * Input Parameters:
+ * psock - A pointer to a NuttX-specific, internal socket structure
+ * msg - Buffer to of the msg
+ * len - Length of buffer
+ * flags - Receive flags
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. If no data is
+ * available to be received and the peer has performed an orderly shutdown,
+ * send() will return 0. Otherwise, on any failure, a negated errno value
+ * is returned (see comments with send() for a list of appropriate errno
+ * values).
+ *
+ ****************************************************************************/
+
+ssize_t psock_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+ int flags)
+{
+ /* Verify that non-NULL pointers were passed */
+
+ if (msg == NULL)
+ {
+ return -EINVAL;
+ }
+
+ if (msg->msg_iovlen != 1)
+ {
+ return -ENOTSUP;
+ }
+
+ /* Verify that the sockfd corresponds to valid, allocated socket */
+
+ if (psock == NULL || psock->s_crefs <= 0)
+ {
+ return -EBADF;
+ }
+
+ /* Let logic specific to this address family handle the sendfrom()
+ * operation.
+ */
+
+ DEBUGASSERT(psock->s_sockif != NULL &&
+ (psock->s_sockif->si_sendmsg != NULL ||
+ psock->s_sockif->si_sendto != NULL));
+
+ if (psock->s_sockif->si_sendmsg != NULL)
+ {
+ return psock->s_sockif->si_sendmsg(psock, msg, flags);
+ }
+ else
+ {
+ /* Socket doesn't implement si_sendmsg fallback to si_sendto */
+
+ FAR void *buf = msg->msg_iov->iov_base;
+ FAR struct sockaddr *to = msg->msg_name;
+ socklen_t tolen = msg->msg_namelen;
+ size_t len = msg->msg_iov->iov_len;
+
+ return psock->s_sockif->si_sendto(psock, buf, len, flags, to, tolen);
+ }
+}
+
+/****************************************************************************
+ * Name: nx_sendfrom
+ *
+ * Description:
+ * nx_sendfrom() receives messages from a socket, and may be used to
+ * receive data on a socket whether or not it is connection-oriented.
+ * This is an internal OS interface. It is functionally equivalent to
+ * sendfrom() except that:
+ *
+ * - It is not a cancellation point, and
+ * - It does not modify the errno variable.
+ *
+ * Input Parameters:
+ * sockfd - Socket descriptor of socket
+ * msg Buffer to receive msg
+ * len - Length of buffer
+ * flags - Receive flags
+ *
+ * Returned Value:
+ * On success, returns the number of characters sent. If no data is
+ * available to be received and the peer has performed an orderly shutdown,
+ * send() will return 0. Otherwise, on any failure, a negated errno value
+ * is returned (see comments with send() for a list of appropriate errno
+ * values).
+ *
+ ****************************************************************************/
+
+ssize_t nx_sendmsg(int sockfd, FAR struct msghdr *msg, int flags)
+{
+ FAR struct socket *psock;
+
+ /* Get the underlying socket structure */
+
+ psock = sockfd_socket(sockfd);
+
+ /* Then let psock_sendmsg() do all of the work */
+
+ return psock_sendmsg(psock, msg, flags);
+}
+
+/****************************************************************************
+ * Function: sendmsg
+ *
+ * Description:
+ * The sendmsg() call is identical to sendfrom() with a NULL from
+ * parameter.
+ *
+ * Parameters:
+ * sockfd Socket descriptor of socket
+ * msg Buffer to receive msg
+ * len Length of buffer
+ * flags Receive flags
+ *
+ * Returned Value:
+ * On success, returns the number of characters received. On error,
+ * -1 is returned, and errno is set appropriately:
+ *
+ * EAGAIN
+ * The socket is marked non-blocking and the receive operation would
+ * block, or a receive timeout had been set and the timeout expired
+ * before data was received.
+ * EBADF
+ * The argument sockfd is an invalid descriptor.
+ * ECONNREFUSED
+ * A remote host refused to allow the network connection (typically
+ * because it is not running the requested service).
+ * EFAULT
+ * The receive buffer pointer(s) point outside the process's address
+ * space.
+ * EINTR
+ * The receive was interrupted by delivery of a signal before any data
+ * were available.
+ * EINVAL
+ * Invalid argument passed.
+ * ENOMEM
+ * Could not allocate memory.
+ * ENOTCONN
+ * The socket is associated with a connection-oriented protocol and has
+ * not been connected.
+ * ENOTSOCK
+ * The argument sockfd does not refer to a socket.
+ *
+ ****************************************************************************/
+
+ssize_t sendmsg(int sockfd, FAR struct msghdr *msg, int flags)
+{
+ FAR struct socket *psock;
+ ssize_t ret;
+
+ /* sendfrom() is a cancellation point */
+
+ enter_cancellation_point();
+
+ /* Get the underlying socket structure */
+
+ psock = sockfd_socket(sockfd);
+
+ /* Let psock_sendfrom() do all of the work */
+
+ ret = psock_sendmsg(psock, msg, flags);
+ if (ret < 0)
+ {
+ _SO_SETERRNO(psock, -ret);
+ ret = ERROR;
+ }
+
+ leave_cancellation_point();
+ return ret;
+}
+
+#endif /* CONFIG_NET_CMSG */
diff --git a/net/socket/setsockopt.c b/net/socket/setsockopt.c
index 211a1df..da4b923 100644
--- a/net/socket/setsockopt.c
+++ b/net/socket/setsockopt.c
@@ -279,6 +279,29 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
}
break;
#endif
+
+#ifdef CONFIG_NET_TIMESTAMP
+ case SO_TIMESTAMP: /* Generates a timestamp for each incoming packet */
+ {
+ /* Verify that option is at least the size of an integer. */
+
+ if (value_len < sizeof(FAR int32_t))
+ {
+ return -EINVAL;
+ }
+
+ /* Lock the network so that we have exclusive access to the socket
+ * options.
+ */
+
+ net_lock();
+
+ psock->s_timestamp = *((FAR int32_t *)value);
+
+ net_unlock();
+ }
+ break;
+#endif
/* The following are not yet implemented */
case SO_RCVBUF: /* Sets receive buffer size */
@@ -399,6 +422,12 @@ int psock_setsockopt(FAR struct socket *psock, int level, int option,
break;
#endif
+#ifdef CONFIG_NET_CANPROTO_OPTIONS
+ case SOL_CAN_RAW: /* CAN protocol socket options (see include/netpacket/can.h) */
+ ret = can_setsockopt(psock, option, value, value_len);
+ break;
+#endif
+
default: /* The provided level is invalid */
ret = -EINVAL;
break;
diff --git a/net/socket/socket.h b/net/socket/socket.h
index 0f809ac..bd2a0ea 100644
--- a/net/socket/socket.h
+++ b/net/socket/socket.h
@@ -80,7 +80,7 @@
/* This is the largest option value. REVISIT: belongs in sys/socket.h */
-#define _SO_MAXOPT (15)
+#define _SO_MAXOPT (16)
/* Macros to set, test, clear options */
diff --git a/net/utils/net_lock.c b/net/utils/net_lock.c
index da6784d..645a5cc 100644
--- a/net/utils/net_lock.c
+++ b/net/utils/net_lock.c
@@ -229,6 +229,57 @@ int net_lock(void)
}
/****************************************************************************
+ * Name: net_trylock
+ *
+ * Description:
+ * Try to take the network lock only when it is currently not locked.
+ * Otherwise, it locks the semaphore. In either
+ * case, the call returns without blocking.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * Zero (OK) is returned on success; a negated errno value is returned on
+ * failured (probably -EAGAIN).
+ *
+ ****************************************************************************/
+
+int net_trylock(void)
+{
+#ifdef CONFIG_SMP
+ irqstate_t flags = enter_critical_section();
+#endif
+ pid_t me = getpid();
+ int ret = OK;
+
+ /* Does this thread already hold the semaphore? */
+
+ if (g_holder == me)
+ {
+ /* Yes.. just increment the reference count */
+
+ g_count++;
+ }
+ else
+ {
+ ret = nxsem_trywait(&g_netlock);
+ if (ret >= 0)
+ {
+ /* Now this thread holds the semaphore */
+
+ g_holder = me;
+ g_count = 1;
+ }
+ }
+
+#ifdef CONFIG_SMP
+ leave_critical_section(flags);
+#endif
+ return ret;
+}
+
+/****************************************************************************
* Name: net_unlock
*
* Description: