Merge remote-tracking branch 'origin/master' into composite

This commit is contained in:
Gregory Nutt 2017-07-13 13:57:40 -06:00
commit 1674cb8c8e
43 changed files with 10609 additions and 5133 deletions

View file

@ -466,6 +466,10 @@ config SAMDL_HAVE_TC7
bool
default n
config SAMDL_HAVE_USB
bool
default n
config SAMDL_AC
bool "Analog Comparator"
default n
@ -737,3 +741,25 @@ config SAMDL_I2C_REGDEBUG
Enable very low-level register access debug. Depends on DEBUG_I2C.
endif # SAMDL_HAVE_I2C
if SAMDL_HAVE_USB
config SAMDL_USB_ENABLE_PPEP
bool "Enable Ping-Pong Endpoints"
default n
---help---
To maximize throughput, an endpoint can be configured for ping-pong
operation. When this is done the input and output endpoint with the same
address are used in the same direction. The CPU or DMA Controller can
then read/write one data buffer while the USB module writes/reads from
the other buffer. This gives double buffered communication.
config SAMDL_USB_REGDEBUG
bool "USB register-Level Debug"
default n
depends on DEBUG_USB_INFO
---help---
Enable very low-level register access debug. Depends on
CONFIG_DEBUG_USB_INFO.
endif # SAMDL_HAVE_USB

View file

@ -98,3 +98,7 @@ endif
ifeq ($(CONFIG_SAMDL_HAVE_I2C),y)
CHIP_CSRCS += sam_i2c_master.c
endif
ifeq ($(CONFIG_SAMDL_USB),y)
CHIP_CSRCS += sam_usb.c
endif

View file

@ -37,6 +37,7 @@
*
********************************************************************************************/
#ifndef __ARCH_ARM_SRC_SAMDL_CHIP_SAML_USB_H
#define __ARCH_ARM_SRC_SAMDL_CHIP_SAML_USB_H
@ -53,6 +54,29 @@
/********************************************************************************************
* Pre-processor Definitions
********************************************************************************************/
/* Capabilities and characteristics of endpoints ********************************************/
/* EP EP BANKS EP SIZE EP TYPE
* --- --------- --------- ---------
* 0 2 64/1023 Control/Bulk/Iso/Interrupt
* 1 2 64/1023 Control/Bulk/Iso/Interrupt
* 2 2 64/1023 Control/Bulk/Iso/Interrupt
* 3 2 64/1023 Control/Bulk/Iso/Interrupt
* 4 2 64/1023 Control/Bulk/Iso/Interrupt
* 5 2 64/1023 Control/Bulk/Iso/Interrupt
* 6 2 64/1023 Control/Bulk/Iso/Interrupt
* 7 2 64/1023 Control/Bulk/Iso/Interrupt
*/
#define SAM_USB_NENDPOINTS (8)
#define SAM_USB_MAXPACKETSIZE(ep) (64)
#define SAM_USB_NBANKS(ep) (2)
#define SAM_USB_CONTROL(ep) (true)
#define SAM_USB_BULK(ep) (true)
#define SAM_USB_ISOCHRONOUS(ep) (true)
#define SAM_USB_INTERRUPT(ep) (true)
/* USB register offsets ********************************************************************/
/* Common USB Device/Host Register Offsets */

File diff suppressed because it is too large Load diff

View file

@ -101,7 +101,7 @@
# define USART4_ASSIGNED 1
#elif defined(CONFIG_USART5_SERIAL_CONSOLE)
# define CONSOLE_DEV g_usart5port /* USART5 is console */
# define TTYS5_DEV g_usart5port /* USART5 is ttyS0 */
# define TTYS0_DEV g_usart5port /* USART5 is ttyS0 */
#else
# undef CONSOLE_DEV /* No console */
# if defined(SAMDL_HAVE_USART0)

View file

@ -1261,7 +1261,12 @@ static void spi_recvblock(struct spi_dev_s *dev, void *buffer, size_t nwords)
static void spi_wait_synchronization(struct sam_spidev_s *priv)
{
#if defined(CONFIG_ARCH_FAMILY_SAMD20)
while ((spi_getreg16(priv, SAM_SPI_STATUS_OFFSET) & SPI_STATUS_SYNCBUSY) != 0);
#elif defined(CONFIG_ARCH_FAMILY_SAMD21) || defined(CONFIG_ARCH_FAMILY_SAML21)
while ((spi_getreg16(priv, SAM_SPI_SYNCBUSY_OFFSET) & SPI_SYNCBUSY_ALL) != 0);
#endif
}
/****************************************************************************

4056
arch/arm/src/samdl/sam_usb.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,99 @@
/******************************************************************************
* arch/arm/src/samdl/sam_usb.h
*
* Copyright (C) 2015 Filament - www.filament.com
* Copyright (C) 2015 Offcode Ltd. All rights reserved.
* Author: Janne Rosberg <janne@offcode.fi>
*
* This driver is derived from the SAM34 UDP driver:
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
#ifndef __ARCH_ARM_SRC_SAMDL_SAM_USB_H
#define __ARCH_ARM_SRC_SAMDL_SAM_USB_H
/*****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/usb/usbdev.h>
#include <stdint.h>
#include "chip.h"
#include "chip/saml_usb.h"
/*****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/*****************************************************************************
* Name: sam_usb_suspend
*
* Description:
* Board logic must provide the sam_usb_suspend logic if the USB driver is
* used. This function is called whenever the USB enters or leaves
* suspend mode.
*
* When 'resume' is false, this function call provides an opportunity to
* perform board-specific power-saving actions so that less power is consumed
* while the USB is suspended.
*
* XXX:
* Certain power-saving operations are performed by the UDP driver when it
* enters suspend mode: The USB device peripheral clocks are be switched off.
* MCK and UDPCK are switched off and the USB transceiver is disabled.
*
* When 'resume' is true, normal clocking and operations must all be restored.
*
*****************************************************************************/
void sam_udp_suspend(FAR struct usbdev_s *dev, bool resume);
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_SRC_SAMDL_SAM_USB_H */

View file

@ -301,7 +301,7 @@ static inline void sam_xosc_config(void)
/* Configure the XOSC clock */
regval = BOARD_XOSC_STARTUPTIME
regval = BOARD_XOSC_STARTUPTIME;
#ifdef BOARD_XOSC_ISCRYSTAL
/* XOSC is a crystal */
@ -383,7 +383,7 @@ static inline void sam_xosc32k_config(void)
/* Configure XOSC32K */
regval = BOARD_XOSC32K_STARTUPTIME
regval = BOARD_XOSC32K_STARTUPTIME;
#ifdef BOARD_XOSC32K_ISCRYSTAL
regval |= SYSCTRL_XOSC32K_XTALEN;

View file

@ -480,6 +480,19 @@
#define BOARD_SERCOM5_FREQUENCY BOARD_GCLK0_FREQUENCY
/* USB definitions ******************************************************************/
/* This is the source clock generator for the GCLK_USB clock
*/
#define BOARD_USB_GCLKGEN 0
#define BOARD_USB_FREQUENCY BOARD_GCLK0_FREQUENCY
/* default USB Pad calibration (not used yet by USB driver) */
#define BOARD_USB_PADCAL_P 29
#define BOARD_USB_PADCAL_N 5
#define BOARD_USB_PADCAL_TRIM 3
/* LED definitions ******************************************************************/
/* There are three LEDs on board the SAMD21 Xplained Pro board: The EDBG
* controls two of the LEDs, a power LED and a status LED. There is only

View file

@ -604,6 +604,19 @@
#define BOARD_SERCOM5_FREQUENCY BOARD_GCLK0_FREQUENCY
/* USB definitions ******************************************************************/
/* This is the source clock generator for the GCLK_USB clock
*/
#define BOARD_USB_GCLKGEN 0
#define BOARD_USB_FREQUENCY BOARD_GCLK0_FREQUENCY
/* default USB Pad calibration (not used yet by USB driver) */
#define BOARD_USB_PADCAL_P 29
#define BOARD_USB_PADCAL_N 5
#define BOARD_USB_PADCAL_TRIM 3
/* LED definitions ******************************************************************/
/* There are three LEDs on board the SAML21 Xplained Pro board: The EDBG
* controls two of the LEDs, a power LED and a status LED. There is only

View file

@ -64,6 +64,11 @@
# define __SOCKFD_OFFSET 0
#endif
/* Capabilities of a socket */
#define SOCKCAP_NONBLOCKING (1 << 0) /* Bit 0: Socket supports non-blocking
* operation. */
/****************************************************************************
* Public Types
****************************************************************************/
@ -94,11 +99,44 @@ typedef uint16_t sockopt_t;
typedef uint16_t socktimeo_t;
/* This type defines the type of the socket capabilities set */
typedef uint8_t sockcaps_t;
/* This callbacks are socket operations that may be performed on a socket of
* a given address family.
*/
struct socket; /* Forward reference */
struct sock_intf_s
{
CODE int (*si_setup)(FAR struct socket *psock, int protocol);
CODE sockcaps_t (*si_sockcaps)(FAR struct socket *psock);
CODE void (*si_addref)(FAR struct socket *psock);
CODE int (*si_bind)(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
CODE int (*si_listen)(FAR struct socket *psock, int backlog);
CODE int (*si_connect)(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
CODE int (*si_accept)(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen, FAR struct socket *newsock);
CODE ssize_t (*si_send)(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags);
CODE ssize_t (*si_sendto)(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags, FAR const struct sockaddr *to,
socklen_t tolen);
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);
CODE int (*si_close)(FAR struct socket *psock);
};
/* This is the internal representation of a socket reference by a file
* descriptor.
*/
struct devif_callback_s; /* Forward reference */
struct devif_callback_s; /* Forward reference */
struct socket
{
@ -120,6 +158,10 @@ struct socket
FAR void *s_conn; /* Connection: struct tcp_conn_s or udp_conn_s */
/* Socket interface */
FAR const struct sock_intf_s *s_sockif;
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* Callback instance for TCP send */

View file

@ -209,9 +209,8 @@ static void copy_base62(FAR char *dest, int len)
* that full path.
*
* Returned Value:
*
* Upon successful completion, mkstemp() returns an open file descriptor.
* Otherwise, -1 is returned if no suitable file could be created.
* Upon successful completion, mkstemp() returns an open file descriptor.
* Otherwise, -1 is returned if no suitable file could be created.
*
****************************************************************************/
@ -284,6 +283,8 @@ int mkstemp(FAR char *path_template)
return fd;
}
retries--;
}
/* We could not find an unique filename */

View file

