This is an automated email from the ASF dual-hosted git repository. gnutt pushed a commit to branch SocketCAN in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 6448d417c4580b9b037323a99ea5b99f82400198 Author: Gregory Nutt <gn...@nuttx.org> AuthorDate: Thu Feb 13 09:59:00 2020 -0600 net/: Add WIP initial framework for SocketCAN sockets. --- net/Kconfig | 1 + net/Makefile | 1 + net/can/Kconfig | 26 ++ net/can/Make.defs | 32 ++ net/can/can.h | 154 +++++++++ net/can/can_conn.c | 225 ++++++++++++++ net/can/can_sockif.c | 810 ++++++++++++++++++++++++++++++++++++++++++++++++ net/net_initialize.c | 7 + net/socket/net_sockif.c | 7 + 9 files changed, 1263 insertions(+) diff --git a/net/Kconfig b/net/Kconfig index fed3d01..70cacf6 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -344,6 +344,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 2890aaf..066d061 100644 --- a/net/Makefile +++ b/net/Makefile @@ -66,6 +66,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/can/Kconfig b/net/can/Kconfig new file mode 100644 index 0000000..2ae1f7b --- /dev/null +++ b/net/can/Kconfig @@ -0,0 +1,26 @@ +# +# 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 + ---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 CAN_CONNS + int "Number of CAN connections" + default 4 + ---help--- + Maximum number of CAN connections (all tasks). + +endif # NET_CAN +endmenu # CAN Socket Support diff --git a/net/can/Make.defs b/net/can/Make.defs new file mode 100644 index 0000000..bb9ef9f --- /dev/null +++ b/net/can/Make.defs @@ -0,0 +1,32 @@ +############################################################################ +# 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) + +SOCK_CSRCS += can_sockif.c +NET_CSRCS += can_conn.c + +# Include can build support + +DEPPATH += --dep-path can +VPATH += :can +endif diff --git a/net/can/can.h b/net/can/can.h new file mode 100644 index 0000000..6f41ce9 --- /dev/null +++ b/net/can/can.h @@ -0,0 +1,154 @@ +/**************************************************************************** + * net/can/can.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __NET_CAN_CAN_H +#define __NET_CAN_CAN_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <poll.h> + +#include <netpacket/can.h> +#include <nuttx/semaphore.h> + +#include "devif/devif.h" +#include "socket/socket.h" + +#ifdef CONFIG_NET_CAN + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +/* 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 */ + + /* CAN-specific content follows */ + + uint8_t protocol; /* Selected CAN protocol */ + int16_t crefs; /* Reference count */ + + /* poll() support */ + + FAR sem_t *pollsem; /* Used to wakeup poll() */ + FAR pollevent_t *pollevent; /* poll() wakeup event */ +}; + +/**************************************************************************** + * 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_active() + * + * Description: + * Find a connection structure that is the appropriate connection for the + * provided NetLink address + * + ****************************************************************************/ + +FAR struct can_conn_s *can_active(FAR struct sockaddr_can *addr); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_NET_CAN */ +#endif /* __NET_CAN_CAN_H */ diff --git a/net/can/can_conn.c b/net/can/can_conn.c new file mode 100644 index 0000000..77733b3 --- /dev/null +++ b/net/can/can_conn.c @@ -0,0 +1,225 @@ +/**************************************************************************** + * net/can/can_conn.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdint.h> +#include <string.h> +#include <queue.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <arch/irq.h> + +#include <nuttx/kmalloc.h> +#include <nuttx/semaphore.h> +#include <nuttx/net/netconfig.h> +#include <nuttx/net/net.h> + +#include "utils/utils.h" +#include "can/can.h" + +#ifdef CONFIG_NET_CAN + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* The array containing all NetLink connections. */ + +static struct can_conn_s g_can_connections[CONFIG_CAN_CONNS]; + +/* A list of all free NetLink connections */ + +static dq_queue_t g_free_can_connections; +static sem_t g_free_sem; + +/* A list of all allocated NetLink connections */ + +static dq_queue_t g_active_can_connections; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: _can_semtake() and _can_semgive() + * + * Description: + * Take/give semaphore + * + ****************************************************************************/ + +static void _can_semtake(FAR sem_t *sem) +{ + net_lockedwait_uninterruptible(sem); +} + +static void _can_semgive(FAR sem_t *sem) +{ + nxsem_post(sem); +} +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: can_initialize() + * + * Description: + * Initialize the User Socket connection structures. Called once and only + * from the networking layer. + * + ****************************************************************************/ + +void can_initialize(void) +{ + int i; + + /* Initialize the queues */ + + dq_init(&g_free_can_connections); + dq_init(&g_active_can_connections); + nxsem_init(&g_free_sem, 0, 1); + + for (i = 0; i < CONFIG_CAN_CONNS; i++) + { + FAR struct can_conn_s *conn = &g_can_connections[i]; + + /* Mark the connection closed and move it to the free list */ + + memset(conn, 0, sizeof(*conn)); + dq_addlast(&conn->node, &g_free_can_connections); + } +} + +/**************************************************************************** + * Name: can_alloc() + * + * Description: + * Allocate a new, uninitialized NetLink connection structure. This is + * normally something done by the implementation of the socket() API + * + ****************************************************************************/ + +FAR struct can_conn_s *can_alloc(void) +{ + FAR struct can_conn_s *conn; + + /* The free list is protected by a semaphore (that behaves like a mutex). */ + + _can_semtake(&g_free_sem); + conn = (FAR struct can_conn_s *)dq_remfirst(&g_free_can_connections); + if (conn != NULL) + { + /* Make sure that the connection is marked as uninitialized */ + + memset(conn, 0, sizeof(*conn)); + + /* 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; + } +} + +/**************************************************************************** + * Name: can_active + * + * Description: + * Find a connection structure that is the appropriate connection for the + * provided NetLink address + * + * Assumptions: + * + ****************************************************************************/ + +FAR struct can_conn_s *can_active(FAR struct sockaddr_can *addr) +{ + /* This function is used to handle routing of incoming messages to sockets + * connected to the address. There is no such use case for NetLink + * sockets. + */ + + return NULL; +} + +#endif /* CONFIG_NET_CAN */ diff --git a/net/can/can_sockif.c b/net/can/can_sockif.c new file mode 100644 index 0000000..b7e3fe6 --- /dev/null +++ b/net/can/can_sockif.c @@ -0,0 +1,810 @@ +/**************************************************************************** + * 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 <nuttx/config.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <stdbool.h> +#include <string.h> +#include <poll.h> +#include <sched.h> +#include <assert.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/kmalloc.h> +#include <nuttx/semaphore.h> +#include <nuttx/wqueue.h> +#include <nuttx/net/net.h> + +#include "can/can.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(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); +static ssize_t can_recvfrom(FAR struct socket *psock, FAR void *buf, + size_t len, int flags, FAR struct sockaddr *from, + FAR socklen_t *fromlen); +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, /* si_poll */ + can_send, /* si_send */ + can_sendto, /* si_sendto */ +#ifdef CONFIG_NET_SENDFILE + NULL, /* si_sendfile */ +#endif + can_recvfrom, /* si_recvfrom */ + can_close /* si_close */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: inet_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 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; + } + + /* 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; +#warning Missing logic + + 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) +{ + FAR struct sockaddr_can *canaddr; + + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && addr != NULL && + addrlen != NULL && *addrlen >= sizeof(struct sockaddr_can)); + + /* Return the address information in the address structure */ + + canaddr = (FAR struct sockaddr_can *)addr; + memset(canaddr, 0, sizeof(struct sockaddr_can)); + + canaddr->can_family = AF_CAN; + + if (_SS_ISBOUND(psock->s_flags)) + { + FAR struct can_conn_s *conn; + + conn = (FAR struct can_conn_s *)psock->s_conn; +#warning Missing logic + } + + *addrlen = sizeof(struct sockaddr_can); + return OK; +} + +/**************************************************************************** + * 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) +{ +#warning Missing logic + return -EOPNOTSUPP; /* Or maybe return -EAFNOSUPPORT; */ +} + +/**************************************************************************** + * 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) +{ +#warning Missing logic + 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) +{ +#warning Missing logic + 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) +{ +#warning Missing logic + return -EOPNOTSUPP; +} + +/**************************************************************************** + * Name: can_poll + * + * 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(FAR struct socket *psock, FAR struct pollfd *fds, + bool setup) +{ + FAR struct can_conn_s *conn; + int ret; + + DEBUGASSERT(psock != NULL && psock->s_conn != NULL); + conn = (FAR struct can_conn_s *)psock->s_conn; + + /* Check if we are setting up or tearing down the poll */ + + if (setup) + { + /* If POLLOUT is selected, return immediately (maybe) */ + + pollevent_t revents = POLLOUT; + + /* If POLLIN is selected and a response is available, return + * immediately if POLLIN and/or POLLIN are included in the + * requested event set. + */ + + net_lock(); + +#warning Missing logic + + revents &= fds->events; + if (revents != 0) + { + fds->revents = revents; + nxsem_post(fds->sem); + net_unlock(); + return OK; + } + + /* Set up to be notified when a response is available if POLLIN is + * requested. + */ + + if ((fds->events & POLLIN) != 0) + { + /* Some limitations: There can be only a single outstanding POLLIN + * on the CAN connection. + */ + + if (conn->pollsem != NULL || conn->pollevent != NULL) + { + nerr("ERROR: Multiple polls() on socket not supported.\n"); + net_unlock(); + return -EBUSY; + } + + /* Set up the notification */ + + conn->pollsem = fds->sem; + conn->pollevent = &fds->revents; + +#warning Missing logic + + if (ret < 0) + { + /* Failed to set up notification */ + + conn->pollsem = NULL; + conn->pollevent = NULL; + } + else + { + /* Setup to receive a notification when CAN data is available */ + +#warning Missing logic + + ret = OK; + } + } + + /* Set up to be notified when we are able to send CAN data without + * waiting. + */ + + else if ((fds->events & POLLOUT) != 0) + { + } + else + { + /* There will not be any wakeups coming? Probably an error? */ + + ret = OK; + } + + net_unlock(); + } + else + { + /* Cancel any response notifications */ + + conn->pollsem = NULL; + conn->pollevent = 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) +{ + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL); + + /* The socket must be connected in order to use send */ + + if (_SS_ISBOUND(psock->s_flags)) + { + FAR struct can_conn_s *conn; + struct sockaddr_can canaddr; + + /* Get the underlying connection structure */ + + conn = (FAR struct can_conn_s *)psock->s_conn; + + /* Format the address */ + + canaddr.can_family = AF_CAN; +#warning Missing logic + + /* Then let sendto() perform the actual send operation */ + + return can_sendto(psock, buf, len, flags, + (FAR const struct sockaddr *)&canaddr, + sizeof(struct sockaddr_can)); + } + + /* EDESTADDRREQ. Signifies that the socket is not connection-mode and no + * peer address is set. + */ + + return -EDESTADDRREQ; +} + +/**************************************************************************** + * 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) +{ + FAR struct can_conn_s *conn; + int ret; + + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && buf != NULL && + to != NULL && tolen >= sizeof(struct sockaddr_can)); + + conn = (FAR struct can_conn_s *)psock->s_conn; +#warning Missing logic + + switch (conn->protocol) + { +#warning Missing logic + + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +/**************************************************************************** + * 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 + * + ****************************************************************************/ + +static 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; + 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; +#warning Missing logic + + switch (conn->protocol) + { +#warning Missing logic + + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +/**************************************************************************** + * 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/net_initialize.c b/net/net_initialize.c index eb82777..bedc4e3 100644 --- a/net/net_initialize.c +++ b/net/net_initialize.c @@ -59,6 +59,7 @@ #include "bluetooth/bluetooth.h" #include "ieee802154/ieee802154.h" #include "local/local.h" +#include "can/can.h" #include "netlink/netlink.h" #include "igmp/igmp.h" #include "route/route.h" @@ -158,6 +159,12 @@ void net_initialize(void) local_initialize(); #endif +#ifdef CONFIG_NET_CAN + /* Initialize SocketCAN support */ + + can_initialize(); +#endif + #ifdef CONFIG_NET_NETLINK /* Initialize the Netlink IPC support */ diff --git a/net/socket/net_sockif.c b/net/socket/net_sockif.c index 01e8368..cc956d8 100644 --- a/net/socket/net_sockif.c +++ b/net/socket/net_sockif.c @@ -47,6 +47,7 @@ #include "inet/inet.h" #include "local/local.h" +#include "can/can.h" #include "netlink/netlink.h" #include "pkt/pkt.h" #include "bluetooth/bluetooth.h" @@ -104,6 +105,12 @@ net_sockif(sa_family_t family, int type, int protocol) break; #endif +#ifdef CONFIG_NET_CAN + case PF_CAN: + sockif = &g_can_sockif; + break; +#endif + #ifdef CONFIG_NET_NETLINK case PF_NETLINK: sockif = &g_netlink_sockif;