diff --git a/fs/vfs/fs_write.c b/fs/vfs/fs_write.c index 6e9a37962bb..d1b7f035b31 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 0b90045aa43..0332ab71120 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 00000000000..4ee66456980 --- /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 + +#include +#include + +/**************************************************************************** + * 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 00000000000..c681b32c520 --- /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 + * + * 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 +#endif + +#include + +#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 + * + * & 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 00000000000..cf5fec64b77 --- /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 + * 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 8984af6b4d8..32c0bfde32d 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 @@ -219,6 +220,9 @@ enum iob_user_e #endif #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 00000000000..f9cbe935be8 --- /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 + * + * Derived from uIP with has a similar BSD-styple license: + * + * Author: Adam Dunkels + * 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 +#include +#include + +/**************************************************************************** + * 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 4717542e12a..6f2f20e0ea4 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 c2cbb930e16..836edbf1401 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 */ @@ -370,6 +380,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 * diff --git a/include/nuttx/wqueue.h b/include/nuttx/wqueue.h index d353772677d..ea7563cf7cc 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 b940126eb45..e8eca51b232 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 984a16fff37..071c189290d 100644 --- a/libs/libc/net/lib_recvmsg.c +++ b/libs/libc/net/lib_recvmsg.c @@ -39,7 +39,7 @@ #include -#ifdef CONFIG_NET +#if defined(CONFIG_NET) && !defined(CONFIG_NET_CMSG) #include #include @@ -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 0d09faa354a..9f98e51f203 100644 --- a/libs/libc/net/lib_sendmsg.c +++ b/libs/libc/net/lib_sendmsg.c @@ -39,7 +39,7 @@ #include -#ifdef CONFIG_NET +#if defined(CONFIG_NET) && !defined(CONFIG_NET_CMSG) #include #include @@ -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 bedf933d581..80fe9190033 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 077d0357c98..f8ffe85aea2 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 41bcafac221..4057d9327bb 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 00000000000..e84c99de454 --- /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 00000000000..3204b3b8669 --- /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 00000000000..cae3eb45e33 --- /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 + +#include +#include + +#include +#include +#include +#include + +#include "devif/devif.h" +#include "socket/socket.h" + +#ifdef CONFIG_NET_CAN_NOTIFIER +# include +#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 00000000000..f8f0fae1d22 --- /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 +#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN) + +#include +#include + +#include +#include +#include + +#include "devif/devif.h" +#include "can/can.h" + +#ifdef CONFIG_NET_TIMESTAMP +#include +#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 00000000000..574796ce282 --- /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 + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#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 00000000000..df6d0c94d45 --- /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 + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#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 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 00000000000..024bb9aad52 --- /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 +#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN) + +#include +#include + +#include +#include + +#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/net/can/can_notifier.c b/net/can/can_notifier.c new file mode 100644 index 00000000000..f4c7b1e8527 --- /dev/null +++ b/net/can/can_notifier.c @@ -0,0 +1,83 @@ +/**************************************************************************** + * net/can/can_notifier.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include +#include + +#include + +#include "can/can.h" + +#ifdef CONFIG_NET_CAN_NOTIFIER + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * 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. + * + ****************************************************************************/ + +void can_readahead_signal(FAR struct can_conn_s *conn) +{ + /* This is just a simple wrapper around work_notifier_signal(). */ + + work_notifier_signal(WORK_CAN_READAHEAD, conn); +} + +#endif /* CONFIG_NET_CAN_NOTIFIER */ diff --git a/net/can/can_poll.c b/net/can/can_poll.c new file mode 100644 index 00000000000..21632429802 --- /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 +#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN) + +#include + +#include +#include + +#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 00000000000..bbea9c30f65 --- /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 + +#ifdef CONFIG_NET_CAN + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "netdev/netdev.h" +#include "devif/devif.h" +#include "can/can.h" +#include "socket/socket.h" +#include + +#ifdef CONFIG_NET_TIMESTAMP +#include +#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 00000000000..3c01684ab99 --- /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 + * + * 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 +#if defined(CONFIG_NET) && defined(CONFIG_NET_CAN) + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "netdev/netdev.h" +#include "devif/devif.h" +#include "socket/socket.h" +#include "can/can.h" + +#ifdef CONFIG_NET_CMSG +#include +#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 00000000000..3359e40a0bf --- /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 + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#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 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/can/can_sockif.c b/net/can/can_sockif.c new file mode 100644 index 00000000000..d39934fd4bc --- /dev/null +++ b/net/can/can_sockif.c @@ -0,0 +1,856 @@ +/**************************************************************************** + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "can/can.h" +#include "netdev/netdev.h" + +#ifdef CONFIG_NET_CAN + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +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 can_getsockname(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); +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 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 can_send(FAR struct socket *psock, + FAR const void *buf, size_t len, int flags); +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); +#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_can_sockif = +{ + 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 */ +#endif + can_recvfrom, /* si_recvfrom */ +#ifdef CONFIG_NET_CMSG + can_recvmsg, /* si_recvmsg */ + can_sendmsg, /* si_sendmsg */ +#endif + can_close /* si_close */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * 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 + * protocol are usable by this address family. Perform any family- + * specific socket fields. + * + * Input Parameters: + * psock - A pointer to a user allocated socket structure to be + * initialized. + * protocol - NetLink socket protocol (see sys/socket.h) + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise, a negated errno value is + * returned. + * + ****************************************************************************/ + +static int can_setup(FAR struct socket *psock, int protocol) +{ + int domain = psock->s_domain; + int type = psock->s_type; + + /* Verify that the protocol is supported */ + + DEBUGASSERT((unsigned int)protocol <= UINT8_MAX); + + switch (protocol) + { + 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; + + default: + return -EPROTONOSUPPORT; + } + + /* Verify the socket type (domain should always be PF_CAN here) */ + + 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 can_conn_s *conn = can_alloc(); + if (conn == NULL) + { + /* Failed to reserve a connection structure */ + + 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; + + /* Set the reference count on the connection structure. This + * reference count will be incremented only if the socket is + * dup'ed + */ + + conn->crefs = 1; + + /* Attach the connection instance to the socket */ + + psock->s_conn = conn; + return OK; + } + + return -EPROTONOSUPPORT; +} + +/**************************************************************************** + * Name: can_sockcaps + * + * Description: + * Return the bit encoded capabilities of this socket. + * + * Input Parameters: + * psock - Socket structure of the socket whose capabilities are being + * queried. + * + * Returned Value: + * The non-negative set of socket capabilities is returned. + * + ****************************************************************************/ + +static sockcaps_t can_sockcaps(FAR struct socket *psock) +{ + /* Permit vfcntl to set socket to non-blocking */ + + return SOCKCAP_NONBLOCKING; +} + +/**************************************************************************** + * Name: can_addref + * + * Description: + * Increment the reference count on the underlying connection structure. + * + * Input Parameters: + * psock - Socket structure of the socket whose reference count will be + * incremented. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void can_addref(FAR struct socket *psock) +{ + FAR struct can_conn_s *conn; + + DEBUGASSERT(psock != NULL && psock->s_conn != NULL); + + conn = psock->s_conn; + DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255); + conn->crefs++; +} + +/**************************************************************************** + * Name: can_bind + * + * Description: + * 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. + * + * Input Parameters: + * conn NetLink socket connection structure + * addr Socket local address + * addrlen Length of 'addr' + * + * Returned Value: + * 0 on success; -1 on error with errno set appropriately + * + * EACCES + * The address is protected, and the user is not the superuser. + * EADDRINUSE + * The given address is already in use. + * EINVAL + * The socket is already bound to an address. + * ENOTSOCK + * psock is a descriptor for a file, not a socket. + * + * Assumptions: + * + ****************************************************************************/ + +static int can_bind(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen) +{ + FAR struct sockaddr_can *canaddr; + FAR struct can_conn_s *conn; + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && addr != NULL && + addrlen >= sizeof(struct sockaddr_can)); + + /* Save the address information in the connection structure */ + + canaddr = (FAR struct sockaddr_can *)addr; + conn = (FAR struct can_conn_s *)psock->s_conn; + + /* Bind CAN device to socket */ + +#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: can_getsockname + * + * Description: + * The getsockname() function retrieves the locally-bound name of the + * specified 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. + * + * If the socket has not been bound to a local name, the value stored in + * the object pointed to by address is unspecified. + * + * Input Parameters: + * conn NetLink socket connection structure + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + ****************************************************************************/ + +static int can_getsockname(FAR struct socket *psock, + FAR struct sockaddr *addr, + FAR socklen_t *addrlen) +{ + return -EAFNOSUPPORT; +} + +/**************************************************************************** + * Name: can_getpeername + * + * Description: + * 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. + * + * If the actual length of the address is greater than the length of the + * supplied sockaddr structure, the stored address will be truncated. + * + * If the socket has not been bound to a local name, the value stored in + * the object pointed to by address is unspecified. + * + * Parameters: + * psock Socket structure of the socket to be queried + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + * Returned Value: + * On success, 0 is returned, the 'addr' argument points to the address + * of the socket, and the 'addrlen' argument points to the length of the + * address. Otherwise, a negated errno value is returned. See + * getpeername() for the list of appropriate error numbers. + * + ****************************************************************************/ + +static int can_getpeername(FAR struct socket *psock, + FAR struct sockaddr *addr, + FAR socklen_t *addrlen) +{ + return -EOPNOTSUPP; +} + +/**************************************************************************** + * Name: can_listen + * + * Description: + * To accept connections, a socket is first created with psock_socket(), a + * willingness to accept incoming connections and a queue limit for + * incoming connections are specified with psock_listen(), and then the + * connections are accepted with psock_accept(). For the case of AFINET + * and AFINET6 sockets, psock_listen() calls this function. The + * psock_listen() call applies only to sockets of type SOCK_STREAM or + * SOCK_SEQPACKET. + * + * Input Parameters: + * psock Reference to an internal, bound socket structure. + * backlog The maximum length the queue of pending connections may grow. + * If a connection request arrives with the queue full, the client + * may receive an error with an indication of ECONNREFUSED or, + * if the underlying protocol supports retransmission, the request + * may be ignored so that retries succeed. + * + * Returned Value: + * On success, zero is returned. On error, a negated errno value is + * returned. See list() for the set of appropriate error values. + * + ****************************************************************************/ + +static int can_listen(FAR struct socket *psock, int backlog) +{ + return -EOPNOTSUPP; +} + +/**************************************************************************** + * Name: can_connect + * + * Description: + * Perform a can connection + * + * Input Parameters: + * 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 + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int can_connect(FAR struct socket *psock, + FAR const struct sockaddr *addr, + socklen_t addrlen) +{ + return -EOPNOTSUPP; +} + +/**************************************************************************** + * Name: can_accept + * + * Description: + * 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 + * allocates a new socket descriptor for the socket, which is returned. The + * newly created socket is no longer in the listening state. The original + * socket 'sockfd' is unaffected by this call. Per file descriptor flags + * are not inherited across an inet_accept. + * + * The 'sockfd' argument is a socket descriptor that has been created with + * socket(), bound to a local address with bind(), and is listening for + * connections after a call to listen(). + * + * On return, the 'addr' structure is filled in with the address of the + * connecting entity. The 'addrlen' argument initially contains the size + * of the structure pointed to by 'addr'; on return it will contain the + * actual length of the address returned. + * + * If no pending connections are present on the queue, and the socket is + * 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. + * + * Input Parameters: + * psock Reference to the listening socket structure + * addr Receives the address of the connecting client + * addrlen Input: Allocated size of 'addr' + * Return: Actual size returned size of 'addr' + * newsock Location to return the accepted socket information. + * + * Returned Value: + * Returns 0 (OK) on success. On failure, it returns a negated errno + * value. See accept() for a description of the appropriate error value. + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static int can_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR struct socket *newsock) +{ + return -EOPNOTSUPP; +} + +/**************************************************************************** + * Name: can_poll_local + * + * Description: + * The standard poll() operation redirects operations on socket descriptors + * to this function. + * + * POLLUP: Will never be reported + * POLLERR: Reported in the event of any failure. + * POLLOUT: Always reported if requested. + * POLLIN: Reported if requested but only when pending response data is + * available + * + * Input Parameters: + * psock - An instance of the internal socket structure. + * fds - The structure describing the events to be monitored. + * setup - true: Setup up the poll; false: Tear down the poll + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +static int can_poll_local(FAR struct socket *psock, FAR struct pollfd *fds, + bool setup) +{ + 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 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) + { + 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 */ + + info->psock = psock; + info->fds = fds; + info->cb = cb; + + /* Initialize the callback structure. Save the reference to the info + * structure as callback private data so that it will be available + * during callback processing. + */ + + 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) + { + cb->flags |= CAN_NEWDATA; + } + + /* Save the reference in the poll info structure as fds private as well + * for use during poll teardown as well. + */ + + fds->priv = (FAR void *)info; + + /* Check for read data availability now */ + + if (!IOB_QEMPTY(&conn->readahead)) + { + /* Normal data may be read without blocking. */ + + fds->revents |= (POLLRDNORM & fds->events); + } + + #if 0 + if (psock_udp_cansend(psock) >= 0) + { + /* Normal data may be sent without blocking (at least one byte). */ + + fds->revents |= (POLLWRNORM & fds->events); + } + #endif + + /* Check if any requested events are already in effect */ + + if (fds->revents != 0) + { + /* Yes.. then signal the poll logic */ + + nxsem_post(fds->sem); + } + +errout_with_lock: + net_unlock(); + } + else + { + info = (FAR struct can_poll_s *)fds->priv; + + 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: can_send + * + * Description: + * 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: + * psock - An instance of the internal socket structure. + * buf - Data to send + * len - Length of data to send + * 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 can_send(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags) +{ + ssize_t ret; + + /* Only SOCK_RAW is supported */ + + if (psock->s_type == SOCK_RAW) + { + /* Raw packet send */ + + ret = psock_can_send(psock, buf, len); + } + else + { + /* EDESTADDRREQ. Signifies that the socket is not connection-mode and + * no peer address is set. + */ + + ret = -EDESTADDRREQ; + } + + return ret; +} + +/**************************************************************************** + * Name: can_sendto + * + * Description: + * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) + * socket, the parameters to and 'tolen' are ignored (and the error EISCONN + * may be returned when they are not NULL and 0), and the error ENOTCONN is + * returned when the socket was not actually connected. + * + * Input Parameters: + * 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) + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +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) +{ + nerr("ERROR: sendto() not supported for raw packet sockets\n"); + return -EAFNOSUPPORT; +} + +/**************************************************************************** + * Name: can_sendmsg + * + * Description: + * The can_sendmsg() send a CAN frame to psock + * + * Input Parameters: + * 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. + * + ****************************************************************************/ +#ifdef CONFIG_NET_CMSG +static ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg, + int flags) +{ + ssize_t ret; + + /* Only SOCK_RAW is supported */ + + if (psock->s_type == SOCK_RAW) + { + /* Raw packet send */ + + ret = psock_can_sendmsg(psock, msg); + } + else + { + /* EDESTADDRREQ. Signifies that the socket is not connection-mode and + * no peer address is set. + */ + + ret = -EDESTADDRREQ; + } + + return ret; +} +#endif + +/**************************************************************************** + * Name: can_close + * + * Description: + * Performs the close operation on a NetLink socket instance + * + * Input Parameters: + * psock Socket instance + * + * Returned Value: + * 0 on success; -1 on error with errno set appropriately. + * + * Assumptions: + * + ****************************************************************************/ + +static int can_close(FAR struct socket *psock) +{ + FAR struct can_conn_s *conn = psock->s_conn; + int ret = OK; + + /* 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). + */ + + if (conn->crefs <= 1) + { + /* Yes... inform user-space daemon of socket close. */ + +#warning Missing logic + + /* Free the connection structure */ + + conn->crefs = 0; + can_free(psock->s_conn); + + if (ret < 0) + { + /* Return with error code, but free resources. */ + + nerr("ERROR: can_close failed: %d\n", ret); + return ret; + } + } + else + { + /* No.. Just decrement the reference count */ + + conn->crefs--; + } + + return ret; +} + +#endif /* CONFIG_NET_CAN */ diff --git a/net/devif/Make.defs b/net/devif/Make.defs index 714a0cedf49..492c7d83856 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 cbe1a005cb4..1a95011f3bf 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/devif/devif_cansend.c b/net/devif/devif_cansend.c new file mode 100644 index 00000000000..43570f22a82 --- /dev/null +++ b/net/devif/devif_cansend.c @@ -0,0 +1,113 @@ +/**************************************************************************** + * net/devif/devif_cansend.c + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include +#include +#include + +#include + +#if defined(CONFIG_NET_CAN) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Public Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Constant Data + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: devif_can_send + * + * Description: + * Called from socket logic in order to send a can 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: + * Called with the network locked. + * + ****************************************************************************/ + +void devif_can_send(FAR struct net_driver_s *dev, FAR const void *buf, + unsigned int len) +{ + DEBUGASSERT(dev && len > 0 && len < NETDEV_PKTSIZE(dev)); + + /* Copy the data into the device packet buffer */ + + memcpy(dev->d_buf, buf, len); + + /* Set the number of bytes to send */ + + dev->d_len = len; + dev->d_sndlen = len; +} + +#endif /* CONFIG_NET_CAN */ diff --git a/net/devif/devif_poll.c b/net/devif/devif_poll.c index 7c4fd045b2d..ffffed463e8 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" @@ -232,6 +233,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 * @@ -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 983eb71675c..2b1e17946f8 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 c99d1845b74..3dbb5c82e47 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 216264a98a4..eb5d6e5f90a 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 9456510fb06..488f2d1bfc0 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 68dfac6e703..644dd310f39 100644 --- a/net/local/local_sendpacket.c +++ b/net/local/local_sendpacket.c @@ -47,6 +47,7 @@ #include #include +#include "devif/devif.h" #include "local/local.h" diff --git a/net/local/local_sockif.c b/net/local/local_sockif.c index f2bbcb1428a..c4f753156a6 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 eb82777d0f2..bedc4e30552 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 2b3f905026f..ce51c1f79aa 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 04c9b5138e2..c169503e094 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 4b08efaefa5..3694db5aad2 100644 --- a/net/netdev/netdev_register.c +++ b/net/netdev/netdev_register.c @@ -37,6 +37,7 @@ #include #include #include +#include #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 577d520c3dd..34b011a3a54 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 e189ddc2f05..dbf3e3c381c 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 c627ea551fe..f13e22ddfe8 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 47fb4d29eb9..6bf79edd029 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 e7474adbf5d..581edc04384 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 01e83681cc6..cc956d8e450 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 00000000000..9ba5de30cea --- /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 + * + * 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 + +#include +#include + +#include +#include + +#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 00000000000..a188b3ad42b --- /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 + * + * 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 + +#include +#include + +#include +#include + +#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 211a1dfe61c..da4b9238315 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 0f809ac9ab9..bd2a0ea792e 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 da6784d9c11..645a5cc9be4 100644 --- a/net/utils/net_lock.c +++ b/net/utils/net_lock.c @@ -228,6 +228,57 @@ int net_lock(void) return ret; } +/**************************************************************************** + * 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 *