@ -224,6 +224,7 @@ void icmpv6_input(FAR struct net_driver_s *dev)
case ICMPV6_ROUTER_ADVERTISE:
{
FAR struct icmpv6_router_advertise_s *adv;
FAR uint8_t *options;
uint16_t pktlen;
uint16_t optlen;
int ndx;
@ -241,14 +242,17 @@ void icmpv6_input(FAR struct net_driver_s *dev)
optlen = ICMPv6_RADV_OPTLEN(pktlen);
/* We need to have a valid router advertisement with a Prefix and
* with the "A" bit set in the flags.
* with the "A" bit set in the flags. Options immediately follow
* the ICMPv6 router advertisement.
*/
adv = ICMPv6RADVERTISE;
adv = ICMPv6RADVERTISE;
options = (FAR uint8_t *)adv + sizeof(struct icmpv6_router_advertise_s);
for (ndx = 0; ndx + sizeof(struct icmpv6_prefixinfo_s) <= optlen; )
{
FAR struct icmpv6_prefixinfo_s *opt =
(FAR struct icmpv6_prefixinfo_s *)&adv->options[ndx];
(FAR struct icmpv6_prefixinfo_s *)&options[ndx];
/* Is this the sought for prefix? Is it the correct size? Is
* the "A" flag set?

View file

@ -39,6 +39,7 @@ ifeq ($(CONFIG_NET_LOCAL),y)
NET_CSRCS += local_conn.c local_release.c local_bind.c local_fifo.c
NET_CSRCS += local_recvfrom.c local_sendpacket.c local_recvutils.c
NET_CSRCS += local_sockif.c
ifeq ($(CONFIG_NET_LOCAL_STREAM),y)
NET_CSRCS += local_connect.c local_listen.c local_accept.c local_send.c

View file

@ -51,6 +51,8 @@
#include <stdint.h>
#include <poll.h>
#include <nuttx/net/net.h>
#ifdef CONFIG_NET_LOCAL
/****************************************************************************
@ -77,6 +79,7 @@
/****************************************************************************
* Public Type Definitions
****************************************************************************/
/* Local, Unix domain socket types */
enum local_type_e
@ -204,6 +207,10 @@ extern "C"
# define EXTERN extern
#endif
/* The local socket interface */
EXTERN const struct sock_intf_s g_local_sockif;
#ifdef CONFIG_NET_LOCAL_STREAM
/* A list of all SOCK_STREAM listener connections */
@ -302,26 +309,31 @@ int local_release(FAR struct local_conn_s *conn);
* Name: local_listen
*
* Description:
* Listen for a new connection of a SOCK_STREAM Unix domain socket.
* 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 local
* Unix sockets, psock_listen() calls this function. The psock_listen()
* call applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET.
*
* This function is called as part of the implementation of listen();
*
* Input Parameters:
* server - A reference to the server-side local connection structure
* backlog - Maximum number of pending connections.
* Parameters:
* psock Reference to an internal, boound 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:
* Zero (OK) on success; a negated errno value on failure.
*
* Assumptions:
* The network is NOT locked
* On success, zero is returned. On error, a negated errno value is
* returned. See list() for the set of appropriate error values.
*
****************************************************************************/
int local_listen(FAR struct local_conn_s *server, int backlog);
int local_listen(FAR struct socket *psock, int backlog);
/****************************************************************************
* Name: psock_local_accept
* Name: local_accept
*
* Description:
* This function implements accept() for Unix domain sockets. See the
@ -343,8 +355,8 @@ int local_listen(FAR struct local_conn_s *server, int backlog);
*
****************************************************************************/
int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen, FAR void **newconn);
int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen, FAR void **newconn);
/****************************************************************************
* Name: psock_local_send
@ -421,7 +433,7 @@ ssize_t psock_local_sendto(FAR struct socket *psock, FAR const void *buf,
int local_send_packet(int fd, FAR const uint8_t *buf, size_t len);
/****************************************************************************
* Name: psock_recvfrom
* Name: local_recvfrom
*
* Description:
* recvfrom() receives messages from a local socket, and may be used to
@ -448,9 +460,9 @@ int local_send_packet(int fd, FAR const uint8_t *buf, size_t len);
*
****************************************************************************/
ssize_t psock_local_recvfrom(FAR struct socket *psock, FAR void *buf,
size_t len, int flags, FAR struct sockaddr *from,
FAR socklen_t *fromlen);
ssize_t local_recvfrom(FAR struct socket *psock, FAR void *buf,
size_t len, int flags, FAR struct sockaddr *from,
FAR socklen_t *fromlen);
/****************************************************************************
* Name: local_fifo_read

View file

@ -88,7 +88,7 @@ static int local_waitlisten(FAR struct local_conn_s *server)
****************************************************************************/
/****************************************************************************
* Name: psock_local_accept
* Name: local_accept
*
* Description:
* This function implements accept() for Unix domain sockets. See the
@ -110,8 +110,8 @@ static int local_waitlisten(FAR struct local_conn_s *server)
*
****************************************************************************/
int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen, FAR void **newconn)
int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen, FAR void **newconn)
{
FAR struct local_conn_s *server;
@ -122,6 +122,18 @@ int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
/* Some sanity checks */
DEBUGASSERT(psock && psock->s_conn);
/* Is the socket a stream? */
if (psock->s_domain != PF_LOCAL || psock->s_type != SOCK_STREAM)
{
return -EOPNOTSUPP;
}
/* Verify that a valid memory block has been provided to receive the
* address
*/
server = (FAR struct local_conn_s *)psock->s_conn;
if (server->lc_proto != SOCK_STREAM ||
@ -213,7 +225,7 @@ int psock_local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
/* Return the address family */
if (addr)
if (addr != NULL)
{
ret = local_getaddr(client, addr, addrlen);
}

View file

@ -66,29 +66,46 @@ dq_queue_t g_local_listeners;
* Name: local_listen
*
* Description:
* Listen for a new connection of a SOCK_STREAM Unix domain socket.
* 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 local
* Unix sockets, psock_listen() calls this function. The psock_listen()
* call applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET.
*
* This function is called as part of the implementation of listen();
*
* Input Parameters:
* server - A reference to the server-side local connection structure
* backlog - Maximum number of pending connections.
* Parameters:
* psock Reference to an internal, boound 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:
* Zero (OK) on success; a negated errno value on failure.
*
* Assumptions:
* The network is NOT locked
* On success, zero is returned. On error, a negated errno value is
* returned. See list() for the set of appropriate error values.
*
****************************************************************************/
int local_listen(FAR struct local_conn_s *server, int backlog)
int local_listen(FAR struct socket *psock, int backlog)
{
FAR struct local_conn_s *server;
/* Verify that the sockfd corresponds to a connected SOCK_STREAM in this
* address family.
*/
if (psock->s_domain != PF_LOCAL || psock->s_type != SOCK_STREAM)
{
nerr("ERROR: Unsupported socket family=%d or socket type=%d\n",
psocl->s_domain, psock->s_type);
return -EOPNOTSUPP;
}
server = (FAR struct local_conn_s *)psock->s_conn;
/* Some sanity checks */
DEBUGASSERT(server);
if (server->lc_proto != SOCK_STREAM ||
server->lc_state == LOCAL_STATE_UNBOUND ||
server->lc_type != LOCAL_TYPE_PATHNAME)

View file

@ -387,11 +387,11 @@ errout_with_halfduplex:
****************************************************************************/
/****************************************************************************
* Name: psock_local_recvfrom
* Name: local_recvfrom
*
* Description:
* psock_local_recvfrom() receives messages from a local socket and may be
* used to receive data on a socket whether or not it is connection-oriented.
* local_recvfrom() receives messages from a local 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
@ -409,14 +409,15 @@ errout_with_halfduplex:
* 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, -1 is returned, and errno
* is set appropriately (see receive from for the complete list).
* recv() will return 0. Otherwise, on errors, a negated errno value is
* returned (see recv_from() for the complete list of appropriate error
* values).
*
****************************************************************************/
ssize_t psock_local_recvfrom(FAR struct socket *psock, FAR void *buf,
size_t len, int flags, FAR struct sockaddr *from,
FAR socklen_t *fromlen)
ssize_t local_recvfrom(FAR struct socket *psock, FAR void *buf,
size_t len, int flags, FAR struct sockaddr *from,
FAR socklen_t *fromlen)
{
DEBUGASSERT(psock && psock->s_conn && buf);

574
net/local/local_sockif.c Normal file
View file

@ -0,0 +1,574 @@
/****************************************************************************
* net/local/local_sockif.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <netinet/in.h>
#include <nuttx/net/net.h>
#include "local/local.h"
#ifdef CONFIG_NET_LOCAL
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int local_setup(FAR struct socket *psock, int protocol);
static sockcaps_t local_sockcaps(FAR struct socket *psock);
static void local_addref(FAR struct socket *psock);
static int local_bind(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
static int local_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
static int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen, FAR struct socket *newsock);
static ssize_t local_send(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags);
static ssize_t local_sendto(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags, FAR const struct sockaddr *to,
socklen_t tolen);
static int local_close(FAR struct socket *psock);
/****************************************************************************
* Public Data
****************************************************************************/
const struct sock_intf_s g_local_sockif =
{
local_setup, /* si_setup */
local_sockcaps, /* si_sockcaps */
local_addref, /* si_addref */
local_bind, /* si_bind */
local_listen, /* si_listen */
local_connect, /* si_connect */
local_accept, /* si_accept */
local_send, /* si_send */
local_sendto, /* si_sendto */
local_recvfrom, /* si_recvfrom */
local_close /* si_close */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: local_sockif_alloc
*
* Description:
* Allocate and attach a local, Unix domain connection structure.
*
****************************************************************************/
static int local_sockif_alloc(FAR struct socket *psock)
{
/* Allocate the local connection structure */
FAR struct local_conn_s *conn = local_alloc();
if (conn == NULL)
{
/* Failed to reserve a connection structure */
return -ENOMEM;
}
/* Set the reference count on the connection structure. This reference
* count will be incremented only if the socket is dup'ed
*/
DEBUGASSERT(conn->lc_crefs == 0);
conn->lc_crefs = 1;
/* Save the pre-allocated connection in the socket structure */
psock->s_conn = conn;
return OK;
}
/****************************************************************************
* Name: local_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.
*
* Parameters:
* psock A pointer to a user allocated socket structure to be initialized.
* protocol (see sys/socket.h)
*
* Returned Value:
* Zero (OK) is returned on success. Otherwise, a negater errno value is
* returned.
*
****************************************************************************/
static int local_setup(FAR struct socket *psock, int protocol)
{
/* Allocate the appropriate connection structure. This reserves the
* the connection structure is is unallocated at this point. It will
* not actually be initialized until the socket is connected.
*
* Only SOCK_STREAM and SOCK_DGRAM and possible SOCK_RAW are supported.
*/
switch (psock->s_type)
{
#ifdef CONFIG_NET_TCP
case SOCK_STREAM:
if (protocol != 0 && protocol != IPPROTO_TCP)
{
return -EPROTONOSUPPORT;
}
/* Allocate and attach the local connection structure */
return local_sockif_alloc(psock);
#endif /* CONFIG_NET_TCP */
#ifdef CONFIG_NET_UDP
case SOCK_DGRAM:
if (protocol != 0 && protocol != IPPROTO_UDP)
{
return -EPROTONOSUPPORT;
}
/* Allocate and attach the local connection structure */
return local_sockif_alloc(psock);
#endif /* CONFIG_NET_UDP */
default:
return -EPROTONOSUPPORT;
}
}
/****************************************************************************
* Name: local_sockcaps
*
* Description:
* Return the bit encoded capabilities of this socket.
*
* Parameters:
* psock - Socket structure of the socket whose capabilities are being
* queried.
*
* Returned Value:
* The set of socket cababilities is returned.
*
****************************************************************************/
static sockcaps_t local_sockcaps(FAR struct socket *psock)
{
return SOCKCAP_NONBLOCKING;
}
/****************************************************************************
* Name: local_addref
*
* Description:
* Increment the refernce count on the underlying connection structure.
*
* Parameters:
* psock - Socket structure of the socket whose reference count will be
* incremented.
*
* Returned Value:
* None
*
****************************************************************************/
static void local_addref(FAR struct socket *psock)
{
FAR struct local_conn_s *conn;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL &&
psock->s_domain == PF_LOCAL);
conn = psock->s_conn;
DEBUGASSERT(conn->lc_crefs > 0 && conn->lc_crefs < 255);
conn->lc_crefs++;
}
/****************************************************************************
* Name: local_bind
*
* Description:
* local_bind() gives the socket 'psock' 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.
*
* Parameters:
* psock Socket structure of the socket to bind
* addr Socket local address
* addrlen Length of 'addr'
*
* Returned Value:
* 0 on success; A negated errno value is returned on failure. See
* bind() for a list a appropriate error values.
*
****************************************************************************/
static int local_bind(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen)
{
int ret;
/* Verify that a valid address has been provided */
if (addr->sa_family != AF_LOCAL || addrlen < sizeof(sa_family_t))
{
nerr("ERROR: Invalid address length: %d < %d\n",
addrlen, sizeof(sa_family_t));
return -EBADF;
}
/* Perform the binding depending on the protocol type */
switch (psock->s_type)
{
/* Bind a local TCP/IP stream or datagram socket */
#if defined(ONFIG_NET_TCP) || defined(CONFIG_NET_UDP)
#ifdef CONFIG_NET_TCP
case SOCK_STREAM:
#endif
#ifdef CONFIG_NET_UDP
case SOCK_DGRAM:
#endif
{
/* Bind the Unix domain connection structure */
ret psock_local_bind(psock, addr, addrlen);
/* Mark the socket bound */
if (ret >= 0)
{
psock->s_flags |= _SF_BOUND;
}
}
break;
#endif /* CONFIG_NET_TCP || CONFIG_NET_UDP*/
default:
ret = -EBADF;
break;
}
return ret;
}
/****************************************************************************
* Name: local_connect
*
* Description:
* local_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
* datagrams are received. If the socket is of type SOCK_STREAM or
* SOCK_SEQPACKET, this call attempts to make a connection to the socket
* that is bound to the address specified by 'addr'.
*
* Generally, connection-based protocol sockets may successfully
* local_connect() only once; connectionless protocol sockets may use
* local_connect() multiple times to change their association.
* Connectionless sockets may dissolve the association by connecting to
* an address with the sa_family member of sockaddr set to AF_UNSPEC.
*
* Parameters:
* psock Pointer to a socket structure initialized by psock_socket()
* addr Server address (form depends on type of socket)
* addrlen Length of actual 'addr'
*
* Returned Value:
* 0 on success; a negated errno value on failue. See connect() for the
* list of appropriate errno values to be returned.
*
****************************************************************************/
static int local_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen)
{
/* Verify that a valid address has been provided */
if (addr->sa_family != AF_LOCAL || addrlen < sizeof(sa_family_t))
{
return -EBADF;
}
/* Perform the connection depending on the protocol type */
switch (psock->s_type)
{
#ifdef CONFIG_NET_TCP
case SOCK_STREAM:
{
/* Verify that the socket is not already connected */
if (_SS_ISCONNECTED(psock->s_flags))
{
return -EISCONN;
}
/* It's not... Connect to the local Unix domain server */
return psock_local_connect(psock, addr);
}
break;
#endif /* CONFIG_NET_TCP */
#ifdef CONFIG_NET_UDP
case SOCK_DGRAM:
{
/* Perform the datagram connection logic */
return psock_local_connect(psock, addr);
}
break;
#endif /* CONFIG_NET_UDP */
default:
return -EBADF;
}
}
/****************************************************************************
* Name: local_send
*
* Description:
* Implements the send() operation for the case of the local, Unix socket.
*
* Parameters:
* psock An instance of the internal socket structure.
* buf Data to send
* len Length of data to send
* flags Send flags
*
* 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 local_send(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags)
{
ssize_t ret;
switch (psock->s_type)
{
#ifdef CONFIG_NET_TCP
case SOCK_STREAM:
{
/* Local TCP packet send */
ret = psock_local_send(psock, buf, len, flags);
}
break;
#endif /* CONFIG_NET_TCP */
#ifdef CONFIG_NET_UDP
case SOCK_DGRAM:
{
/* Local UDP packet send */
#warning Missing logic
ret = -ENOSYS;
}
break;
#endif /* CONFIG_NET_UDP */
default:
{
/* EDESTADDRREQ. Signifies that the socket is not connection-mode
* and no peer address is set.
*/
ret = -EDESTADDRREQ;
}
break;
}
return ret;
}
/****************************************************************************
* Name: local_sendto
*
* Description:
* Implements the sendto() operation for the case of the local, Unix socket.
*
* Parameters:
* psock A pointer to a NuttX-specific, internal socket structure
* buf Data to send
* len Length of data to send
* flags Send flags
* to Address of recipient
* tolen The length of the address structure
*
* Returned Value:
* On success, returns the number of characters sent. On error, a negated
* errno value is returned (see send_to() for the list of appropriate error
* values.
*
****************************************************************************/
ssize_t local_sendto(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags, FAR const struct sockaddr *to,
socklen_t tolen)
{
ssize_t nsent;
/* Verify that a valid address has been provided */
if (to->sa_family != AF_LOCAL || tolen < sizeof(sa_family_t))
{
nerr("ERROR: Unrecognized address family: %d\n",
to->sa_family);
return -EAFNOSUPPORT;
}
#ifdef CONFIG_NET_UDP
/* If this is a connected socket, then return EISCONN */
if (psock->s_type != SOCK_DGRAM)
{
nerr("ERROR: Connected socket\n");
return -EISCONN;
}
/* Now handle the local UDP sendto() operation */
nsent = psock_local_sendto(psock, buf, len, flags, to, tolen);
#else
nsent = -EISCONN;
#endif /* CONFIG_NET_LOCAL_DGRAM */
return nsent;
}
/****************************************************************************
* Name: local_close
*
* Description:
* Performs the close operation on a local, Unix socket instance
*
* Parameters:
* psock Socket instance
*
* Returned Value:
* 0 on success; a negated errno value is returned on any failure.
*
* Assumptions:
*
****************************************************************************/
static int local_close(FAR struct socket *psock)
{
/* Perform some pre-close operations for the local address type */
switch (psock->s_type)
{
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP)
#ifdef CONFIG_NET_TCP
case SOCK_STREAM:
#endif
#ifdef CONFIG_NET_UDP
case SOCK_DGRAM:
#endif
{
FAR struct local_conn_s *conn = psock->s_conn;
/* Is this the last reference to the connection structure (there
* could be more if the socket was dup'ed).
*/
if (conn->lc_crefs <= 1)
{
conn->lc_crefs = 0;
local_release(conn);
}
else
{
/* No.. Just decrement the reference count */
conn->lc_crefs--;
}
return OK;
}
#endif /* CONFIG_NET_TCP || CONFIG_NET_UDP*/
default:
return -EBADF;
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name:
*
* Description:
*
* Parameters:
*
* Returned Value:
*
* Assumptions:
*
****************************************************************************/
#endif /* CONFIG_NET_LOCAL */

View file

@ -39,7 +39,9 @@ ifeq ($(CONFIG_NET_PKT),y)
# Socket layer
SOCK_CSRCS += pkt_sockif.c
SOCK_CSRCS += pkt_send.c
SOCK_CSRCS += pkt_recvfrom.c
# Transport layer

View file

@ -91,12 +91,17 @@ extern "C"
# define EXTERN extern
#endif
/* The packet socket interface */
EXTERN const struct sock_intf_s g_pkt_sockif;
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
struct net_driver_s; /* Forward reference */
struct eth_hdr_s; /* Forward reference */
struct socket; /* Forward reference */
/****************************************************************************
* Name: pkt_initialize()
@ -197,6 +202,41 @@ uint16_t pkt_callback(FAR struct net_driver_s *dev,
/* pkt_input() is prototyped in include/nuttx/net/pkt.h */
/****************************************************************************
* Name: pkt_recvfrom
*
* Description:
* Implements the socket recvfrom interface for the case of the AF_INET
* and AF_INET6 address families. pkt_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' is
* initialized to the size of the buffer associated with from, and
* modified on return to indicate the actual size of the address stored
* there.
*
* 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 pkt_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
int flags, FAR struct sockaddr *from,
FAR socklen_t *fromlen);
/****************************************************************************
* Name: pkt_find_device
*

485
net/pkt/pkt_recvfrom.c Normal file
View file

@ -0,0 +1,485 @@
/****************************************************************************
* net/socket/pkt_recvfrom.c
*
* Copyright (C) 2007-2009, 2011-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#ifdef CONFIG_NET
#include <sys/types.h>
#include <sys/socket.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <debug.h>
#include <assert.h>
#include <arch/irq.h>
#include <nuttx/clock.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include "netdev/netdev.h"
#include "devif/devif.h"
#include "pkt/pkt.h"
#include "socket/socket.h"
#include <netpacket/packet.h>
/****************************************************************************
* Private Types
****************************************************************************/
struct pkt_recvfrom_s
{
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 */
uint8_t *pr_buffer; /* Pointer to receive buffer */
ssize_t pr_recvlen; /* The received length */
int pr_result; /* Success:OK, failure:negated errno */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: pkt_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 .
*
* Parameters:
* pstate recvfrom state structure
* recvlen size of new data appended to buffer
*
* Returned Value:
* None
*
****************************************************************************/
static inline void pkt_add_recvlen(FAR struct pkt_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: pkt_recvfrom_newdata
*
* Description:
* Copy the read data from the packet
*
* Parameters:
* dev The structure of the network driver that caused the interrupt
* pstate recvfrom state structure
*
* Returned Value:
* None.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static void pkt_recvfrom_newdata(FAR struct net_driver_s *dev,
FAR struct pkt_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);
ninfo("Received %d bytes (of %d)\n", (int)recvlen, (int)dev->d_len);
/* Update the accumulated size of the data read */
pkt_add_recvlen(pstate, recvlen);
}
/****************************************************************************
* Name: pkt_recvfrom_sender
*
* Description:
*
* Parameters:
*
* Returned Values:
*
* Assumptions:
*
****************************************************************************/
static inline void pkt_recvfrom_sender(FAR struct net_driver_s *dev,
FAR struct pkt_recvfrom_s *pstate)
{
}
/****************************************************************************
* Name: pkt_recvfrom_interrupt
*
* Description:
*
* Parameters:
*
* Returned Values:
*
* Assumptions:
*
****************************************************************************/
static uint16_t pkt_recvfrom_interrupt(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv,
uint16_t flags)
{
struct pkt_recvfrom_s *pstate = (struct pkt_recvfrom_s *)pvpriv;
ninfo("flags: %04x\n", flags);
/* 'priv' might be null in some race conditions (?) */
if (pstate)
{
/* If a new packet is available, then complete the read action. */
if ((flags & PKT_NEWDATA) != 0)
{
/* Copy the packet */
pkt_recvfrom_newdata(dev, pstate);
/* We are finished. */
ninfo("PKT done\n");
/* Don't allow any further call backs. */
pstate->pr_cb->flags = 0;
pstate->pr_cb->priv = NULL;
pstate->pr_cb->event = NULL;
#if 0
/* Save the sender's address in the caller's 'from' location */
pkt_recvfrom_sender(dev, pstate);
#endif
/* indicate that the data has been consumed */
flags &= ~PKT_NEWDATA;
/* Wake up the waiting thread, returning the number of bytes
* actually read.
*/
sem_post(&pstate->pr_sem);
}
}
return flags;
}
/****************************************************************************
* Name: pkt_recvfrom_initialize
*
* Description:
* Initialize the state structure
*
* Parameters:
* psock Pointer to the socket structure for the socket
* buf Buffer to receive data
* len Length of buffer
* pstate A pointer to the state structure to be initialized
*
* Returned Value:
* None
*
* Assumptions:
*
****************************************************************************/
static void pkt_recvfrom_initialize(FAR struct socket *psock, FAR void *buf,
size_t len, FAR struct sockaddr *infrom,
FAR socklen_t *fromlen,
FAR struct pkt_recvfrom_s *pstate)
{
/* Initialize the state structure. */
memset(pstate, 0, sizeof(struct pkt_recvfrom_s));
/* This semaphore is used for signaling and, hence, should not have
* priority inheritance enabled.
*/
(void)sem_init(&pstate->pr_sem, 0, 0); /* Doesn't really fail */
(void)sem_setprotocol(&pstate->pr_sem, SEM_PRIO_NONE);
pstate->pr_buflen = len;
pstate->pr_buffer = buf;
}
/* The only un-initialization that has to be performed is destroying the
* semaphore.
*/
#define pkt_recvfrom_uninitialize(s) sem_destroy(&(s)->pr_sem)
/****************************************************************************
* Name: pkt_recvfrom_result
*
* Description:
* Evaluate the result of the recv operations
*
* 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 pkt_recvfrom_result(int result, struct pkt_recvfrom_s *pstate)
{
int save_errno = get_errno(); /* In case something we do changes it */
/* Check for a error/timeout detected by the interrupt handler. Errors are
* signaled by negative errno values for the rcv length
*/
if (pstate->pr_result < 0)
{
/* This might return EAGAIN on a timeout or ENOTCONN on loss of
* connection (TCP only)
*/
return pstate->pr_result;
}
/* If net_lockedwait failed, then we were probably reawakened by a signal. In
* this case, net_lockedwait will have set errno appropriately.
*/
if (result < 0)
{
return -save_errno;
}
return pstate->pr_recvlen;
}
/****************************************************************************
* Name: pkt_recvfrom_rxnotify
*
* Description:
* Notify the appropriate device driver that we are ready to receive a
* packet (PKT)
*
* Parameters:
* conn - The PKT connection structure
*
* Returned Value:
* None
*
****************************************************************************/
#if 0 /* Not implemented */
static void pkt_recvfrom_rxnotify(FAR struct pkt_conn_s *conn)
{
# warning Missing logic
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: pkt_recvfrom
*
* Description:
* Implements the socket recvfrom interface for the case of the AF_INET
* and AF_INET6 address families. pkt_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' is
* initialized to the size of the buffer associated with from, and
* modified on return to indicate the actual size of the address stored
* there.
*
* 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 pkt_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
int flags, FAR struct sockaddr *from,
FAR socklen_t *fromlen)
{
FAR struct pkt_conn_s *conn = (FAR struct pkt_conn_s *)psock->s_conn;
FAR struct net_driver_s *dev;
struct pkt_recvfrom_s state;
ssize_t ret;
/* If a 'from' address has been provided, verify that it is large
* enough to hold this address family.
*/
if (from != NULL && *fromlen < sizeof(sa_family_t))
{
return -EINVAL;
}
if (psock->s_type != SOCK_RAW)
{
nerr("ERROR: Unsupported socket type: %d\n", psock->s_type);
ret = -ENOSYS;
}
/* Perform the packet recvfrom() operation */
/* Initialize the state structure. This is done with interrupts
* disabled because we don't want anything to happen until we
* are ready.
*/
net_lock();
pkt_recvfrom_initialize(psock, buf, len, from, fromlen, &state);
/* Get the device driver that will service this transfer */
dev = pkt_find_device(conn);
if (dev == NULL)
{
ret = -ENODEV;
goto errout_with_state;
}
/* TODO pkt_recvfrom_initialize() expects from to be of type sockaddr_in, but
* in our case is sockaddr_ll
*/
#if 0
ret = pkt_connect(conn, NULL);
if (ret < 0)
{
goto errout_with_state;
}
#endif
/* Set the socket state to receiving */
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV);
/* Set up the callback in the connection */
state.pr_cb = pkt_callback_alloc(dev, conn);
if (state.pr_cb)
{
state.pr_cb->flags = (PKT_NEWDATA | PKT_POLL);
state.pr_cb->priv = (FAR void *)&state;
state.pr_cb->event = pkt_recvfrom_interrupt;
/* Notify the device driver of the receive call */
#if 0 /* Not implemented */
pkt_recvfrom_rxnotify(conn);
#endif
/* 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)
* interrupts are disabled! They will be re-enabled while the task sleeps
* and automatically re-enabled when the task restarts.
*/
ret = net_lockedwait(&state.pr_sem);
/* Make sure that no further interrupts are processed */
pkt_callback_free(dev, conn, state.pr_cb);
ret = pkt_recvfrom_result(ret, &state);
}
else
{
ret = -EBUSY;
}
/* Set the socket state to idle */
psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);
errout_with_state:
net_unlock();
pkt_recvfrom_uninitialize(&state);
return ret;
}
#endif /* CONFIG_NET */

551
net/pkt/pkt_sockif.c Normal file
View file

@ -0,0 +1,551 @@
/****************************************************************************
* net/socket/pkt_sockif.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/net/net.h>
#include "pkt/pkt.h"
#ifdef CONFIG_NET_PKT
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int pkt_setup(FAR struct socket *psock, int protocol);
static sockcaps_t pkt_sockcaps(FAR struct socket *psock);
static void pkt_addref(FAR struct socket *psock);
static int pkt_bind(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
static int pkt_listen(FAR struct socket *psock, int backlog);
static int pkt_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen);
static int pkt_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen, FAR struct socket *newsock);
static ssize_t pkt_send(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags);
static ssize_t pkt_sendto(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags, FAR const struct sockaddr *to,
socklen_t tolen);
static int pkt_close(FAR struct socket *psock);
/****************************************************************************
* Public Data
****************************************************************************/
const struct sock_intf_s g_pkt_sockif =
{
pkt_setup, /* si_setup */
pkt_sockcaps, /* si_sockcaps */
pkt_addref, /* si_addref */
pkt_bind, /* si_bind */
pkt_listen, /* si_listen */
pkt_connect, /* si_connect */
pkt_accept, /* si_accept */
pkt_send, /* si_send */
pkt_sendto, /* si_sendto */
pkt_recvfrom, /* si_recvfrom */
pkt_close /* si_close */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: pkt_sockif_alloc
*
* Description:
* Allocate and attach a raw packet connection structure.
*
****************************************************************************/
static int pkt_sockif_alloc(FAR struct socket *psock)
{
/* Allocate the packet socket connection structure and save in the new
* socket instance.
*/
FAR struct pkt_conn_s *conn = pkt_alloc();
if (conn == NULL)
{
/* Failed to reserve a connection structure */
return -ENOMEM;
}
/* Set the reference count on the connection structure. This reference
* count will be incremented only if the socket is dup'ed
*/
DEBUGASSERT(conn->crefs == 0);
conn->crefs = 1;
/* Save the pre-allocated connection in the socket structure */
psock->s_conn = conn;
return OK;
}
/****************************************************************************
* Name: pkt_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.
*
* Parameters:
* psock A pointer to a user allocated socket structure to be
* initialized.
* protocol (see sys/socket.h)
*
* Returned Value:
* Zero (OK) is returned on success. Otherwise, a negater errno value is
* returned.
*
****************************************************************************/
static int pkt_setup(FAR struct socket *psock, int protocol)
{
/* Allocate the appropriate connection structure. This reserves the
* the connection structure is is unallocated at this point. It will
* not actually be initialized until the socket is connected.
*
* Only SOCK_RAW is supported.
*/
if (psock->s_type == SOCK_RAW)
{
return pkt_sockif_alloc(psock);
}
else
{
return -EPROTONOSUPPORT;
}
}
/****************************************************************************
* Name: pkt_sockcaps
*
* Description:
* Return the bit encoded capabilities of this socket.
*
* Parameters:
* psock - Socket structure of the socket whose capabilities are being
* queried.
*
* Returned Value:
* The set of socket cababilities is returned.
*
****************************************************************************/
static sockcaps_t pkt_sockcaps(FAR struct socket *psock)
{
return 0;
}
/****************************************************************************
* Name: pkt_addref
*
* Description:
* Increment the refernce count on the underlying connection structure.
*
* Parameters:
* psock - Socket structure of the socket whose reference count will be
* incremented.
*
* Returned Value:
* None
*
****************************************************************************/
static void pkt_addref(FAR struct socket *psock)
{
FAR struct pkt_conn_s *conn;
DEBUGASSERT(psock != NULL && psock->s_conn != NULL &&
psock->s_type == SOCK_RAW);
conn = psock->s_conn;
DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255);
conn->crefs++;
}
/****************************************************************************
* Name: pkt_connect
*
* Description:
* pkt_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
* datagrams are received. If the socket is of type SOCK_STREAM or
* SOCK_SEQPACKET, this call attempts to make a connection to the socket
* that is bound to the address specified by 'addr'.
*
* Generally, connection-based protocol sockets may successfully
* pkt_connect() only once; connectionless protocol sockets may use
* pkt_connect() multiple times to change their association.
* Connectionless sockets may dissolve the association by connecting to
* an address with the sa_family member of sockaddr set to AF_UNSPEC.
*
* Parameters:
* psock Pointer to a socket structure initialized by psock_socket()
* addr Server address (form depends on type of socket)
* addrlen Length of actual 'addr'
*
* Returned Value:
* 0 on success; a negated errno value on failue. See connect() for the
* list of appropriate errno values to be returned.
*
****************************************************************************/
static int pkt_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr, socklen_t addrlen)
{
return -EAFNOSUPPORT;
}
/****************************************************************************
* Name: pkt_accept
*
* Description:
* The pkt_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 pkt_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, pkt_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, pkt_accept returns
* EAGAIN.
*
* 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'
* 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 desrciption of the approriate error value.
*
****************************************************************************/
static int pkt_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen, FAR struct socket *newsock)
{
return -EAFNOSUPPORT;
}
/****************************************************************************
* Name: pkt_bind
*
* Description:
* pkt_bind() gives the socket 'psock' 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.
*
* Parameters:
* psock Socket structure of the socket to bind
* addr Socket local address
* addrlen Length of 'addr'
*
* Returned Value:
* 0 on success; A negated errno value is returned on failure. See
* bind() for a list a appropriate error values.
*
****************************************************************************/
static int pkt_bind(FAR struct socket *psock, FAR const struct sockaddr *addr,
socklen_t addrlen)
{
#if 0
char hwaddr[6] = /* our MAC for debugging */
{
0x00, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1
};
#endif
char hwaddr[6] = /* MAC from ifconfig */
{
0x00, 0xe0, 0xde, 0xad, 0xbe, 0xef
};
int ifindex;
/* Verify that a valid address has been provided */
if (addr->sa_family != AF_PACKET || addrlen < sizeof(struct sockaddr_ll)
{
nerr("ERROR: Invalid address length: %d < %d\n",
addrlen, sizeof(struct sockaddr_ll);
return -EBADF;
}
/* Bind a raw socket to an network device. */
if (psock->s_type == SOCK_RAW)
{
FAR struct pkt_conn_s *conn = (FAR struct pkt_conn_s *)psock->s_conn;
/* Look at the addr and identify network interface */
ifindex = addr->sll_ifindex;
#if 0
/* Get the MAC address of that interface */
memcpy(hwaddr, g_netdevices->d_mac.ether, 6);
#endif
/* Put ifindex and mac address into connection */
conn->ifindex = ifindex;
memcpy(conn->lmac, hwaddr, 6);
/* Mark the socket bound */
psock->s_flags |= _SF_BOUND;
return OK;
}
else
{
return -EBADF;
}
}
/****************************************************************************
* Name: pkt_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 raw
* packet sockets, psock_listen() calls this function. The psock_listen()
* call applies only to sockets of type SOCK_STREAM or SOCK_SEQPACKET.
*
* Parameters:
* psock Reference to an internal, boound 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.
*
****************************************************************************/
int pkt_listen(FAR struct socket *psock, int backlog)
{
return -EOPNOTSUPP;
}
/****************************************************************************
* Name: pkt_send
*
* Description:
* Socket send() method for the raw packet socket.
*
* Parameters:
* psock An instance of the internal socket structure.
* buf Data to send
* len Length of data to send
* flags Send flags
*
* 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 pkt_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_pkt_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: pkt_sendto
*
* Description:
* Implements the sendto() operation for the case of the raw packet socket.
*
* Parameters:
* psock A pointer to a NuttX-specific, internal socket structure
* buf Data to send
* len Length of data to send
* flags Send flags
* to Address of recipient
* tolen The length of the address structure
*
* Returned Value:
* On success, returns the number of characters sent. On error, a negated
* errno value is returned (see send_to() for the list of appropriate error
* values.
*
****************************************************************************/
static ssize_t pkt_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: pkt_close
*
* Description:
* Performs the close operation on a raw packet socket instance
*
* Parameters:
* psock Socket instance
*
* Returned Value:
* 0 on success; a negated errno value is returned on any failure.
*
* Assumptions:
*
****************************************************************************/
static int pkt_close(FAR struct socket *psock)
{
/* Perform some pre-close operations for the raw packet address type */
switch (psock->s_type)
{
case SOCK_RAW:
{
FAR struct pkt_conn_s *conn = psock->s_conn;
/* Is this the last reference to the connection structure (there
* could be more if the socket was dup'ed).
*/
if (conn->crefs <= 1)
{
/* Yes... free the connection structure */
conn->crefs = 0; /* No more references on the connection */
pkt_free(psock->s_conn); /* Free network resources */
}
else
{
/* No.. Just decrement the reference count */
conn->crefs--;
}
return OK;
}
#endif
default:
return -EBADF;
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name:
*
* Description:
*
* Parameters:
*
* Returned Value:
*
* Assumptions:
*
****************************************************************************/
#endif /* CONFIG_NET_PKT */

View file

@ -1,7 +1,7 @@
############################################################################
# net/socket/Make.defs
#
# Copyright (C) 2014-2015 Gregory Nutt. All rights reserved.
# Copyright (C) 2014-2015, 2017 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# Redistribution and use in source and binary forms, with or without
@ -39,6 +39,16 @@ SOCK_CSRCS += bind.c connect.c getsockname.c recv.c recvfrom.c send.c
SOCK_CSRCS += sendto.c socket.c net_sockets.c net_close.c net_dupsd.c
SOCK_CSRCS += net_dupsd2.c net_clone.c net_poll.c net_vfcntl.c
# Socket address families
SOCK_CSRCS += net_sockif.c
ifeq ($(CONFIG_NET_IPv4),y)
SOCK_CSRCS += inet_sockif.c inet_recvfrom.c inet_connect.c inet_close.c
else ifeq ($(CONFIG_NET_IPv6),y)
SOCK_CSRCS += inet_sockif.c inet_recvfrom.c inet_connect.c inet_close.c
endif
# TCP/IP support
ifeq ($(CONFIG_NET_TCP),y)

View file

@ -38,8 +38,6 @@
****************************************************************************/
#include <nuttx/config.h>
#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 && \
(defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM))
#include <sys/types.h>
#include <sys/socket.h>
@ -56,6 +54,8 @@
#include "socket/socket.h"
#include "usrsock/usrsock.h"
#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0
/****************************************************************************
* Public Functions
****************************************************************************/
@ -115,8 +115,7 @@
* ENFILE
* The system maximum for file descriptors has been reached.
* EFAULT
* The addr parameter is not in a writable part of the user address
* space.
* The addr parameter is not in a writable part of the user address space.
* ENOBUFS or ENOMEM
* Not enough free memory.
* EPROTO
@ -130,29 +129,20 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen, FAR struct socket *newsock)
{
int errcode;
#if defined(NET_TCP_HAVE_STACK) || defined(CONFIG_NET_LOCAL_STREAM)
int ret;
#endif
DEBUGASSERT(psock != NULL);
DEBUGASSERT(psock != NULL && psock->s_conn != NULL && newsock != NULL);
/* Treat as a cancellation point */
(void)enter_cancellation_point();
/* Is the socket a stream? */
/* May sure that the socket has been opened with socket() */
if (psock->s_type != SOCK_STREAM)
if (psock == NULL || psock->s_conn == NULL)
{
#ifdef CONFIG_NET_USRSOCK
if (psock->s_type == SOCK_USRSOCK_TYPE)
{
#warning "Missing logic"
}
#endif
errcode = EOPNOTSUPP;
goto errout;
nerr("ERROR: Socket invalid or not opened\n");
return -EINVAL;
}
/* Is the socket listening for a connection? */
@ -163,127 +153,16 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
goto errout;
}
/* Verify that a valid memory block has been provided to receive the
* address
*/
/* Let the address family's accept() method handle the operation */
if (addr)
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_accept != NULL);
ret = psock->s_sockif->si_accept(psock, addr, addrlen, newsock);
if (ret < 0)
{
/* If an address is provided, then the length must also be provided. */
DEBUGASSERT(addrlen);
/* A valid length depends on the address domain */
switch (psock->s_domain)
{
#ifdef CONFIG_NET_IPv4
case PF_INET:
{
if (*addrlen < sizeof(struct sockaddr_in))
{
errcode = EBADF;
goto errout;
}
}
break;
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
case PF_INET6:
{
if (*addrlen < sizeof(struct sockaddr_in6))
{
errcode = EBADF;
goto errout;
}
}
break;
#endif /* CONFIG_NET_IPv6 */
#ifdef CONFIG_NET_LOCAL_STREAM
case PF_LOCAL:
{
if (*addrlen < sizeof(sa_family_t))
{
errcode = EBADF;
goto errout;
}
}
break;
#endif /* CONFIG_NET_IPv6 */
default:
DEBUGPANIC();
errcode = EINVAL;
goto errout;
}
}
/* Initialize the socket structure. */
newsock->s_domain = psock->s_domain;
newsock->s_type = SOCK_STREAM;
/* Perform the correct accept operation for this address domain */
#ifdef CONFIG_NET_LOCAL_STREAM
#ifdef CONFIG_NET_TCP
if (psock->s_domain == PF_LOCAL)
#endif
{
/* Perform the local accept operation (with the network unlocked) */
ret = psock_local_accept(psock, addr, addrlen, &newsock->s_conn);
if (ret < 0)
{
errcode = -ret;
goto errout;
}
}
#endif /* CONFIG_NET_LOCAL_STREAM */
#ifdef CONFIG_NET_TCP
#ifdef CONFIG_NET_LOCAL_STREAM
else
#endif
{
#ifdef NET_TCP_HAVE_STACK
/* Perform the local accept operation (with the network locked) */
net_lock();
ret = psock_tcp_accept(psock, addr, addrlen, &newsock->s_conn);
if (ret < 0)
{
net_unlock();
errcode = -ret;
goto errout;
}
/* Begin monitoring for TCP connection events on the newly connected
* socket
*/
ret = net_startmonitor(newsock);
if (ret < 0)
{
/* net_startmonitor() can only fail on certain race conditions
* where the connection was lost just before this function was
* called. Undo everything we have done and return a failure.
*/
net_unlock();
errcode = -ret;
goto errout_after_accept;
}
net_unlock();
#else
errcode = EOPNOTSUPP;
nerr("ERROR: si_accept failed: %d\n", ret);
errcode = -ret;
goto errout;
#endif /* NET_TCP_HAVE_STACK */
}
#endif /* CONFIG_NET_TCP */
/* Mark the new socket as connected. */
@ -293,11 +172,6 @@ int psock_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
leave_cancellation_point();
return OK;
#ifdef NET_TCP_HAVE_STACK
errout_after_accept:
psock_close(newsock);
#endif
errout:
set_errno(errcode);
leave_cancellation_point();
@ -447,4 +321,4 @@ errout:
return ERROR;
}
#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS && (CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM) */
#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS */

View file

@ -1,7 +1,7 @@
/****************************************************************************
* net/socket/bind.c
*
* Copyright (C) 2007-2009, 2012, 2014-2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2012, 2014-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -38,85 +38,23 @@
****************************************************************************/
#include <nuttx/config.h>
#ifdef CONFIG_NET
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <string.h>
#include <debug.h>
#include <assert.h>
#ifdef CONFIG_NET_PKT
# include <netpacket/packet.h>
#endif
#include <errno.h>
#include <debug.h>
#include <nuttx/net/net.h>
#include <nuttx/net/udp.h>
#include "socket/socket.h"
#include "netdev/netdev.h"
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "pkt/pkt.h"
#include "local/local.h"
#include "usrsock/usrsock.h"
#ifdef CONFIG_NET
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: pkt_bind
*
* Description:
* Bind a raw socket to an network device.
*
* Parameters:
* conn AF_PACKET connection structure
* addr Peer address information
*
* Returned Value:
* 0 on success; -1 on error with errno set appropriately
*
****************************************************************************/
#ifdef CONFIG_NET_PKT
static int pkt_bind(FAR struct pkt_conn_s *conn,
FAR const struct sockaddr_ll *addr)
{
int ifindex;
#if 0
char hwaddr[6] = /* our MAC for debugging */
{
0x00, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1
};
#endif
char hwaddr[6] = /* MAC from ifconfig */
{
0x00, 0xe0, 0xde, 0xad, 0xbe, 0xef
};
/* Look at the addr and identify network interface */
ifindex = addr->sll_ifindex;
#if 0
/* Get the MAC address of that interface */
memcpy(hwaddr, g_netdevices->d_mac.ether, 6);
#endif
/* Put ifindex and mac address into connection */
conn->ifindex = ifindex;
memcpy(conn->lmac, hwaddr, 6);
return OK;
}
#endif /* CONFIG_NET_PKT */
/****************************************************************************
* Public Functions
****************************************************************************/
@ -157,7 +95,6 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr,
#ifdef CONFIG_NET_PKT
FAR const struct sockaddr_ll *lladdr = (const struct sockaddr_ll *)addr;
#endif
socklen_t minlen;
int errcode;
int ret = OK;
@ -169,165 +106,10 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr,
goto errout;
}
/* Verify that a valid address has been provided */
/* Let the address family's connect() method handle the operation */
switch (addr->sa_family)
{
#ifdef CONFIG_NET_IPv4
case AF_INET:
minlen = sizeof(struct sockaddr_in);
break;
#endif
#ifdef CONFIG_NET_IPv6
case AF_INET6:
minlen = sizeof(struct sockaddr_in6);
break;
#endif
#ifdef CONFIG_NET_LOCAL
case AF_LOCAL:
minlen = sizeof(sa_family_t);
break;
#endif
#ifdef CONFIG_NET_PKT
case AF_PACKET:
minlen = sizeof(struct sockaddr_ll);
break;
#endif
default:
nerr("ERROR: Unrecognized address family: %d\n", addr->sa_family);
errcode = EAFNOSUPPORT;
goto errout;
}
if (addrlen < minlen)
{
nerr("ERROR: Invalid address length: %d < %d\n", addrlen, minlen);
errcode = EBADF;
goto errout;
}
/* Perform the binding depending on the protocol type */
switch (psock->s_type)
{
#ifdef CONFIG_NET_USRSOCK
case SOCK_USRSOCK_TYPE:
{
FAR struct usrsock_conn_s *conn = psock->s_conn;
DEBUGASSERT(conn);
/* Perform the usrsock bind operation */
ret = usrsock_bind(conn, addr, addrlen);
}
break;
#endif
#ifdef CONFIG_NET_PKT
case SOCK_RAW:
ret = pkt_bind(psock->s_conn, lladdr);
break;
#endif
/* Bind a stream socket which may either be TCP/IP or a local, Unix
* domain socket.
*/
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM)
case SOCK_STREAM:
{
#ifdef CONFIG_NET_LOCAL_STREAM
#ifdef CONFIG_NET_TCP
/* Is this a Unix domain socket? */
if (psock->s_domain == PF_LOCAL)
#endif
{
/* Bind the Unix domain connection structure */
ret = psock_local_bind(psock, addr, addrlen);
}
#endif /* CONFIG_NET_LOCAL_STREAM */
#ifdef CONFIG_NET_TCP
#ifdef CONFIG_NET_LOCAL_STREAM
else
#endif
{
#ifdef NET_TCP_HAVE_STACK
/* Bind the TCP/IP connection structure */
ret = tcp_bind(psock->s_conn, addr);
#else
ret = -ENOSYS;
#endif
}
#endif /* CONFIG_NET_TCP */
/* Mark the socket bound */
if (ret >= 0)
{
psock->s_flags |= _SF_BOUND;
}
}
break;
#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */
/* Bind a datagram socket which may either be TCP/IP or a local, Unix
* domain socket.
*/
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM)
case SOCK_DGRAM:
{
#ifdef CONFIG_NET_LOCAL_DGRAM
#ifdef CONFIG_NET_UDP
/* Is this a Unix domain socket? */
if (psock->s_domain == PF_LOCAL)
#endif
{
/* Bind the Unix domain connection structure */
ret = psock_local_bind(psock, addr, addrlen);
}
#endif /* CONFIG_NET_LOCAL_DGRAM */
#ifdef CONFIG_NET_UDP
#ifdef CONFIG_NET_LOCAL_DGRAM
else
#endif
{
#ifdef NET_UDP_HAVE_STACK
/* Bind the UDPP/IP connection structure */
ret = udp_bind(psock->s_conn, addr);
#else
ret = -ENOSYS;
#endif
}
#endif /* CONFIG_NET_UDP */
/* Mark the socket bound */
if (ret >= 0)
{
psock->s_flags |= _SF_BOUND;
}
}
break;
#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */
default:
errcode = EBADF;
goto errout;
}
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_bind != NULL);
ret = psock->s_sockif->si_bind(psock, addr, addrlen);
/* Was the bind successful */

View file

@ -38,7 +38,6 @@
****************************************************************************/
#include <nuttx/config.h>
#ifdef CONFIG_NET
#include <sys/types.h>
#include <sys/socket.h>
@ -48,398 +47,17 @@
#include <assert.h>
#include <debug.h>
#include <arch/irq.h>
#include <nuttx/semaphore.h>
#include <nuttx/cancelpt.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/udp.h>
#include <nuttx/net/tcp.h>
#include "devif/devif.h"
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "local/local.h"
#include "socket/socket.h"
#include "usrsock/usrsock.h"
/****************************************************************************
* Private Types
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
struct tcp_connect_s
{
FAR struct tcp_conn_s *tc_conn; /* Reference to TCP connection structure */
FAR struct devif_callback_s *tc_cb; /* Reference to callback instance */
FAR struct socket *tc_psock; /* The socket being connected */
sem_t tc_sem; /* Semaphore signals recv completion */
int tc_result; /* OK on success, otherwise a negated errno. */
};
#endif
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static inline int psock_setup_callbacks(FAR struct socket *psock,
FAR struct tcp_connect_s *pstate);
static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate,
int status);
static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv,
uint16_t flags);
static inline int psock_tcp_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr);
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: psock_setup_callbacks
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static inline int psock_setup_callbacks(FAR struct socket *psock,
FAR struct tcp_connect_s *pstate)
{
FAR struct tcp_conn_s *conn = psock->s_conn;
int ret = -EBUSY;
/* Initialize the TCP state structure */
/* This semaphore is used for signaling and, hence, should not have
* priority inheritance enabled.
*/
(void)sem_init(&pstate->tc_sem, 0, 0); /* Doesn't really fail */
(void)sem_setprotocol(&pstate->tc_sem, SEM_PRIO_NONE);
pstate->tc_conn = conn;
pstate->tc_psock = psock;
pstate->tc_result = -EAGAIN;
/* Set up the callbacks in the connection */
pstate->tc_cb = tcp_callback_alloc(conn);
if (pstate->tc_cb)
{
/* Set up the connection "interrupt" handler */
pstate->tc_cb->flags = (TCP_NEWDATA | TCP_CLOSE | TCP_ABORT |
TCP_TIMEDOUT | TCP_CONNECTED | NETDEV_DOWN);
pstate->tc_cb->priv = (FAR void *)pstate;
pstate->tc_cb->event = psock_connect_interrupt;
ret = OK;
}
return ret;
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: psock_teardown_callbacks
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate,
int status)
{
FAR struct tcp_conn_s *conn = pstate->tc_conn;
/* Make sure that no further interrupts are processed */
tcp_callback_free(conn, pstate->tc_cb);
pstate->tc_cb = NULL;
/* If we successfully connected, we will continue to monitor the connection
* state via callbacks.
*/
if (status < 0)
{
/* Failed to connect. Stop the connection event monitor */
net_stopmonitor(conn);
}
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: psock_connect_interrupt
*
* Description:
* This function is called from the interrupt level to perform the actual
* connection operation via by the lower, device interfacing layer.
*
* Parameters:
* dev The structure of the network driver that caused the interrupt
* pvconn The connection structure associated with the socket
* flags Set of events describing why the callback was invoked
*
* Returned Value:
* The new flags setting
*
* Assumptions:
* Running at the interrupt level
*
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv,
uint16_t flags)
{
struct tcp_connect_s *pstate = (struct tcp_connect_s *)pvpriv;
ninfo("flags: %04x\n", flags);
/* 'priv' might be null in some race conditions (?) */
if (pstate)
{
/* The following errors should be detected here (someday)
*
* ECONNREFUSED
* No one listening on the remote address.
* ENETUNREACH
* Network is unreachable.
* ETIMEDOUT
* Timeout while attempting connection. The server may be too busy
* to accept new connections.
*/
/* TCP_CLOSE: The remote host has closed the connection
* TCP_ABORT: The remote host has aborted the connection
*/
if ((flags & (TCP_CLOSE | TCP_ABORT)) != 0)
{
/* Indicate that remote host refused the connection */
pstate->tc_result = -ECONNREFUSED;
}
/* TCP_TIMEDOUT: Connection aborted due to too many retransmissions. */
else if ((flags & TCP_TIMEDOUT) != 0)
{
/* Indicate that the connection timedout?) */
pstate->tc_result = -ETIMEDOUT;
}
else if ((flags & NETDEV_DOWN) != 0)
{
/* The network device went down. Indicate that the remote host
* is unreachable.
*/
pstate->tc_result = -ENETUNREACH;
}
/* TCP_CONNECTED: The socket is successfully connected */
else if ((flags & TCP_CONNECTED) != 0)
{
FAR struct socket *psock = pstate->tc_psock;
DEBUGASSERT(psock);
/* Mark the connection bound and connected. NOTE this is
* is done here (vs. later) in order to avoid any race condition
* in the socket state. It is known to connected here and now,
* but not necessarily at any time later.
*/
psock->s_flags |= (_SF_BOUND | _SF_CONNECTED);
/* Indicate that the socket is no longer connected */
pstate->tc_result = OK;
}
/* Otherwise, it is not an event of importance to us at the moment */
else
{
/* Drop data received in this state */
dev->d_len = 0;
return flags & ~TCP_NEWDATA;
}
ninfo("Resuming: %d\n", pstate->tc_result);
/* Stop further callbacks */
psock_teardown_callbacks(pstate, pstate->tc_result);
#ifdef CONFIG_NET_MULTILINK
/* When we set up the connection structure, we did not know the size
* of the initial MSS. Now that the connection is associated with a
* network device, we now know the size of link layer header and can
* determine the correct initial MSS.
*/
DEBUGASSERT(pstate->tc_conn);
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (pstate->tc_conn->domain == PF_INET)
#endif
{
pstate->tc_conn->mss = TCP_IPv4_INITIAL_MSS(dev);
}
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
{
pstate->tc_conn->mss = TCP_IPv6_INITIAL_MSS(dev);
}
#endif /* CONFIG_NET_IPv6 */
#ifdef CONFIG_NETDEV_MULTINIC
/* We now have to filter all outgoing transfers so that they use only
* the MSS of this device.
*/
DEBUGASSERT(pstate->tc_conn->dev == NULL ||
pstate->tc_conn->dev == dev);
pstate->tc_conn->dev = dev;
#endif /* CONFIG_NETDEV_MULTINIC */
#endif /* CONFIG_NET_MULTILINK */
/* Wake up the waiting thread */
sem_post(&pstate->tc_sem);
}
return flags;
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: psock_tcp_connect
*
* Description:
* Perform a TCP connection
*
* Parameters:
* psock - A reference to the socket structure of the socket to be connected
* addr - The address of the remote server to connect to
*
* Returned Value:
* None
*
* Assumptions:
* Running at the interrupt level
*
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static inline int psock_tcp_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr)
{
struct tcp_connect_s state;
int ret = OK;
/* Interrupts must be disabled through all of the following because
* we cannot allow the network callback to occur until we are completely
* setup.
*/
net_lock();
/* Get the connection reference from the socket */
if (!psock->s_conn) /* Should always be non-NULL */
{
ret = -EINVAL;
}
else
{
/* Perform the TCP connection operation */
ret = tcp_connect(psock->s_conn, addr);
}
if (ret >= 0)
{
/* Set up the callbacks in the connection */
ret = psock_setup_callbacks(psock, &state);
if (ret >= 0)
{
/* Wait for either the connect to complete or for an error/timeout
* to occur. NOTES: (1) net_lockedwait will also terminate if a signal
* is received, (2) interrupts may be disabled! They will be re-
* enabled while the task sleeps and automatically re-disabled
* when the task restarts.
*/
ret = net_lockedwait(&state.tc_sem);
/* Uninitialize the state structure */
(void)sem_destroy(&state.tc_sem);
/* If net_lockedwait failed, recover the negated error (probably -EINTR) */
if (ret < 0)
{
ret = -get_errno();
}
else
{
/* If the wait succeeded, then get the new error value from
* the state structure
*/
ret = state.tc_result;
}
/* Make sure that no further interrupts are processed */
psock_teardown_callbacks(&state, ret);
}
/* Check if the socket was successfully connected. */
if (ret >= 0)
{
/* Yes... Now that we are connected, we need to set up to monitor
* the state of the connection up the connection event monitor.
*/
ret = net_startmonitor(psock);
if (ret < 0)
{
/* net_startmonitor() can only fail on certain race
* conditions where the connection was lost just before
* this function was called. That is not expected to
* happen in this context, but just in case...
*/
net_lostconnection(psock, TCP_ABORT);
}
}
}
net_unlock();
return ret;
}
#endif /* NET_TCP_HAVE_STACK */
#ifdef CONFIG_NET
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: psock_connect
*
@ -512,12 +130,8 @@ static inline int psock_tcp_connect(FAR struct socket *psock,
int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
socklen_t addrlen)
{
FAR const struct sockaddr_in *inaddr = (FAR const struct sockaddr_in *)addr;
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) || \
defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_USRSOCK)
int ret;
#endif
int errcode;
int ret;
/* Treat as a cancellation point */
@ -525,179 +139,22 @@ int psock_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
/* Verify that the psock corresponds to valid, allocated socket */
if (!psock || psock->s_crefs <= 0)
if (psock == NULL || psock->s_crefs <= 0)
{
errcode = EBADF;
goto errout;
}
/* Verify that a valid address has been provided */
/* Let the address family's connect() method handle the operation */
switch (inaddr->sin_family)
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_connect != NULL);
ret = psock->s_sockif->si_connect(psock, addr, addrlen);
if (ret < 0)
{
#ifdef CONFIG_NET_IPv4
case AF_INET:
{
if (addrlen < sizeof(struct sockaddr_in))
{
errcode = EBADF;
goto errout;
}
}
break;
#endif
#ifdef CONFIG_NET_IPv6
case AF_INET6:
{
if (addrlen < sizeof(struct sockaddr_in6))
{
errcode = EBADF;
goto errout;
}
}
break;
#endif
#ifdef CONFIG_NET_LOCAL
case AF_LOCAL:
{
if (addrlen < sizeof(sa_family_t))
{
errcode = EBADF;
goto errout;
}
}
break;
#endif
default:
#ifdef CONFIG_NET_USRSOCK
if (psock->s_type == SOCK_USRSOCK_TYPE)
{
break;
}
#endif
DEBUGPANIC();
errcode = EAFNOSUPPORT;
errcode = -ret;
goto errout;
}
/* Perform the connection depending on the protocol type */
switch (psock->s_type)
{
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM)
case SOCK_STREAM:
{
/* Verify that the socket is not already connected */
if (_SS_ISCONNECTED(psock->s_flags))
{
errcode = EISCONN;
goto errout;
}
/* It's not ... connect it */
#ifdef CONFIG_NET_LOCAL_STREAM
#ifdef CONFIG_NET_TCP
if (psock->s_domain == PF_LOCAL)
#endif
{
/* Connect to the local Unix domain server */
ret = psock_local_connect(psock, addr);
}
#endif /* CONFIG_NET_LOCAL_STREAM */
#ifdef CONFIG_NET_TCP
#ifdef CONFIG_NET_LOCAL_STREAM
else
#endif
{
#ifdef NET_TCP_HAVE_STACK
/* Connect the TCP/IP socket */
ret = psock_tcp_connect(psock, addr);
#else
ret = -ENOSYS;
#endif
}
#endif /* CONFIG_NET_TCP */
if (ret < 0)
{
errcode = -ret;
goto errout;
}
}
break;
#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM)
case SOCK_DGRAM:
{
#ifdef CONFIG_NET_LOCAL_DGRAM
#ifdef CONFIG_NET_UDP
if (psock->s_domain == PF_LOCAL)
#endif
{
/* Perform the datagram connection logic */
ret = psock_local_connect(psock, addr);
}
#endif /* CONFIG_NET_LOCAL_DGRAM */
#ifdef CONFIG_NET_UDP
#ifdef CONFIG_NET_LOCAL_DGRAM
else
#endif
{
#ifdef NET_UDP_HAVE_STACK
ret = udp_connect(psock->s_conn, addr);
if (ret < 0 || addr == NULL)
{
psock->s_flags &= ~_SF_CONNECTED;
}
else
{
psock->s_flags |= _SF_CONNECTED;
}
#else
ret = -ENOSYS;
#endif
}
#endif /* CONFIG_NET_UDP */
if (ret < 0)
{
errcode = -ret;
goto errout;
}
}
break;
#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */
#ifdef CONFIG_NET_USRSOCK
case SOCK_USRSOCK_TYPE:
{
ret = usrsock_connect(psock, addr, addrlen);
if (ret < 0)
{
errcode = -ret;
goto errout;
}
}
break;
#endif /* CONFIG_NET_USRSOCK */
default:
errcode = EBADF;
goto errout;
}
leave_cancellation_point();
return OK;

610
net/socket/inet_close.c Normal file
View file

@ -0,0 +1,610 @@
/****************************************************************************
* net/socket/inet_close.c
*
* Copyright (C) 2007-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#ifdef CONFIG_NET
#include <sys/types.h>
#include <sys/socket.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <debug.h>
#include <assert.h>
#include <arch/irq.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/tcp.h>
#include <nuttx/net/udp.h>
#ifdef CONFIG_NET_SOLINGER
# include <nuttx/clock.h>
#endif
#include "netdev/netdev.h"
#include "devif/devif.h"
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "pkt/pkt.h"
#include "local/local.h"
#include "socket/socket.h"
#include "usrsock/usrsock.h"
/****************************************************************************
* Private Types
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
struct tcp_close_s
{
FAR struct devif_callback_s *cl_cb; /* Reference to TCP callback instance */
#ifdef CONFIG_NET_SOLINGER
FAR struct socket *cl_psock; /* Reference to the TCP socket */
sem_t cl_sem; /* Signals disconnect completion */
int cl_result; /* The result of the close */
systime_t cl_start; /* Time close started (in ticks) */
#endif
};
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: tcp_close_timeout
*
* Description:
* Check for a timeout on a lingering close.
*
* Parameters:
* pstate - close state structure
*
* Returned Value:
* TRUE:timeout FALSE:no timeout
*
* Assumptions:
* Running at the interrupt level
*
****************************************************************************/
#if defined(NET_TCP_HAVE_STACK) && defined(CONFIG_NET_SOLINGER)
static inline int tcp_close_timeout(FAR struct tcp_close_s *pstate)
{
FAR struct socket *psock = 0;
/* Make sure that we are performing a lingering close */
if (pstate != NULL)
{
/* Yes Check for a timeout configured via setsockopts(SO_LINGER).
* If none... we well let the send wait forever.
*/
psock = pstate->cl_psock;
if (psock && psock->s_linger != 0)
{
/* Check if the configured timeout has elapsed */
return net_timeo(pstate->cl_start, psock->s_linger);
}
}
/* No timeout */
return FALSE;
}
#endif /* NET_TCP_HAVE_STACK && CONFIG_NET_SOLINGER */
/****************************************************************************
* Name: tcp_close_interrupt
*
* Description:
* Handle network callback events.
*
* Parameters:
* conn - TCP connection structure
*
* Returned Value:
* None
*
* Assumptions:
* Called from normal user-level logic
*
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static uint16_t tcp_close_interrupt(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv,
uint16_t flags)
{
#ifdef CONFIG_NET_SOLINGER
FAR struct tcp_close_s *pstate = (FAR struct tcp_close_s *)pvpriv;
#endif
FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn;
DEBUGASSERT(conn != NULL);
ninfo("conn: %p flags: %04x\n", conn, flags);
/* TCP_DISCONN_EVENTS:
* TCP_CLOSE: The remote host has closed the connection
* TCP_ABORT: The remote host has aborted the connection
* TCP_TIMEDOUT: The remote did not respond, the connection timed out
* NETDEV_DOWN: The network device went down
*/
if ((flags & TCP_DISCONN_EVENTS) != 0)
{
/* The disconnection is complete */
#ifdef CONFIG_NET_SOLINGER
/* pstate non-NULL means that we are performing a LINGERing close. */
if (pstate != NULL)
{
/* Wake up the waiting thread with a successful result */
pstate->cl_result = OK;
goto end_wait;
}
/* Otherwise, nothing is waiting on the close event and we can perform
* the completion actions here.
*/
else
#endif
{
/* Free connection resources */
tcp_free(conn);
/* Stop further callbacks */
flags = 0;
}
}
#ifdef CONFIG_NET_SOLINGER
/* Check for a timeout. */
else if (pstate && tcp_close_timeout(pstate))
{
/* Yes.. Wake up the waiting thread and report the timeout */
nerr("ERROR: CLOSE timeout\n");
pstate->cl_result = -ETIMEDOUT;
goto end_wait;
}
#endif /* CONFIG_NET_SOLINGER */
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* Check if all outstanding bytes have been ACKed */
else if (conn->unacked != 0 || !sq_empty(&conn->write_q))
{
/* No... we are still waiting for ACKs. Drop any received data, but
* do not yet report TCP_CLOSE in the response.
*/
dev->d_len = 0;
flags = (flags & ~TCP_NEWDATA);
}
#endif /* CONFIG_NET_TCP_WRITE_BUFFERS */
else
{
/* Drop data received in this state and make sure that TCP_CLOSE
* is set in the response
*/
dev->d_len = 0;
flags = (flags & ~TCP_NEWDATA) | TCP_CLOSE;
}
return flags;
#ifdef CONFIG_NET_SOLINGER
end_wait:
pstate->cl_cb->flags = 0;
pstate->cl_cb->priv = NULL;
pstate->cl_cb->event = NULL;
sem_post(&pstate->cl_sem);
ninfo("Resuming\n");
return 0;
#endif
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: tcp_close_txnotify
*
* Description:
* Notify the appropriate device driver that we are have data ready to
* be send (TCP)
*
* Parameters:
* psock - Socket state structure
* conn - The TCP connection structure
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static inline void tcp_close_txnotify(FAR struct socket *psock,
FAR struct tcp_conn_s *conn)
{
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
/* If both IPv4 and IPv6 support are enabled, then we will need to select
* the device driver using the appropriate IP domain.
*/
if (psock->s_domain == PF_INET)
#endif
{
/* Notify the device driver that send data is available */
#ifdef CONFIG_NETDEV_MULTINIC
netdev_ipv4_txnotify(conn->u.ipv4.laddr, conn->u.ipv4.raddr);
#else
netdev_ipv4_txnotify(conn->u.ipv4.raddr);
#endif
}
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else /* if (psock->s_domain == PF_INET6) */
#endif /* CONFIG_NET_IPv4 */
{
/* Notify the device driver that send data is available */
DEBUGASSERT(psock->s_domain == PF_INET6);
#ifdef CONFIG_NETDEV_MULTINIC
netdev_ipv6_txnotify(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
#else
netdev_ipv6_txnotify(conn->u.ipv6.raddr);
#endif
}
#endif /* CONFIG_NET_IPv6 */
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: tcp_close_disconnect
*
* Description:
* Break any current TCP connection
*
* Parameters:
* conn - TCP connection structure
*
* Returned Value:
* None
*
* Assumptions:
* Called from normal user-level logic
*
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static inline int tcp_close_disconnect(FAR struct socket *psock)
{
struct tcp_close_s state;
FAR struct tcp_conn_s *conn;
#ifdef CONFIG_NET_SOLINGER
bool linger;
#endif
int ret = OK;
/* Interrupts are disabled here to avoid race conditions */
net_lock();
conn = (FAR struct tcp_conn_s *)psock->s_conn;
/* If we have a semi-permanent write buffer callback in place, then
* release it now.
*/
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
if (psock->s_sndcb)
{
psock->s_sndcb = NULL;
}
#endif
DEBUGASSERT(conn != NULL);
/* Check for the case where the host beat us and disconnected first */
if (conn->tcpstateflags == TCP_ESTABLISHED &&
(state.cl_cb = tcp_callback_alloc(conn)) != NULL)
{
/* Set up to receive TCP data event callbacks */
state.cl_cb->flags = (TCP_NEWDATA | TCP_POLL | TCP_DISCONN_EVENTS);
state.cl_cb->event = tcp_close_interrupt;
#ifdef CONFIG_NET_SOLINGER
/* Check for a lingering close */
linger = _SO_GETOPT(psock->s_options, SO_LINGER);
/* Has a lingering close been requested */
if (linger)
{
/* A non-NULL value of the priv field means that lingering is
* enabled.
*/
state.cl_cb->priv = (FAR void *)&state;
/* Set up for the lingering wait */
state.cl_psock = psock;
state.cl_result = -EBUSY;
/* This semaphore is used for signaling and, hence, should not have
* priority inheritance enabled.
*/
sem_init(&state.cl_sem, 0, 0);
sem_setprotocol(&state.cl_sem, SEM_PRIO_NONE);
/* Record the time that we started the wait (in ticks) */
state.cl_start = clock_systimer();
}
else
#endif /* CONFIG_NET_SOLINGER */
{
/* We will close immediately. The NULL priv field signals this */
state.cl_cb->priv = NULL;
/* No further references on the connection */
conn->crefs = 0;
}
/* Notify the device driver of the availability of TX data */
tcp_close_txnotify(psock, conn);
#ifdef CONFIG_NET_SOLINGER
/* Wait only if we are lingering */
if (linger)
{
/* Wait for the disconnect event */
(void)net_lockedwait(&state.cl_sem);
/* We are now disconnected */
sem_destroy(&state.cl_sem);
tcp_callback_free(conn, state.cl_cb);
/* Free the connection */
conn->crefs = 0; /* No more references on the connection */
tcp_free(conn); /* Free network resources */
/* Get the result of the close */
ret = state.cl_result;
}
#endif /* CONFIG_NET_SOLINGER */
}
else
{
tcp_free(conn);
}
net_unlock();
return ret;
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: inet_close
*
* Description:
* Performs the close operation on an AF_INET or AF_INET6 socket instance
*
* Parameters:
* psock Socket instance
*
* Returned Value:
* 0 on success; -1 on error with errno set appropriately.
*
* Assumptions:
*
****************************************************************************/
int inet_close(FAR struct socket *psock)
{
/* Perform some pre-close operations for the AF_INET/AF_INET6 address
* types.
*/
switch (psock->s_type)
{
#ifdef CONFIG_NET_TCP
case SOCK_STREAM:
{
#ifdef NET_TCP_HAVE_STACK
FAR struct tcp_conn_s *conn = psock->s_conn;
int ret;
/* Is this the last reference to the connection structure (there
* could be more if the socket was dup'ed).
*/
if (conn->crefs <= 1)
{
/* Yes... then perform the disconnection now */
tcp_unlisten(conn); /* No longer accepting connections */
conn->crefs = 0; /* Discard our reference to the connection */
/* Break any current connections */
ret = tcp_close_disconnect(psock);
if (ret < 0)
{
/* This would normally occur only if there is a timeout
* from a lingering close.
*/
nerr("ERROR: tcp_close_disconnect failed: %d\n", ret);
return ret;
}
/* Stop the network monitor */
net_stopmonitor(conn);
}
else
{
/* No.. Just decrement the reference count */
conn->crefs--;
}
#else
nwarn("WARNING: SOCK_STREAM support is not available in this configuration\n");
return -EAFNOSUPPORT;
#endif /* NET_TCP_HAVE_STACK */
}
break;
#endif /* CONFIG_NET_TCP */
#ifdef CONFIG_NET_UDP
case SOCK_DGRAM:
{
#ifdef NET_UDP_HAVE_STACK
FAR struct udp_conn_s *conn = psock->s_conn;
/* Is this the last reference to the connection structure (there
* could be more if the socket was dup'ed).
*/
if (conn->crefs <= 1)
{
/* Yes... free the connection structure */
conn->crefs = 0;
udp_free(psock->s_conn);
}
else
{
/* No.. Just decrement the reference count */
conn->crefs--;
}
#else
nwarn("WARNING: SOCK_DGRAM support is not available in this configuration\n");
return -EAFNOSUPPORT;
#endif /* NET_UDP_HAVE_STACK */
}
break;
#endif /* CONFIG_NET_UDP */
#ifdef CONFIG_NET_USRSOCK
case SOCK_USRSOCK_TYPE:
{
FAR struct usrsock_conn_s *conn = psock->s_conn;
int ret;
/* 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. */
ret = usrsock_close(conn);
/* Free the connection structure */
conn->crefs = 0;
usrsock_free(psock->s_conn);
if (ret < 0)
{
/* Return with error code, but free resources. */
nerr("ERROR: usrsock_close failed: %d\n", ret);
return ret;
}
}
else
{
/* No.. Just decrement the reference count */
conn->crefs--;
}
}
break;
#endif
default:
return -EBADF;
}
return OK;
}
#endif /* CONFIG_NET */

567
net/socket/inet_connect.c Normal file
View file

@ -0,0 +1,567 @@
/****************************************************************************
* net/socket/inet_connect.c
*
* Copyright (C) 2007-2012, 2015-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <arch/irq.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/udp.h>
#include <nuttx/net/tcp.h>
#include "devif/devif.h"
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "socket/socket.h"
#include "usrsock/usrsock.h"
#ifdef CONFIG_NET
/****************************************************************************
* Private Types
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
struct tcp_connect_s
{
FAR struct tcp_conn_s *tc_conn; /* Reference to TCP connection structure */
FAR struct devif_callback_s *tc_cb; /* Reference to callback instance */
FAR struct socket *tc_psock; /* The socket being connected */
sem_t tc_sem; /* Semaphore signals recv completion */
int tc_result; /* OK on success, otherwise a negated errno. */
};
#endif
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static inline int psock_setup_callbacks(FAR struct socket *psock,
FAR struct tcp_connect_s *pstate);
static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate,
int status);
static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv,
uint16_t flags);
static inline int psock_tcp_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr);
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: psock_setup_callbacks
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static inline int psock_setup_callbacks(FAR struct socket *psock,
FAR struct tcp_connect_s *pstate)
{
FAR struct tcp_conn_s *conn = psock->s_conn;
int ret = -EBUSY;
/* Initialize the TCP state structure */
/* This semaphore is used for signaling and, hence, should not have
* priority inheritance enabled.
*/
(void)sem_init(&pstate->tc_sem, 0, 0); /* Doesn't really fail */
(void)sem_setprotocol(&pstate->tc_sem, SEM_PRIO_NONE);
pstate->tc_conn = conn;
pstate->tc_psock = psock;
pstate->tc_result = -EAGAIN;
/* Set up the callbacks in the connection */
pstate->tc_cb = tcp_callback_alloc(conn);
if (pstate->tc_cb)
{
/* Set up the connection "interrupt" handler */
pstate->tc_cb->flags = (TCP_NEWDATA | TCP_CLOSE | TCP_ABORT |
TCP_TIMEDOUT | TCP_CONNECTED | NETDEV_DOWN);
pstate->tc_cb->priv = (FAR void *)pstate;
pstate->tc_cb->event = psock_connect_interrupt;
ret = OK;
}
return ret;
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: psock_teardown_callbacks
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static void psock_teardown_callbacks(FAR struct tcp_connect_s *pstate,
int status)
{
FAR struct tcp_conn_s *conn = pstate->tc_conn;
/* Make sure that no further interrupts are processed */
tcp_callback_free(conn, pstate->tc_cb);
pstate->tc_cb = NULL;
/* If we successfully connected, we will continue to monitor the connection
* state via callbacks.
*/
if (status < 0)
{
/* Failed to connect. Stop the connection event monitor */
net_stopmonitor(conn);
}
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: psock_connect_interrupt
*
* Description:
* This function is called from the interrupt level to perform the actual
* connection operation via by the lower, device interfacing layer.
*
* Parameters:
* dev The structure of the network driver that caused the interrupt
* pvconn The connection structure associated with the socket
* flags Set of events describing why the callback was invoked
*
* Returned Value:
* The new flags setting
*
* Assumptions:
* Running at the interrupt level
*
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static uint16_t psock_connect_interrupt(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv,
uint16_t flags)
{
struct tcp_connect_s *pstate = (struct tcp_connect_s *)pvpriv;
ninfo("flags: %04x\n", flags);
/* 'priv' might be null in some race conditions (?) */
if (pstate)
{
/* The following errors should be detected here (someday)
*
* ECONNREFUSED
* No one listening on the remote address.
* ENETUNREACH
* Network is unreachable.
* ETIMEDOUT
* Timeout while attempting connection. The server may be too busy
* to accept new connections.
*/
/* TCP_CLOSE: The remote host has closed the connection
* TCP_ABORT: The remote host has aborted the connection
*/
if ((flags & (TCP_CLOSE | TCP_ABORT)) != 0)
{
/* Indicate that remote host refused the connection */
pstate->tc_result = -ECONNREFUSED;
}
/* TCP_TIMEDOUT: Connection aborted due to too many retransmissions. */
else if ((flags & TCP_TIMEDOUT) != 0)
{
/* Indicate that the connection timedout?) */
pstate->tc_result = -ETIMEDOUT;
}
else if ((flags & NETDEV_DOWN) != 0)
{
/* The network device went down. Indicate that the remote host
* is unreachable.
*/
pstate->tc_result = -ENETUNREACH;
}
/* TCP_CONNECTED: The socket is successfully connected */
else if ((flags & TCP_CONNECTED) != 0)
{
FAR struct socket *psock = pstate->tc_psock;
DEBUGASSERT(psock);
/* Mark the connection bound and connected. NOTE this is
* is done here (vs. later) in order to avoid any race condition
* in the socket state. It is known to connected here and now,
* but not necessarily at any time later.
*/
psock->s_flags |= (_SF_BOUND | _SF_CONNECTED);
/* Indicate that the socket is no longer connected */
pstate->tc_result = OK;
}
/* Otherwise, it is not an event of importance to us at the moment */
else
{
/* Drop data received in this state */
dev->d_len = 0;
return flags & ~TCP_NEWDATA;
}
ninfo("Resuming: %d\n", pstate->tc_result);
/* Stop further callbacks */
psock_teardown_callbacks(pstate, pstate->tc_result);
#ifdef CONFIG_NET_MULTILINK
/* When we set up the connection structure, we did not know the size
* of the initial MSS. Now that the connection is associated with a
* network device, we now know the size of link layer header and can
* determine the correct initial MSS.
*/
DEBUGASSERT(pstate->tc_conn);
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (pstate->tc_conn->domain == PF_INET)
#endif
{
pstate->tc_conn->mss = TCP_IPv4_INITIAL_MSS(dev);
}
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
{
pstate->tc_conn->mss = TCP_IPv6_INITIAL_MSS(dev);
}
#endif /* CONFIG_NET_IPv6 */
#ifdef CONFIG_NETDEV_MULTINIC
/* We now have to filter all outgoing transfers so that they use only
* the MSS of this device.
*/
DEBUGASSERT(pstate->tc_conn->dev == NULL ||
pstate->tc_conn->dev == dev);
pstate->tc_conn->dev = dev;
#endif /* CONFIG_NETDEV_MULTINIC */
#endif /* CONFIG_NET_MULTILINK */
/* Wake up the waiting thread */
sem_post(&pstate->tc_sem);
}
return flags;
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: psock_tcp_connect
*
* Description:
* Perform a TCP connection
*
* Parameters:
* psock - A reference to the socket structure of the socket to be connected
* addr - The address of the remote server to connect to
*
* Returned Value:
* None
*
* Assumptions:
* Running at the interrupt level
*
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static inline int psock_tcp_connect(FAR struct socket *psock,
FAR const struct sockaddr *addr)
{
struct tcp_connect_s state;
int ret = OK;
/* Interrupts must be disabled through all of the following because
* we cannot allow the network callback to occur until we are completely
* setup.
*/
net_lock();
/* Get the connection reference from the socket */
if (!psock->s_conn) /* Should always be non-NULL */
{
ret = -EINVAL;
}
else
{
/* Perform the TCP connection operation */
ret = tcp_connect(psock->s_conn, addr);
}
if (ret >= 0)
{
/* Set up the callbacks in the connection */
ret = psock_setup_callbacks(psock, &state);
if (ret >= 0)
{
/* Wait for either the connect to complete or for an error/timeout
* to occur. NOTES: (1) net_lockedwait will also terminate if a signal
* is received, (2) interrupts may be disabled! They will be re-
* enabled while the task sleeps and automatically re-disabled
* when the task restarts.
*/
ret = net_lockedwait(&state.tc_sem);
/* Uninitialize the state structure */
(void)sem_destroy(&state.tc_sem);
/* If net_lockedwait failed, recover the negated error (probably -EINTR) */
if (ret < 0)
{
ret = -get_errno();
}
else
{
/* If the wait succeeded, then get the new error value from
* the state structure
*/
ret = state.tc_result;
}
/* Make sure that no further interrupts are processed */
psock_teardown_callbacks(&state, ret);
}
/* Check if the socket was successfully connected. */
if (ret >= 0)
{
/* Yes... Now that we are connected, we need to set up to monitor
* the state of the connection up the connection event monitor.
*/
ret = net_startmonitor(psock);
if (ret < 0)
{
/* net_startmonitor() can only fail on certain race
* conditions where the connection was lost just before
* this function was called. That is not expected to
* happen in this context, but just in case...
*/
net_lostconnection(psock, TCP_ABORT);
}
}
}
net_unlock();
return ret;
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: inet_connect
*
* Description:
* inet_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
* datagrams are received. If the socket is of type SOCK_STREAM or
* SOCK_SEQPACKET, this call attempts to make a connection to the socket
* that is bound to the address specified by 'addr'.
*
* Generally, connection-based protocol sockets may successfully
* inet_connect() only once; connectionless protocol sockets may use
* inet_connect() multiple times to change their association.
* Connectionless sockets may dissolve the association by connecting to
* an address with the sa_family member of sockaddr set to AF_UNSPEC.
*
* Parameters:
* psock Pointer to a socket structure initialized by psock_socket()
* addr Server address (form depends on type of socket)
* addrlen Length of actual 'addr'
*
* Returned Value:
* 0 on success; a negated errno value on failue. See connect() for the
* list of appropriate errno values to be returned.
*
****************************************************************************/
int inet_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
socklen_t addrlen)
{
FAR const struct sockaddr_in *inaddr = (FAR const struct sockaddr_in *)addr;
/* Verify that a valid address has been provided */
switch (inaddr->sin_family)
{
#ifdef CONFIG_NET_IPv4
case AF_INET:
{
if (addrlen < sizeof(struct sockaddr_in))
{
return -EBADF;
}
}
break;
#endif
#ifdef CONFIG_NET_IPv6
case AF_INET6:
{
if (addrlen < sizeof(struct sockaddr_in6))
{
return -EBADF;
}
}
break;
#endif
default:
#ifdef CONFIG_NET_USRSOCK
if (psock->s_type == SOCK_USRSOCK_TYPE)
{
break;
}
#endif
DEBUGPANIC();
return -EAFNOSUPPORT;
}
/* Perform the connection depending on the protocol type */
switch (psock->s_type)
{
#ifdef CONFIG_NET_TCP
case SOCK_STREAM:
{
/* Verify that the socket is not already connected */
if (_SS_ISCONNECTED(psock->s_flags))
{
return -EISCONN;
}
/* It's not ... Connect the TCP/IP socket */
return psock_tcp_connect(psock, addr);
}
#endif /* CONFIG_NET_TCP */
#ifdef CONFIG_NET_UDP
case SOCK_DGRAM:
{
int ret = udp_connect(psock->s_conn, addr);
if (ret < 0 || addr == NULL)
{
psock->s_flags &= ~_SF_CONNECTED;
}
else
{
psock->s_flags |= _SF_CONNECTED;
}
return ret;
}
#endif /* CONFIG_NET_UDP */
#ifdef CONFIG_NET_USRSOCK
case SOCK_USRSOCK_TYPE:
{
return usrsock_connect(psock, addr, addrlen);
}
#endif /* CONFIG_NET_USRSOCK */
default:
return -EBADF;
}
}
#endif /* CONFIG_NET */

1674
net/socket/inet_recvfrom.c Normal file

File diff suppressed because it is too large Load diff

1022
net/socket/inet_sockif.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
/****************************************************************************
* net/socket/listen.c
*
* Copyright (C) 2007-2009, 201-2016 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 201-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -38,17 +38,15 @@
****************************************************************************/
#include <nuttx/config.h>
#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0
#include <sys/socket.h>
#include <errno.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include "tcp/tcp.h"
#include "local/local.h"
#include "socket/socket.h"
#include "usrsock/usrsock.h"
#if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0
/****************************************************************************
* Public Functions
@ -86,83 +84,29 @@
int psock_listen(FAR struct socket *psock, int backlog)
{
int errcode;
int ret;
DEBUGASSERT(psock != NULL);
/* Verify that the sockfd corresponds to a connected SOCK_STREAM */
if (psock->s_type != SOCK_STREAM || !psock->s_conn)
if (psock == NULL || psock->s_conn == NULL)
{
#ifdef CONFIG_NET_USRSOCK
if (psock->s_type == SOCK_USRSOCK_TYPE)
{
#warning "Missing logic"
}
#endif
errcode = EOPNOTSUPP;
nerr("ERROR: Invalid or unconnected socket\n");
errcode = EINVAL;
goto errout;
}
#ifdef CONFIG_NET_LOCAL
#ifdef CONFIG_NET_TCP
if (psock->s_domain == PF_LOCAL)
#endif
/* Let the address family's listen() method handle the operation */
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_listen != NULL);
ret = psock->s_sockif->si_listen(psock, backlog);
if (ret < 0)
{
FAR struct local_conn_s *conn =
(FAR struct local_conn_s *)psock->s_conn;
errcode = local_listen(conn, backlog);
if (errcode < 0)
{
errcode = -errcode;
goto errout;
}
}
#endif /* CONFIG_NET_LOCAL */
#ifdef CONFIG_NET_TCP
#ifdef CONFIG_NET_LOCAL
else
#endif
{
#ifdef NET_TCP_HAVE_STACK
FAR struct tcp_conn_s *conn =
(FAR struct tcp_conn_s *)psock->s_conn;
if (conn->lport <= 0)
{
errcode = EOPNOTSUPP;
goto errout;
}
/* Set up the backlog for this connection */
#ifdef CONFIG_NET_TCPBACKLOG
errcode = tcp_backlogcreate(conn, backlog);
if (errcode < 0)
{
errcode = -errcode;
goto errout;
}
#endif
/* Start listening to the bound port. This enables callbacks when
* accept() is called and enables poll()/select() logic.
*/
errcode = tcp_listen(conn);
if (errcode < 0)
{
errcode = -errcode;
goto errout;
}
#else
errcode = EOPNOTSUPP;
nerr("ERROR: si_listen failed: %d\n", ret);
errcode = -ret;
goto errout;
#endif /* NET_TCP_HAVE_STACK */
}
#endif /* CONFIG_NET_TCP */
psock->s_flags |= _SF_LISTENING;
return OK;

View file

@ -79,6 +79,7 @@ int net_clone(FAR struct socket *psock1, FAR struct socket *psock2)
psock2->s_domain = psock1->s_domain; /* IP domain: PF_INET, PF_INET6, or PF_PACKET */
psock2->s_type = psock1->s_type; /* Protocol type: Only SOCK_STREAM or SOCK_DGRAM */
psock2->s_sockif = psock1->s_sockif; /* Socket interface */
psock2->s_flags = psock1->s_flags; /* See _SF_* definitions */
#ifdef CONFIG_NET_SOCKOPTS
psock2->s_options = psock1->s_options; /* Selected socket options */
@ -94,65 +95,19 @@ int net_clone(FAR struct socket *psock1, FAR struct socket *psock2)
* instance for TCP send */
#endif
/* Increment the reference count on the connection */
/* Increment the reference count on the socket */
DEBUGASSERT(psock2->s_conn);
psock2->s_crefs = 1; /* One reference on the new socket itself */
#ifdef CONFIG_NET_LOCAL
if (psock2->s_domain == PF_LOCAL)
{
FAR struct local_conn_s *conn = psock2->s_conn;
DEBUGASSERT(conn->lc_crefs > 0 && conn->lc_crefs < 255);
conn->lc_crefs++;
}
else
#endif
#ifdef CONFIG_NET_PKT
if (psock2->s_type == SOCK_RAW)
{
FAR struct pkt_conn_s *conn = psock2->s_conn;
DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255);
conn->crefs++;
}
else
#endif
#ifdef NET_TCP_HAVE_STACK
if (psock2->s_type == SOCK_STREAM)
{
FAR struct tcp_conn_s *conn = psock2->s_conn;
DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255);
conn->crefs++;
}
else
#endif
#ifdef NET_UDP_HAVE_STACK
if (psock2->s_type == SOCK_DGRAM)
{
FAR struct udp_conn_s *conn = psock2->s_conn;
DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255);
conn->crefs++;
}
else
#endif
#ifdef CONFIG_NET_USRSOCK
if (psock2->s_type == SOCK_USRSOCK_TYPE)
{
FAR struct usrsock_conn_s *conn = psock2->s_conn;
DEBUGASSERT(conn->crefs > 0 && conn->crefs < 255);
conn->crefs++;
}
else
#endif
{
nerr("ERROR: Unsupported type: %d\n", psock2->s_type);
ret = -EBADF;
}
/* Increment the reference count on the underlying connection structure
* for this address family type.
*/
DEBUGASSERT(psock2->s_sockif != NULL && psock2->s_sockif->si_addref != NULL);
psock2->s_sockif->si_addref(psock2);
net_unlock();
return ret;
}
#endif /* CONFIG_NET */

View file

@ -38,7 +38,6 @@
****************************************************************************/
#include <nuttx/config.h>
#ifdef CONFIG_NET
#include <sys/types.h>
#include <sys/socket.h>
@ -48,450 +47,11 @@
#include <debug.h>
#include <assert.h>
#include <arch/irq.h>
#include <nuttx/semaphore.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/tcp.h>
#include <nuttx/net/udp.h>
#ifdef CONFIG_NET_SOLINGER
# include <nuttx/clock.h>
#endif
#include "netdev/netdev.h"
#include "devif/devif.h"
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "pkt/pkt.h"
#include "local/local.h"
#include "socket/socket.h"
#include "usrsock/usrsock.h"
/****************************************************************************
* Private Types
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
struct tcp_close_s
{
FAR struct devif_callback_s *cl_cb; /* Reference to TCP callback instance */
#ifdef CONFIG_NET_SOLINGER
FAR struct socket *cl_psock; /* Reference to the TCP socket */
sem_t cl_sem; /* Signals disconnect completion */
int cl_result; /* The result of the close */
systime_t cl_start; /* Time close started (in ticks) */
#endif
};
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: close_timeout
*
* Description:
* Check for a timeout on a lingering close.
*
* Parameters:
* pstate - close state structure
*
* Returned Value:
* TRUE:timeout FALSE:no timeout
*
* Assumptions:
* Running at the interrupt level
*
****************************************************************************/
#if defined(NET_TCP_HAVE_STACK) && defined(CONFIG_NET_SOLINGER)
static inline int close_timeout(FAR struct tcp_close_s *pstate)
{
FAR struct socket *psock = 0;
/* Make sure that we are performing a lingering close */
if (pstate)
{
/* Yes Check for a timeout configured via setsockopts(SO_LINGER).
* If none... we well let the send wait forever.
*/
psock = pstate->cl_psock;
if (psock && psock->s_linger != 0)
{
/* Check if the configured timeout has elapsed */
return net_timeo(pstate->cl_start, psock->s_linger);
}
}
/* No timeout */
return FALSE;
}
#endif /* NET_TCP_HAVE_STACK && CONFIG_NET_SOLINGER */
/****************************************************************************
* Name: netclose_interrupt
*
* Description:
* Handle network callback events.
*
* Parameters:
* conn - TCP connection structure
*
* Returned Value:
* None
*
* Assumptions:
* Called from normal user-level logic
*
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static uint16_t netclose_interrupt(FAR struct net_driver_s *dev,
FAR void *pvconn, FAR void *pvpriv,
uint16_t flags)
{
#ifdef CONFIG_NET_SOLINGER
FAR struct tcp_close_s *pstate = (FAR struct tcp_close_s *)pvpriv;
#endif
FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn;
DEBUGASSERT(conn != NULL);
ninfo("conn: %p flags: %04x\n", conn, flags);
/* TCP_DISCONN_EVENTS:
* TCP_CLOSE: The remote host has closed the connection
* TCP_ABORT: The remote host has aborted the connection
* TCP_TIMEDOUT: The remote did not respond, the connection timed out
* NETDEV_DOWN: The network device went down
*/
if ((flags & TCP_DISCONN_EVENTS) != 0)
{
/* The disconnection is complete */
#ifdef CONFIG_NET_SOLINGER
/* pstate non-NULL means that we are performing a LINGERing close. */
if (pstate)
{
/* Wake up the waiting thread with a successful result */
pstate->cl_result = OK;
goto end_wait;
}
/* Otherwise, nothing is waiting on the close event and we can perform
* the completion actions here.
*/
else
#endif
{
/* Free connection resources */
tcp_free(conn);
/* Stop further callbacks */
flags = 0;
}
}
#ifdef CONFIG_NET_SOLINGER
/* Check for a timeout. */
else if (pstate && close_timeout(pstate))
{
/* Yes.. Wake up the waiting thread and report the timeout */
nerr("ERROR: CLOSE timeout\n");
pstate->cl_result = -ETIMEDOUT;
goto end_wait;
}
#endif /* CONFIG_NET_SOLINGER */
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
/* Check if all outstanding bytes have been ACKed */
else if (conn->unacked != 0 || !sq_empty(&conn->write_q))
{
/* No... we are still waiting for ACKs. Drop any received data, but
* do not yet report TCP_CLOSE in the response.
*/
dev->d_len = 0;
flags = (flags & ~TCP_NEWDATA);
}
#endif /* CONFIG_NET_TCP_WRITE_BUFFERS */
else
{
/* Drop data received in this state and make sure that TCP_CLOSE
* is set in the response
*/
dev->d_len = 0;
flags = (flags & ~TCP_NEWDATA) | TCP_CLOSE;
}
return flags;
#ifdef CONFIG_NET_SOLINGER
end_wait:
pstate->cl_cb->flags = 0;
pstate->cl_cb->priv = NULL;
pstate->cl_cb->event = NULL;
sem_post(&pstate->cl_sem);
ninfo("Resuming\n");
return 0;
#endif
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: netclose_txnotify
*
* Description:
* Notify the appropriate device driver that we are have data ready to
* be send (TCP)
*
* Parameters:
* psock - Socket state structure
* conn - The TCP connection structure
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static inline void netclose_txnotify(FAR struct socket *psock,
FAR struct tcp_conn_s *conn)
{
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
/* If both IPv4 and IPv6 support are enabled, then we will need to select
* the device driver using the appropriate IP domain.
*/
if (psock->s_domain == PF_INET)
#endif
{
/* Notify the device driver that send data is available */
#ifdef CONFIG_NETDEV_MULTINIC
netdev_ipv4_txnotify(conn->u.ipv4.laddr, conn->u.ipv4.raddr);
#else
netdev_ipv4_txnotify(conn->u.ipv4.raddr);
#endif
}
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else /* if (psock->s_domain == PF_INET6) */
#endif /* CONFIG_NET_IPv4 */
{
/* Notify the device driver that send data is available */
DEBUGASSERT(psock->s_domain == PF_INET6);
#ifdef CONFIG_NETDEV_MULTINIC
netdev_ipv6_txnotify(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
#else
netdev_ipv6_txnotify(conn->u.ipv6.raddr);
#endif
}
#endif /* CONFIG_NET_IPv6 */
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: netclose_disconnect
*
* Description:
* Break any current TCP connection
*
* Parameters:
* conn - TCP connection structure
*
* Returned Value:
* None
*
* Assumptions:
* Called from normal user-level logic
*
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static inline int netclose_disconnect(FAR struct socket *psock)
{
struct tcp_close_s state;
FAR struct tcp_conn_s *conn;
#ifdef CONFIG_NET_SOLINGER
bool linger;
#endif
int ret = OK;
/* Interrupts are disabled here to avoid race conditions */
net_lock();
conn = (FAR struct tcp_conn_s *)psock->s_conn;
/* If we have a semi-permanent write buffer callback in place, then
* release it now.
*/
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
if (psock->s_sndcb)
{
psock->s_sndcb = NULL;
}
#endif
DEBUGASSERT(conn != NULL);
/* Check for the case where the host beat us and disconnected first */
if (conn->tcpstateflags == TCP_ESTABLISHED &&
(state.cl_cb = tcp_callback_alloc(conn)) != NULL)
{
/* Set up to receive TCP data event callbacks */
state.cl_cb->flags = (TCP_NEWDATA | TCP_POLL | TCP_DISCONN_EVENTS);
state.cl_cb->event = netclose_interrupt;
#ifdef CONFIG_NET_SOLINGER
/* Check for a lingering close */
linger = _SO_GETOPT(psock->s_options, SO_LINGER);
/* Has a lingering close been requested */
if (linger)
{
/* A non-NULL value of the priv field means that lingering is
* enabled.
*/
state.cl_cb->priv = (FAR void *)&state;
/* Set up for the lingering wait */
state.cl_psock = psock;
state.cl_result = -EBUSY;
/* This semaphore is used for signaling and, hence, should not have
* priority inheritance enabled.
*/
sem_init(&state.cl_sem, 0, 0);
sem_setprotocol(&state.cl_sem, SEM_PRIO_NONE);
/* Record the time that we started the wait (in ticks) */
state.cl_start = clock_systimer();
}
else
#endif /* CONFIG_NET_SOLINGER */
{
/* We will close immediately. The NULL priv field signals this */
state.cl_cb->priv = NULL;
/* No further references on the connection */
conn->crefs = 0;
}
/* Notify the device driver of the availability of TX data */
netclose_txnotify(psock, conn);
#ifdef CONFIG_NET_SOLINGER
/* Wait only if we are lingering */
if (linger)
{
/* Wait for the disconnect event */
(void)net_lockedwait(&state.cl_sem);
/* We are now disconnected */
sem_destroy(&state.cl_sem);
tcp_callback_free(conn, state.cl_cb);
/* Free the connection */
conn->crefs = 0; /* No more references on the connection */
tcp_free(conn); /* Free network resources */
/* Get the result of the close */
ret = state.cl_result;
}
#endif /* CONFIG_NET_SOLINGER */
}
else
{
tcp_free(conn);
}
net_unlock();
return ret;
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: local_close
*
* Description:
* Performs the close operation on a local socket instance
*
* Parameters:
* psock Socket instance
*
* Returned Value:
* 0 on success; -1 on error with errno set appropriately.
*
* Assumptions:
*
****************************************************************************/
#ifdef CONFIG_NET_LOCAL
static void local_close(FAR struct socket *psock)
{
FAR struct local_conn_s *conn = psock->s_conn;
/* Is this the last reference to the connection structure (there could
* be more if the socket was dup'ed).
*/
if (conn->lc_crefs <= 1)
{
conn->lc_crefs = 0;
local_release(conn);
}
else
{
/* No.. Just decrement the reference count */
conn->lc_crefs--;
}
}
#endif /* CONFIG_NET_LOCAL */
#ifdef CONFIG_NET
/****************************************************************************
* Public Functions
@ -516,6 +76,7 @@ static void local_close(FAR struct socket *psock)
int psock_close(FAR struct socket *psock)
{
int errcode;
int ret;
/* Verify that the sockfd corresponds to valid, allocated socket */
@ -535,185 +96,17 @@ int psock_close(FAR struct socket *psock)
if (psock->s_crefs <= 1 && psock->s_conn != NULL)
{
/* Perform local side of the close depending on the protocol type */
/* Let the address family's close() method handle the operation */
switch (psock->s_type)
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_close != NULL);
ret = psock->s_sockif->si_close(psock);
/* Was the close successful */
if (ret < 0)
{
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM)
case SOCK_STREAM:
{
#ifdef CONFIG_NET_LOCAL_STREAM
#ifdef CONFIG_NET_TCP
if (psock->s_domain == PF_LOCAL)
#endif
{
/* Release our reference to the local connection structure */
local_close(psock);
}
#endif /* CONFIG_NET_LOCAL_STREAM */
#ifdef CONFIG_NET_TCP
#ifdef CONFIG_NET_LOCAL_STREAM
else
#endif
{
#ifdef NET_TCP_HAVE_STACK
FAR struct tcp_conn_s *conn = psock->s_conn;
/* Is this the last reference to the connection structure
* (there could be more if the socket was dup'ed).
*/
if (conn->crefs <= 1)
{
/* Yes... then perform the disconnection now */
tcp_unlisten(conn); /* No longer accepting connections */
conn->crefs = 0; /* Discard our reference to the connection */
/* Break any current connections */
errcode = netclose_disconnect(psock);
if (errcode < 0)
{
/* This would normally occur only if there is a
* timeout from a lingering close.
*/
goto errout_with_psock;
}
/* Stop the network monitor */
net_stopmonitor(conn);
}
else
{
/* No.. Just decrement the reference count */
conn->crefs--;
}
#endif /* NET_TCP_HAVE_STACK */
}
#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */
}
break;
#endif
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM)
case SOCK_DGRAM:
{
#ifdef CONFIG_NET_LOCAL_DGRAM
#ifdef CONFIG_NET_UDP
if (psock->s_domain == PF_LOCAL)
#endif
{
/* Release our reference to the local connection structure */
local_close(psock);
}
#endif /* CONFIG_NET_LOCAL_DGRAM */
#ifdef CONFIG_NET_UDP
#ifdef CONFIG_NET_LOCAL_DGRAM
else
#endif
{
#ifdef NET_UDP_HAVE_STACK
FAR struct udp_conn_s *conn = psock->s_conn;
/* Is this the last reference to the connection structure
* (there could be more if the socket was dup'ed).
*/
if (conn->crefs <= 1)
{
/* Yes... free the connection structure */
conn->crefs = 0;
udp_free(psock->s_conn);
}
else
{
/* No.. Just decrement the reference count */
conn->crefs--;
}
#endif /* NET_UDP_HAVE_STACK */
}
#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */
}
break;
#endif
#ifdef CONFIG_NET_PKT
case SOCK_RAW:
{
FAR struct pkt_conn_s *conn = psock->s_conn;
/* Is this the last reference to the connection structure (there
* could be more if the socket was dup'ed).
*/
if (conn->crefs <= 1)
{
/* Yes... free the connection structure */
conn->crefs = 0; /* No more references on the connection */
pkt_free(psock->s_conn); /* Free network resources */
}
else
{
/* No.. Just decrement the reference count */
conn->crefs--;
}
}
break;
#endif
#ifdef CONFIG_NET_USRSOCK
case SOCK_USRSOCK_TYPE:
{
FAR struct usrsock_conn_s *conn = psock->s_conn;
/* 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. */
errcode = usrsock_close(conn);
/* Free the connection structure */
conn->crefs = 0;
usrsock_free(psock->s_conn);
if (errcode < 0)
{
/* Return with error code, but free resources. */
errcode = -errcode;
goto errout_with_psock;
}
}
else
{
/* No.. Just decrement the reference count */
conn->crefs--;
}
}
break;
#endif
default:
errcode = EBADF;
goto errout;
errcode = -ret;
goto errout;
}
}
@ -722,11 +115,6 @@ int psock_close(FAR struct socket *psock)
sock_release(psock);
return OK;
#if defined(NET_TCP_HAVE_STACK) || defined(CONFIG_NET_USRSOCK)
errout_with_psock:
sock_release(psock);
#endif
errout:
set_errno(errcode);
return ERROR;

111
net/socket/net_sockif.c Normal file
View file

@ -0,0 +1,111 @@
/****************************************************************************
* net/socket/net_sockif.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/net/net.h>
#include "local/local.h"
#include "pkt/pkt.h"
#include "socket/socket.h"
#ifdef CONFIG_NET
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: net_sockif
*
* Description:
* Return the socket interface associated with this address family.
*
* Parameters:
* family - Address family
*
* Returned Value:
* On success, a non-NULL instance of struct sock_intf_s is returned. NULL
* is returned only if the address family is not supported.
*
****************************************************************************/
FAR const struct sock_intf_s *net_sockif(sa_family_t family)
{
FAR const struct sock_intf_s *sockif = NULL;
/* Get the socket interface */
switch (family)
{
#if defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_IPv6)
#ifdef CONFIG_NET_IPv4
case PF_INET:
#endif
#ifdef CONFIG_NET_IPv6
case PF_INET6:
#endif
sockif = &g_inet_sockif;
break;
#endif
#ifdef CONFIG_NET_LOCAL
case PF_LOCAL:
sockif = &g_local_sockif;
break;
#endif
#ifdef CONFIG_NET_PKT
case PF_PACKET:
sockif = &g_pkt_sockif;
break;
#endif
default:
nerr("ERROR: Address family unsupported: %d\n", family);
}
return sockif;
}
#endif /* CONFIG_NET */

View file

@ -84,7 +84,7 @@ int net_vfcntl(int sockfd, int cmd, va_list ap)
/* Verify that the sockfd corresponds to valid, allocated socket */
if (!psock || psock->s_crefs <= 0)
if (psock == NULL || psock->s_crefs <= 0)
{
errcode = EBADF;
goto errout;
@ -140,38 +140,25 @@ int net_vfcntl(int sockfd, int cmd, va_list ap)
*/
{
sockcaps_t sockcaps;
/* This summarizes the behavior of all NuttX sockets */
ret = O_RDWR | O_SYNC | O_RSYNC;
#if defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_TCP_READAHEAD) || \
defined(CONFIG_NET_UDP_READAHEAD)
/* Unix domain sockets may be non-blocking. TCP/IP and UDP/IP
* sockets may also be non-blocking if read-ahead is enabled
*/
if ((0
#ifdef CONFIG_NET_LOCAL
|| psock->s_domain == PF_LOCAL /* Unix domain stream or datagram */
#endif
#ifdef CONFIG_NET_TCP_READAHEAD
|| psock->s_type == SOCK_STREAM /* IP or Unix domain stream */
#endif
#ifdef CONFIG_NET_UDP_READAHEAD
|| psock->s_type == SOCK_DGRAM /* IP or Unix domain datagram */
#endif
) && _SS_ISNONBLOCK(psock->s_flags))
{
ret |= O_NONBLOCK;
}
#endif /* CONFIG_NET_LOCAL || CONFIG_NET_TCP_READAHEAD || CONFIG_NET_UDP_READAHEAD */
DEBUGASSERT(psock->s_sockif != NULL &&
psock->s_sockif->si_sockcaps != NULL);
sockcaps = psock->s_sockif->si_sockcaps(psock);
#ifdef CONFIG_NET_USRSOCK
if (psock->s_type == SOCK_USRSOCK_TYPE && _SS_ISNONBLOCK(psock->s_flags))
if ((sockcaps & SOCKCAP_NONBLOCKING) != 0 &&
_SS_ISNONBLOCK(psock->s_flags))
{
ret |= O_NONBLOCK;
}
#endif
}
break;
@ -185,16 +172,19 @@ int net_vfcntl(int sockfd, int cmd, va_list ap)
*/
{
#if defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_TCP_READAHEAD) || \
defined(CONFIG_NET_UDP_READAHEAD) || defined(CONFIG_NET_USRSOCK)
/* Non-blocking is the only configurable option. And it applies
* only Unix domain sockets and to read operations on TCP/IP
* and UDP/IP sockets when read-ahead is enabled.
*/
int mode = va_arg(ap, int);
#if defined(CONFIG_NET_LOCAL_STREAM) || defined(CONFIG_NET_TCP_READAHEAD)
if (psock->s_type == SOCK_STREAM) /* IP or Unix domain stream */
sockcaps_t sockcaps;
DEBUGASSERT(psock->s_sockif != NULL &&
psock->s_sockif->si_sockcaps != NULL);
sockcaps = psock->s_sockif->si_sockcaps(psock);
if ((sockcaps & SOCKCAP_NONBLOCKING) != 0)
{
if ((mode & O_NONBLOCK) != 0)
{
@ -206,37 +196,6 @@ int net_vfcntl(int sockfd, int cmd, va_list ap)
}
}
else
#endif
#if defined(CONFIG_NET_LOCAL_DGRAM) || defined(CONFIG_NET_UDP_READAHEAD)
if (psock->s_type == SOCK_DGRAM) /* IP or Unix domain datagram */
{
if ((mode & O_NONBLOCK) != 0)
{
psock->s_flags |= _SF_NONBLOCK;
}
else
{
psock->s_flags &= ~_SF_NONBLOCK;
}
}
else
#endif
#if defined(CONFIG_NET_USRSOCK)
if (psock->s_type == SOCK_USRSOCK_TYPE) /* usrsock socket */
{
if ((mode & O_NONBLOCK) != 0)
{
psock->s_flags |= _SF_NONBLOCK;
}
else
{
psock->s_flags &= ~_SF_NONBLOCK;
}
}
else
#endif
#endif /* CONFIG_NET_LOCAL || CONFIG_NET_TCP_READAHEAD ||
CONFIG_NET_UDP_READAHEAD || CONFIG_NET_USRSOCK */
{
nerr("ERROR: Non-blocking not supported for this socket\n");
}

File diff suppressed because it is too large Load diff

View file

@ -42,6 +42,8 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/cancelpt.h>
@ -51,7 +53,6 @@
#include "sixlowpan/sixlowpan.h"
#include "local/local.h"
#include "socket/socket.h"
#include "usrsock/usrsock.h"
/****************************************************************************
* Public Functions
@ -126,132 +127,21 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
{
ssize_t ret;
DEBUGASSERT(psock != NULL && buf != NULL);
/* Treat as a cancellation point */
(void)enter_cancellation_point();
switch (psock->s_type)
{
#if defined(CONFIG_NET_PKT)
case SOCK_RAW:
{
/* Raw packet send */
/* Let the address family's send() method handle the operation */
ret = psock_pkt_send(psock, buf, len);
}
break;
#endif
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM)
case SOCK_STREAM:
{
#ifdef CONFIG_NET_LOCAL_STREAM
#ifdef CONFIG_NET_TCP
if (psock->s_domain == PF_LOCAL)
#endif
{
/* Local TCP packet send */
ret = psock_local_send(psock, buf, len, flags);
}
#endif /* CONFIG_NET_LOCAL_STREAM */
#ifdef CONFIG_NET_TCP
#ifdef CONFIG_NET_LOCAL_STREAM
else
#endif
{
#ifdef CONFIG_NET_6LOWPAN
/* Try 6LoWPAN TCP packet send */
ret = psock_6lowpan_tcp_send(psock, buf, len);
#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_TCP_HAVE_STACK)
if (ret < 0)
{
/* TCP/IP packet send */
ret = psock_tcp_send(psock, buf, len);
}
#endif /* CONFIG_NETDEV_MULTINIC && NET_TCP_HAVE_STACK */
#elif defined(NET_TCP_HAVE_STACK)
ret = psock_tcp_send(psock, buf, len);
#else
ret = -ENOSYS;
#endif /* CONFIG_NET_6LOWPAN */
}
#endif /* CONFIG_NET_TCP */
}
break;
#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */
#ifdef CONFIG_NET_UDP
case SOCK_DGRAM:
{
#ifdef CONFIG_NET_LOCAL_DGRAM
#ifdef CONFIG_NET_UDP
if (psock->s_domain == PF_LOCAL)
#endif
{
/* Local UDP packet send */
#warning Missing logic
ret = -ENOSYS;
}
#endif /* CONFIG_NET_LOCAL_DGRAM */
#ifdef CONFIG_NET_UDP
#ifdef CONFIG_NET_LOCAL_DGRAM
else
#endif
{
#if defined(CONFIG_NET_6LOWPAN)
/* Try 6LoWPAN UDP packet send */
ret = psock_6lowpan_udp_send(psock, buf, len);
#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_UDP_HAVE_STACK)
if (ret < 0)
{
/* UDP/IP packet send */
ret = psock_udp_send(psock, buf, len);
}
#endif /* CONFIG_NETDEV_MULTINIC && NET_UDP_HAVE_STACK */
#elif defined(NET_UDP_HAVE_STACK)
/* Only UDP/IP packet send */
ret = psock_udp_send(psock, buf, len);
#else
ret = -ENOSYS;
#endif /* CONFIG_NET_6LOWPAN */
}
#endif /* CONFIG_NET_UDP */
}
break;
#endif /* CONFIG_NET_UDP */
#ifdef CONFIG_NET_USRSOCK
case SOCK_USRSOCK_TYPE:
{
ret = usrsock_sendto(psock, buf, len, NULL, 0);
}
break;
#endif /*CONFIG_NET_USRSOCK*/
default:
{
/* EDESTADDRREQ. Signifies that the socket is not connection-mode
* and no peer address is set.
*/
ret = -EDESTADDRREQ;
}
break;
}
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_send != NULL);
ret = psock->s_sockif->si_send(psock, buf, len, flags);
leave_cancellation_point();
if (ret < 0)
{
nerr("ERROR: socket si_send() (or usrsock_sendto()) failed: %d\n", ret);
set_errno(-ret);
ret = ERROR;
}

View file

@ -42,6 +42,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <stdint.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
@ -52,7 +53,6 @@
#include "sixlowpan/sixlowpan.h"
#include "local/local.h"
#include "socket/socket.h"
#include "usrsock/usrsock.h"
/****************************************************************************
* Public Functions
@ -127,18 +127,16 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags, FAR const struct sockaddr *to,
socklen_t tolen)
{
socklen_t minlen;
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM) || \
defined(CONFIG_NET_USRSOCK)
ssize_t nsent;
#endif
int errcode;
DEBUGASSERT(psock != NULL && buf != NULL);
/* If to is NULL or tolen is zero, then this function is same as send (for
* connected socket types)
*/
if (!to || !tolen)
if (to == NULL || tolen <= 0)
{
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM) || \
defined(CONFIG_NET_USRSOCK)
@ -150,57 +148,6 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf,
#endif
}
#ifdef CONFIG_NET_USRSOCK
if (psock->s_type == SOCK_USRSOCK_TYPE)
{
/* Perform the usrsock sendto operation */
nsent = usrsock_sendto(psock, buf, len, to, tolen);
if (nsent < 0)
{
errcode = -nsent;
goto errout;
}
return nsent;
}
#endif
/* Verify that a valid address has been provided */
switch (to->sa_family)
{
#ifdef CONFIG_NET_IPv4
case AF_INET:
minlen = sizeof(struct sockaddr_in);
break;
#endif
#ifdef CONFIG_NET_IPv6
case AF_INET6:
minlen = sizeof(struct sockaddr_in6);
break;
#endif
#ifdef CONFIG_NET_LOCAL_DGRAM
case AF_LOCAL:
minlen = sizeof(sa_family_t);
break;
#endif
default:
nerr("ERROR: Unrecognized address family: %d\n", to->sa_family);
errcode = EAFNOSUPPORT;
goto errout;
}
if (tolen < minlen)
{
nerr("ERROR: Invalid address length: %d < %d\n", tolen, minlen);
errcode = EBADF;
goto errout;
}
/* Verify that the psock corresponds to valid, allocated socket */
if (!psock || psock->s_crefs <= 0)
@ -210,68 +157,21 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf,
goto errout;
}
/* If this is a connected socket, then return EISCONN */
/* Let the address family's send() method handle the operation */
if (psock->s_type != SOCK_DGRAM)
{
nerr("ERROR: Connected socket\n");
errcode = EISCONN;
goto errout;
}
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM)
/* Now handle the sendto() operation according to the socket domain,
* currently either IP or Unix domains.
*/
#ifdef CONFIG_NET_LOCAL_DGRAM
#ifdef CONFIG_NET_UDP
if (psock->s_domain == PF_LOCAL)
#endif
{
nsent = psock_local_sendto(psock, buf, len, flags, to, tolen);
}
#endif /* CONFIG_NET_LOCAL_DGRAM */
#ifdef CONFIG_NET_UDP
#ifdef CONFIG_NET_LOCAL_DGRAM
else
#endif
{
#if defined(CONFIG_NET_6LOWPAN)
/* Try 6LoWPAN UDP packet sendto() */
nsent = psock_6lowpan_udp_sendto(psock, buf, len, flags, to, tolen);
#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_UDP_HAVE_STACK)
if (nsent < 0)
{
/* UDP/IP packet sendto */
nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen);
}
#endif /* CONFIG_NETDEV_MULTINIC && NET_UDP_HAVE_STACK */
#elif defined(NET_UDP_HAVE_STACK)
nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen);
#else
nsent = -ENOSYS;
#endif /* CONFIG_NET_6LOWPAN */
}
#endif /* CONFIG_NET_UDP */
DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_send != NULL);
nsent = psock->s_sockif->si_send(psock, buf, len, flags);
/* Check if the domain-specific sendto() logic failed */
if (nsent < 0)
{
nerr("ERROR: UDP or Unix domain sendto() failed: %ld\n", (long)nsent);
nerr("ERROR: Family-specific send failed: %ld\n", (long)nsent);
errcode = -nsent;
goto errout;
}
return nsent;
#else
errcode = ENOSYS;
#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */
errout:
set_errno(errcode);

View file

@ -38,167 +38,15 @@
****************************************************************************/
#include <nuttx/config.h>
#ifdef CONFIG_NET
#include <sys/socket.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/net/udp.h>
#include "socket/socket.h"
#include "tcp/tcp.h"
#include "udp/udp.h"
#include "pkt/pkt.h"
#include "local/local.h"
#include "usrsock/usrsock.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: psock_tcp_alloc
*
* Description:
* Allocate and attach a TCP connection structure.
*
****************************************************************************/
#ifdef NET_TCP_HAVE_STACK
static int psock_tcp_alloc(FAR struct socket *psock)
{
/* Allocate the TCP connection structure */
FAR struct tcp_conn_s *conn = tcp_alloc(psock->s_domain);
if (!conn)
{
/* Failed to reserve a connection structure */
return -ENOMEM;
}
/* Set the reference count on the connection structure. This reference
* count will be incremented only if the socket is dup'ed
*/
DEBUGASSERT(conn->crefs == 0);
conn->crefs = 1;
/* Save the pre-allocated connection in the socket structure */
psock->s_conn = conn;
return OK;
}
#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
* Name: psock_udp_alloc
*
* Description:
* Allocate and attach a UDP connection structure.
*
****************************************************************************/
#ifdef NET_UDP_HAVE_STACK
static int psock_udp_alloc(FAR struct socket *psock)
{
/* Allocate the UDP connection structure */
FAR struct udp_conn_s *conn = udp_alloc(psock->s_domain);
if (!conn)
{
/* Failed to reserve a connection structure */
return -ENOMEM;
}
/* Set the reference count on the connection structure. This reference
* count will be incremented only if the socket is dup'ed
*/
DEBUGASSERT(conn->crefs == 0);
conn->crefs = 1;
/* Save the pre-allocated connection in the socket structure */
psock->s_conn = conn;
return OK;
}
#endif /* NET_UDP_HAVE_STACK */
/****************************************************************************
* Name: psock_pkt_alloc
*
* Description:
* Allocate and attach a raw packet connection structure.
*
****************************************************************************/
#ifdef CONFIG_NET_PKT
static int psock_pkt_alloc(FAR struct socket *psock)
{
/* Allocate the packet socket connection structure and save in the new
* socket instance.
*/
FAR struct pkt_conn_s *conn = pkt_alloc();
if (!conn)
{
/* Failed to reserve a connection structure */
return -ENOMEM;
}
/* Set the reference count on the connection structure. This reference
* count will be incremented only if the socket is dup'ed
*/
DEBUGASSERT(conn->crefs == 0);
conn->crefs = 1;
/* Save the pre-allocated connection in the socket structure */
psock->s_conn = conn;
return OK;
}
#endif /* CONFIG_NET_PKT */
/****************************************************************************
* Name: psock_local_alloc
*
* Description:
* Allocate and attach a local, Unix domain connection structure.
*
****************************************************************************/
#ifdef CONFIG_NET_LOCAL
static int psock_local_alloc(FAR struct socket *psock)
{
/* Allocate the local connection structure */
FAR struct local_conn_s *conn = local_alloc();
if (!conn)
{
/* Failed to reserve a connection structure */
return -ENOMEM;
}
/* Set the reference count on the connection structure. This reference
* count will be incremented only if the socket is dup'ed
*/
DEBUGASSERT(conn->lc_crefs == 0);
conn->lc_crefs = 1;
/* Save the pre-allocated connection in the socket structure */
psock->s_conn = conn;
return OK;
}
#endif /* CONFIG_NET_LOCAL */
#ifdef CONFIG_NET
/****************************************************************************
* Public Functions
@ -244,180 +92,11 @@ static int psock_local_alloc(FAR struct socket *psock)
int psock_socket(int domain, int type, int protocol, FAR struct socket *psock)
{
#ifdef CONFIG_NET_LOCAL
bool ipdomain = false;
#endif
bool dgramok = false;
int ret;
FAR const struct sock_intf_s *sockif = NULL;
int errcode;
#ifdef CONFIG_NET_USRSOCK
switch (domain)
{
default:
break;
case PF_INET:
case PF_INET6:
{
#ifndef CONFIG_NET_USRSOCK_UDP
if (type == SOCK_DGRAM)
break;
#endif
#ifndef CONFIG_NET_USRSOCK_TCP
if (type == SOCK_STREAM)
break;
#endif
psock->s_type = 0;
psock->s_conn = NULL;
ret = usrsock_socket(domain, type, protocol, psock);
if (ret >= 0)
{
/* Successfully handled and opened by usrsock daemon. */
return OK;
}
else if (ret == -ENETDOWN)
{
/* Net down means that usrsock daemon is not running.
* Attempt to open socket with kernel networking stack. */
}
else
{
errcode = -ret;
goto errout;
}
}
}
#endif /* CONFIG_NET_USRSOCK */
/* Only PF_INET, PF_INET6 or PF_PACKET domains supported */
switch (domain)
{
#ifdef CONFIG_NET_IPv4
case PF_INET:
#ifdef CONFIG_NET_LOCAL
ipdomain = true;
#endif
dgramok = true;
break;
#endif
#ifdef CONFIG_NET_IPv6
case PF_INET6:
#ifdef CONFIG_NET_LOCAL
ipdomain = true;
#endif
dgramok = true;
break;
#endif
#ifdef CONFIG_NET_LOCAL
case PF_LOCAL:
dgramok = true;
break;
#endif
#ifdef CONFIG_NET_PKT
case PF_PACKET:
break;
#endif
default:
errcode = EAFNOSUPPORT;
goto errout;
}
#if defined(CONFIG_NET_LOCAL) && !defined(CONFIG_NET_LOCAL_STREAM) && !defined(CONFIG_NET_LOCAL_DGRAM)
UNUSED(ipdomain);
#endif
/* Only SOCK_STREAM, SOCK_DGRAM and possible SOCK_RAW are supported */
switch (type)
{
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM)
case SOCK_STREAM:
#ifdef CONFIG_NET_TCP
#ifdef CONFIG_NET_LOCAL_STREAM
if (ipdomain)
#endif
{
if ((protocol != 0 && protocol != IPPROTO_TCP) || !dgramok)
{
errcode = EPROTONOSUPPORT;
goto errout;
}
}
#endif /* CONFIG_NET_TCP */
#ifdef CONFIG_NET_LOCAL_STREAM
#ifdef CONFIG_NET_TCP
else
#endif
{
if (protocol != 0 || !dgramok)
{
errcode = EPROTONOSUPPORT;
goto errout;
}
}
#endif /* CONFIG_NET_LOCAL_STREAM */
break;
#endif /* CONFIG_NET_TCP || CONFIG_NET_LOCAL_STREAM */
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM)
case SOCK_DGRAM:
#ifdef CONFIG_NET_UDP
#ifdef CONFIG_NET_LOCAL_DGRAM
if (ipdomain)
#endif
{
if ((protocol != 0 && protocol != IPPROTO_UDP) || !dgramok)
{
errcode = EPROTONOSUPPORT;
goto errout;
}
}
#endif /* CONFIG_NET_UDP */
#ifdef CONFIG_NET_LOCAL_DGRAM
#ifdef CONFIG_NET_UDP
else
#endif
{
if (protocol != 0 || !dgramok)
{
errcode = EPROTONOSUPPORT;
goto errout;
}
}
#endif /* CONFIG_NET_LOCAL_DGRAM */
break;
#endif /* CONFIG_NET_UDP || CONFIG_NET_LOCAL_DGRAM */
#ifdef CONFIG_NET_PKT
case SOCK_RAW:
if (dgramok)
{
errcode = EPROTONOSUPPORT;
goto errout;
}
break;
#endif
default:
errcode = EPROTONOSUPPORT;
goto errout;
}
/* Everything looks good. Initialize the socket structure */
/* Save the protocol type */
int ret;
/* Initialize the socket structure */
psock->s_domain = domain;
psock->s_type = type;
@ -426,115 +105,29 @@ int psock_socket(int domain, int type, int protocol, FAR struct socket *psock)
psock->s_sndcb = NULL;
#endif
/* Allocate the appropriate connection structure. This reserves the
* the connection structure is is unallocated at this point. It will
* not actually be initialized until the socket is connected.
/* Get the socket interface */
sockif = net_sockif(domain);
if (sockif == NULL)
{
nerr("ERROR: socket address family unsupported: %d\n", domain);
errcode = EAFNOSUPPORT;
goto errout;
}
/* The remaining of the socket initialization depends on the address
* family.
*/
errcode = ENOMEM; /* Assume failure to allocate connection instance */
switch (type)
DEBUGASSERT(sockif->si_setup != NULL);
psock->s_sockif = sockif;
ret = sockif->si_setup(psock, protocol);
if (ret < 0)
{
#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_STREAM)
case SOCK_STREAM:
{
#ifdef CONFIG_NET_TCP
#ifdef CONFIG_NET_LOCAL_STREAM
if (ipdomain)
#endif
{
#ifdef NET_TCP_HAVE_STACK
/* Allocate and attach the TCP connection structure */
ret = psock_tcp_alloc(psock);
#else
ret = -ENETDOWN;
#endif
}
#endif /* CONFIG_NET_TCP */
#ifdef CONFIG_NET_LOCAL_STREAM
#ifdef CONFIG_NET_TCP
else
#endif
{
/* Allocate and attach the local connection structure */
ret = psock_local_alloc(psock);
}
#endif /* CONFIG_NET_LOCAL_STREAM */
/* Check for failures to allocate the connection structure. */
if (ret < 0)
{
/* Failed to reserve a connection structure */
errcode = -ret;
goto errout;
}
}
break;
#endif
#if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_LOCAL_DGRAM)
case SOCK_DGRAM:
{
#ifdef CONFIG_NET_UDP
#ifdef CONFIG_NET_LOCAL_DGRAM
if (ipdomain)
#endif
{
#ifdef NET_UDP_HAVE_STACK
/* Allocate and attach the UDP connection structure */
ret = psock_udp_alloc(psock);
#else
ret = -ENETDOWN;
#endif
}
#endif /* CONFIG_NET_UDP */
#ifdef CONFIG_NET_LOCAL_DGRAM
#ifdef CONFIG_NET_UDP
else
#endif
{
/* Allocate and attach the local connection structure */
ret = psock_local_alloc(psock);
}
#endif /* CONFIG_NET_LOCAL_DGRAM */
/* Check for failures to allocate the connection structure. */
if (ret < 0)
{
/* Failed to reserve a connection structure */
errcode = -ret;
goto errout;
}
}
break;
#endif
#ifdef CONFIG_NET_PKT
case SOCK_RAW:
{
ret = psock_pkt_alloc(psock);
if (ret < 0)
{
/* Failed to reserve a connection structure */
errcode = -ret;
goto errout;
}
}
break;
#endif
default:
break;
nerr("ERROR: socket si_setup() failed: %d\n", ret);
errcode = -ret;
goto errout;
}
return OK;
@ -592,6 +185,7 @@ int socket(int domain, int type, int protocol)
sockfd = sockfd_allocate(0);
if (sockfd < 0)
{
nerr("ERROR: Failed to allodate a socket descriptor\n");
set_errno(ENFILE);
return ERROR;
}
@ -610,8 +204,9 @@ int socket(int domain, int type, int protocol)
ret = psock_socket(domain, type, protocol, psock);
if (ret < 0)
{
/* Error already set by psock_socket() */
/* errno already set by psock_socket() */
nerr("ERROR: psock_socket() failed: %d\n", ret);
goto errout;
}

View file

@ -149,6 +149,10 @@ extern "C"
#define EXTERN extern
#endif
#if defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_IPv6)
EXTERN const struct sock_intf_s g_inet_sockif;
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
@ -223,6 +227,23 @@ void sockfd_release(int sockfd);
FAR struct socket *sockfd_socket(int sockfd);
/****************************************************************************
* Name: net_sockif
*
* Description:
* Return the socket interface associated with this address family.
*
* Parameters:
* family - Address family
*
* Returned Value:
* On success, a non-NULL instance of struct sock_intf_s is returned. NULL
* is returned only if the address family is not supported.
*
****************************************************************************/
FAR const struct sock_intf_s *net_sockif(sa_family_t family);
/****************************************************************************
* Name: net_startmonitor
*
@ -410,13 +431,99 @@ int net_timeo(systime_t start_time, socktimeo_t timeo);
* In this case the process will also receive a SIGPIPE unless
* MSG_NOSIGNAL is set.
*
* Assumptions:
*
****************************************************************************/
ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
int flags);
/****************************************************************************
* Name: inet_connect
*
* Description:
* inet_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
* datagrams are received. If the socket is of type SOCK_STREAM or
* SOCK_SEQPACKET, this call attempts to make a connection to the socket
* that is bound to the address specified by 'addr'.
*
* Generally, connection-based protocol sockets may successfully
* inet_connect() only once; connectionless protocol sockets may use
* inet_connect() multiple times to change their association.
* Connectionless sockets may dissolve the association by connecting to
* an address with the sa_family member of sockaddr set to AF_UNSPEC.
*
* Parameters:
* psock Pointer to a socket structure initialized by psock_socket()
* addr Server address (form depends on type of socket)
* addrlen Length of actual 'addr'
*
* Returned Value:
* 0 on success; a negated errno value on failue. See connect() for the
* list of appropriate errno values to be returned.
*
****************************************************************************/
int inet_connect(FAR struct socket *psock, FAR const struct sockaddr *addr,
socklen_t addrlen);
/****************************************************************************
* Name: inet_recvfrom
*
* Description:
* Implements the socket recvfrom interface for the case of the AF_INET
* and AF_INET6 address families. inet_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' is
* initialized to the size of the buffer associated with from, and
* modified on return to indicate the actual size of the address stored
* there.
*
* 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 inet_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
int flags, FAR struct sockaddr *from,
FAR socklen_t *fromlen);
/****************************************************************************
* Name: inet_close
*
* Description:
* Performs the close operation on an AF_INET or AF_INET6 socket instance
*
* Parameters:
* psock Socket instance
*
* Returned Value:
* 0 on success; -1 on error with errno set appropriately.
*
* Assumptions:
*
****************************************************************************/
int inet_close(FAR struct socket *psock);
#undef EXTERN
#if defined(__cplusplus)
}

View file

@ -874,7 +874,7 @@ static void enable_feature(const char *destconfig, const char *varname)
int ret;
snprintf(g_buffer, BUFFER_SIZE,
"kconfig-tweak --file %s --disable %s",
"kconfig-tweak --file %s --enable %s",
destconfig, varname);
ret = system(g_buffer);