diff --git a/arch/arm/src/stm32f7/chip/stm32_ethernet.h b/arch/arm/src/stm32f7/chip/stm32_ethernet.h index 962cb6d922..dfb3a34745 100644 --- a/arch/arm/src/stm32f7/chip/stm32_ethernet.h +++ b/arch/arm/src/stm32f7/chip/stm32_ethernet.h @@ -47,7 +47,7 @@ * families */ -#if defined(CONFIG_STM32F7_STM32F74XX) || defined(CONFIG_STM32F7_STM32F75XX) \ +#if defined(CONFIG_STM32F7_STM32F74XX) || defined(CONFIG_STM32F7_STM32F75XX) || \ defined(CONFIG_STM32F7_STM32F76XX) || defined(CONFIG_STM32F7_STM32F77XX) /**************************************************************************************************** diff --git a/arch/arm/src/stm32f7/stm32_ethernet.c b/arch/arm/src/stm32f7/stm32_ethernet.c index 3573100631..dac4787a8c 100644 --- a/arch/arm/src/stm32f7/stm32_ethernet.c +++ b/arch/arm/src/stm32f7/stm32_ethernet.c @@ -82,6 +82,11 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ + +/* Memory synchronization */ + +#define MEMORY_SYNC() do { ARM_DSB(); ARM_ISB(); } while (0) + /* Configuration ************************************************************/ /* See configs/stm3240g-eval/README.txt for an explanation of the configuration * settings. @@ -1219,6 +1224,8 @@ static int stm32_transmit(struct stm32_ethmac_s *priv) /* Check if the TX Buffer unavailable flag is set */ + MEMORY_SYNC(); + if ((stm32_getreg(STM32_ETH_DMASR) & ETH_DMAINT_TBUI) != 0) { /* Clear TX Buffer unavailable flag */ @@ -2210,6 +2217,8 @@ static int stm32_interrupt(int irq, void *context, FAR void *arg) wd_cancel(priv->txtimeout); } + DEBUGASSERT(work_available(&priv->irqwork)); + /* Schedule to perform the interrupt processing on the worker thread. */ work_queue(ETHWORK, &priv->irqwork, stm32_interrupt_work, priv, 0); @@ -2287,6 +2296,8 @@ static void stm32_txtimeout_expiry(int argc, uint32_t arg, ...) /* Schedule to perform the TX timeout processing on the worker thread. */ + DEBUGASSERT(work_available(&priv->irqwork)); + work_queue(ETHWORK, &priv->irqwork, stm32_txtimeout_work, priv, 0); } @@ -2386,7 +2397,14 @@ static void stm32_poll_expiry(int argc, uint32_t arg, ...) /* Schedule to perform the interrupt processing on the worker thread. */ - work_queue(ETHWORK, &priv->pollwork, stm32_poll_work, priv, 0); + if (work_available(&priv->pollwork)) + { + work_queue(ETHWORK, &priv->pollwork, stm32_poll_work, priv, 0); + } + else + { + (void)wd_start(priv->txpoll, STM32_WDDELAY, stm32_poll_expiry, 1, priv); + } } /**************************************************************************** diff --git a/configs/nucleo-144/include/board.h b/configs/nucleo-144/include/board.h index 18d2727502..1027e514ec 100644 --- a/configs/nucleo-144/include/board.h +++ b/configs/nucleo-144/include/board.h @@ -449,7 +449,7 @@ * -------- ------------ ------------- * PG11 RMII_TX_EN TXEN * PG13 RMII_TXD0 TXD0 - * PG14 RMII_TXD1 TXD1 + * PB13 RMII_TXD1 TXD1 * PC4 RMII_RXD0 RXD0/MODE0 * PC5 RMII_RXD1 RXD1/MODE1 * PG2 RMII_RXER RXER/PHYAD0 -- Not used @@ -466,7 +466,7 @@ #define GPIO_ETH_RMII_TX_EN GPIO_ETH_RMII_TX_EN_2 #define GPIO_ETH_RMII_TXD0 GPIO_ETH_RMII_TXD0_2 -#define GPIO_ETH_RMII_TXD1 GPIO_ETH_RMII_TXD1_2 +#define GPIO_ETH_RMII_TXD1 GPIO_ETH_RMII_TXD1_1 /************************************************************************************ * Public Data diff --git a/configs/sim/README.txt b/configs/sim/README.txt index 20f76fbf29..be8d47456c 100644 --- a/configs/sim/README.txt +++ b/configs/sim/README.txt @@ -909,6 +909,9 @@ udgram nsh> server & nsh> client + For the sake of sanity, binfs and logins are disabled in this + configuration. + unionfs This is a version of NSH dedicated to performing the simple test diff --git a/configs/sim/udgram/defconfig b/configs/sim/udgram/defconfig index 913e36117e..64f8e6f20a 100644 --- a/configs/sim/udgram/defconfig +++ b/configs/sim/udgram/defconfig @@ -15,14 +15,15 @@ CONFIG_DEBUG_SYMBOLS=y CONFIG_DISABLE_POLL=y CONFIG_EXAMPLES_HELLO=y CONFIG_EXAMPLES_NSH=y +CONFIG_EXAMPLES_UDGRAM_CLIENT_STACKSIZE=8192 +CONFIG_EXAMPLES_UDGRAM_SERVER_STACKSIZE=8192 CONFIG_EXAMPLES_UDGRAM=y CONFIG_FAT_LCNAMES=y CONFIG_FAT_LFN=y -CONFIG_FS_BINFS=y CONFIG_FS_FAT=y CONFIG_FS_PROCFS=y CONFIG_FS_ROMFS=y -CONFIG_IDLETHREAD_STACKSIZE=4096 +CONFIG_IDLETHREAD_STACKSIZE=8192 CONFIG_LIBC_EXECFUNCS=y CONFIG_MAX_TASKS=64 CONFIG_NET_LOCAL=y @@ -45,4 +46,4 @@ CONFIG_SIM_WALLTIME=y CONFIG_START_MONTH=6 CONFIG_START_YEAR=2008 CONFIG_USER_ENTRYPOINT="nsh_main" -CONFIG_USERMAIN_STACKSIZE=4096 +CONFIG_USERMAIN_STACKSIZE=8192 diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index 7dee03d5ae..36f90d1a56 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -108,6 +108,7 @@ typedef uint8_t sockcaps_t; */ struct socket; /* Forward reference */ +struct pollfd; /* Forward reference */ struct sock_intf_s { @@ -116,16 +117,27 @@ struct sock_intf_s 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_getsockname)(FAR struct socket *psock, + FAR struct sockaddr *addr, FAR 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); +#ifndef CONFIG_DISABLE_POLL + CODE int (*si_poll)(FAR struct socket *psock, + FAR struct pollfd *fds, bool setup); +#endif 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); +#ifdef CONFIG_NET_SENDFILE + CODE ssize_t (*si_sendfile)(FAR struct socket *psock, + FAR struct file *infile, FAR off_t *offset, + size_t count) +#endif 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); diff --git a/net/local/local.h b/net/local/local.h index 983e17950a..3409cc9608 100644 --- a/net/local/local.h +++ b/net/local/local.h @@ -330,7 +330,9 @@ int local_release(FAR struct local_conn_s *conn); * ****************************************************************************/ +#ifdef CONFIG_NET_LOCAL_STREAM int local_listen(FAR struct socket *psock, int backlog); +#endif /**************************************************************************** * Name: local_accept @@ -355,8 +357,10 @@ int local_listen(FAR struct socket *psock, int backlog); * ****************************************************************************/ +#ifdef CONFIG_NET_LOCAL_STREAM int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, FAR socklen_t *addrlen, FAR void **newconn); +#endif /**************************************************************************** * Name: psock_local_send diff --git a/net/local/local_bind.c b/net/local/local_bind.c index 316fe3e2e9..08a82efca3 100644 --- a/net/local/local_bind.c +++ b/net/local/local_bind.c @@ -69,8 +69,8 @@ int psock_local_bind(FAR struct socket *psock, (FAR const struct sockaddr_un *)addr; int namelen; - DEBUGASSERT(psock && psock->s_conn && unaddr && - unaddr->sun_family == AF_LOCAL && + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && + unaddr != NULL && unaddr->sun_family == AF_LOCAL && addrlen >= sizeof(sa_family_t)); conn = (FAR struct local_conn_s *)psock->s_conn; @@ -79,7 +79,7 @@ int psock_local_bind(FAR struct socket *psock, conn->lc_proto = psock->s_type; - /* No determine the type of the Unix domain socket by comparing the size + /* Now determine the type of the Unix domain socket by comparing the size * of the address description. */ diff --git a/net/local/local_connect.c b/net/local/local_connect.c index ee9a1dc2c9..0d385f1fd8 100644 --- a/net/local/local_connect.c +++ b/net/local/local_connect.c @@ -38,7 +38,6 @@ ****************************************************************************/ #include -#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL_STREAM) #include #include @@ -55,6 +54,8 @@ #include "socket/socket.h" #include "local/local.h" +#ifdef CONFIG_NET_LOCAL_STREAM + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -343,4 +344,4 @@ int psock_local_connect(FAR struct socket *psock, return -EADDRNOTAVAIL; } -#endif /* CONFIG_NET && CONFIG_NET_LOCAL_STREAM */ +#endif /* CONFIG_NET_LOCAL_STREAM */ diff --git a/net/local/local_listen.c b/net/local/local_listen.c index 996bb049fe..be6aac3516 100644 --- a/net/local/local_listen.c +++ b/net/local/local_listen.c @@ -43,6 +43,7 @@ #include #include #include +#include #include @@ -98,7 +99,7 @@ int local_listen(FAR struct socket *psock, int backlog) 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); + psock->s_domain, psock->s_type); return -EOPNOTSUPP; } diff --git a/net/local/local_send.c b/net/local/local_send.c index c8f1cd92a0..4d37cbd9cc 100644 --- a/net/local/local_send.c +++ b/net/local/local_send.c @@ -38,7 +38,6 @@ ****************************************************************************/ #include -#if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL_STREAM) #include #include @@ -49,6 +48,8 @@ #include "local/local.h" +#ifdef CONFIG_NET_LOCAL_STREAM + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -101,4 +102,4 @@ ssize_t psock_local_send(FAR struct socket *psock, FAR const void *buf, return ret < 0 ? ret : len; } -#endif /* CONFIG_NET && CONFIG_NET_LOCAL_STREAM */ +#endif /* CONFIG_NET_LOCAL_STREAM */ diff --git a/net/local/local_sockif.c b/net/local/local_sockif.c index 56c4b513a9..3bb225de70 100644 --- a/net/local/local_sockif.c +++ b/net/local/local_sockif.c @@ -41,6 +41,8 @@ #include #include +#include +#include #include #include #include @@ -48,6 +50,7 @@ #include #include +#include #include "local/local.h" @@ -62,10 +65,22 @@ 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_getsockname(FAR struct socket *psock, + FAR struct sockaddr *addr, FAR socklen_t *addrlen); +#ifndef CONFIG_NET_LOCAL_STREAM +static int local_listen(FAR struct socket *psock, int backlog); +#endif 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); +#ifndef CONFIG_NET_LOCAL_STREAM +static int local_accept(FAR struct socket *psock, + FAR struct sockaddr *addr, FAR socklen_t *addrlen, + FAR struct socket *newsock); +#endif +#ifndef CONFIG_DISABLE_POLL +static int local_poll(FAR struct socket *psock, + FAR struct pollfd *fds, bool setup); +#endif 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, @@ -79,17 +94,24 @@ static int local_close(FAR struct socket *psock); 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 */ + local_setup, /* si_setup */ + local_sockcaps, /* si_sockcaps */ + local_addref, /* si_addref */ + local_bind, /* si_bind */ + local_getsockname, /* si_getsockname */ + local_listen, /* si_listen */ + local_connect, /* si_connect */ + local_accept, /* si_accept */ +#ifndef CONFIG_DISABLE_POLL + local_poll, /* si_poll */ +#endif + local_send, /* si_send */ + local_sendto, /* si_sendto */ +#ifdef CONFIG_NET_SENDFILE + NULL, /* si_sendfile */ +#endif + local_recvfrom, /* si_recvfrom */ + local_close /* si_close */ }; /**************************************************************************** @@ -104,6 +126,7 @@ const struct sock_intf_s g_local_sockif = * ****************************************************************************/ +#if defined(CONFIG_NET_LOCAL_STREAM) || defined(CONFIG_NET_LOCAL_DGRAM) static int local_sockif_alloc(FAR struct socket *psock) { /* Allocate the local connection structure */ @@ -128,6 +151,7 @@ static int local_sockif_alloc(FAR struct socket *psock) psock->s_conn = conn; return OK; } +#endif /**************************************************************************** * Name: local_setup @@ -158,7 +182,7 @@ static int local_setup(FAR struct socket *psock, int protocol) switch (psock->s_type) { -#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL_STREAM case SOCK_STREAM: if (protocol != 0 && protocol != IPPROTO_TCP) { @@ -168,9 +192,9 @@ static int local_setup(FAR struct socket *psock, int protocol) /* Allocate and attach the local connection structure */ return local_sockif_alloc(psock); -#endif /* CONFIG_NET_TCP */ +#endif /* CONFIG_NET_LOCAL_STREAM */ -#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL_DGRAM case SOCK_DGRAM: if (protocol != 0 && protocol != IPPROTO_UDP) { @@ -180,7 +204,7 @@ static int local_setup(FAR struct socket *psock, int protocol) /* Allocate and attach the local connection structure */ return local_sockif_alloc(psock); -#endif /* CONFIG_NET_UDP */ +#endif /* CONFIG_NET_LOCAL_DGRAM */ default: return -EPROTONOSUPPORT; @@ -274,17 +298,17 @@ static int local_bind(FAR struct socket *psock, { /* Bind a local TCP/IP stream or datagram socket */ -#if defined(ONFIG_NET_TCP) || defined(CONFIG_NET_UDP) -#ifdef CONFIG_NET_TCP +#if defined(ONFIG_NET_TCP) || defined(CONFIG_NET_LOCAL_DGRAM) +#ifdef CONFIG_NET_LOCAL_STREAM case SOCK_STREAM: #endif -#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL_DGRAM case SOCK_DGRAM: #endif { /* Bind the Unix domain connection structure */ - ret psock_local_bind(psock, addr, addrlen); + ret = psock_local_bind(psock, addr, addrlen); /* Mark the socket bound */ @@ -294,7 +318,7 @@ static int local_bind(FAR struct socket *psock, } } break; -#endif /* CONFIG_NET_TCP || CONFIG_NET_UDP*/ +#endif /* CONFIG_NET_LOCAL_STREAM || CONFIG_NET_LOCAL_DGRAM*/ default: ret = -EBADF; @@ -304,6 +328,129 @@ static int local_bind(FAR struct socket *psock, return ret; } +/**************************************************************************** + * Name: local_getsockname + * + * Description: + * The local_getsockname() function retrieves the locally-bound name of + * the specified local socket, stores this address in the sockaddr + * structure pointed to by the 'addr' argument, and stores the length of + * this address in the object pointed to by the 'addrlen' argument. + * + * If the actual length of the address is greater than the length of the + * supplied sockaddr structure, the stored address will be truncated. + * + * If the socket has not been bound to a local name, the value stored in + * the object pointed to by address is unspecified. + * + * Parameters: + * psock Socket structure of the socket to be queried + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + * Returned Value: + * On success, 0 is returned, the 'addr' argument points to the address + * of the socket, and the 'addrlen' argument points to the length of the + * address. Otherwise, a negated errno value is returned. See + * getsockname() for the list of appropriate error numbers. + * + ****************************************************************************/ + +static int local_getsockname(FAR struct socket *psock, + FAR struct sockaddr *addr, + FAR socklen_t *addrlen) +{ + FAR struct sockaddr_un *unaddr = (FAR struct sockaddr_un *)addr; + FAR struct local_conn_s *conn; + + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && + unaddr != NULL && addrlen != NULL && + *addrlen >= sizeof(sa_family_t)); + + if (*addrlen < sizeof(sa_family_t)) + { + /* This is apparently not an error */ + + *addrlen = 0; + return OK; + } + + conn = (FAR struct local_conn_s *)psock->s_conn; + + /* Save the address family */ + + unaddr->sun_family = AF_LOCAL; + if (*addrlen > sizeof(sa_family_t)) + { + /* Now copy the address description. */ + + if (conn->lc_type == LOCAL_TYPE_UNNAMED) + { + /* Zero-length sun_path... This is an abstract Unix domain socket */ + + *addrlen = sizeof(sa_family_t); + } + else /* conn->lctype = LOCAL_TYPE_PATHNAME */ + { + /* Get the full length of the socket name (including null terminator) */ + + int namelen = strlen(conn->lc_path) + 1; + + /* Get the available length in the user-provided buffer. */ + + int pathlen = *addrlen - sizeof(sa_family_t); + + /* Clip the socket name size so that if fits in the user buffer */ + + if (pathlen < namelen) + { + namelen = pathlen; + } + + /* Copy the path into the user address structure */ + + (void)strncpy(unaddr->sun_path, conn->lc_path, namelen); + unaddr->sun_path[pathlen - 1] = '\0'; + + *addrlen = sizeof(sa_family_t) + namelen; + } + } + + return OK; +} + +/**************************************************************************** + * Name: local_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 local + * unix 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. + * + ****************************************************************************/ + +#ifndef CONFIG_NET_LOCAL_STREAM +int local_listen(FAR struct socket *psock, int backlog) +{ + return -EOPNOTSUPP; +} +#endif + /**************************************************************************** * Name: local_connect * @@ -350,7 +497,7 @@ static int local_connect(FAR struct socket *psock, switch (psock->s_type) { -#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL_STREAM case SOCK_STREAM: { /* Verify that the socket is not already connected */ @@ -365,23 +512,114 @@ static int local_connect(FAR struct socket *psock, return psock_local_connect(psock, addr); } break; -#endif /* CONFIG_NET_TCP */ +#endif /* CONFIG_NET_LOCAL_STREAM */ -#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL_DGRAM case SOCK_DGRAM: { /* Perform the datagram connection logic */ - - return psock_local_connect(psock, addr); +#warning Missing logic + return -ENOSYS; } break; -#endif /* CONFIG_NET_UDP */ +#endif /* CONFIG_NET_LOCAL_DGRAM */ default: return -EBADF; } } +/**************************************************************************** + * 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. + * + ****************************************************************************/ + +#ifndef CONFIG_NET_LOCAL_STREAM +static int local_accept(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen, FAR struct socket *newsock) +{ + return -EAFNOSUPPORT; +} +#endif + +/**************************************************************************** + * Name: local_poll + * + * Description: + * The standard poll() operation redirects operations on socket descriptors + * to local_poll which, indiectly, calls to function. + * + * Input Parameters: + * psock - An instance of the internal socket structure. + * fds - The structure describing the events to be monitored, OR NULL if + * this is a request to stop monitoring events. + * setup - true: Setup up the poll; false: Teardown the poll + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_POLL +static int local_poll(FAR struct socket *psock, FAR struct pollfd *fds, + bool setup) +{ +#ifndef HAVE_LOCAL_POLL + return -ENOSYS; +#else + /* Check if we are setting up or tearing down the poll */ + + if (setup) + { + /* Perform the TCP/IP poll() setup */ + + return local_pollsetup(psock, fds); + } + else + { + /* Perform the TCP/IP poll() teardown */ + + return loal_pollteardown(psock, fds); + } +#endif /* HAVE_LOCAL_POLL */ +} +#endif /* !CONFIG_DISABLE_POLL */ + /**************************************************************************** * Name: local_send * @@ -408,7 +646,7 @@ static ssize_t local_send(FAR struct socket *psock, FAR const void *buf, switch (psock->s_type) { -#ifdef CONFIG_NET_TCP +#ifdef CONFIG_NET_LOCAL_STREAM case SOCK_STREAM: { /* Local TCP packet send */ @@ -416,9 +654,9 @@ static ssize_t local_send(FAR struct socket *psock, FAR const void *buf, ret = psock_local_send(psock, buf, len, flags); } break; -#endif /* CONFIG_NET_TCP */ +#endif /* CONFIG_NET_LOCAL_STREAM */ -#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL_DGRAM case SOCK_DGRAM: { /* Local UDP packet send */ @@ -426,7 +664,7 @@ static ssize_t local_send(FAR struct socket *psock, FAR const void *buf, ret = -ENOSYS; } break; -#endif /* CONFIG_NET_UDP */ +#endif /* CONFIG_NET_LOCAL_DGRAM */ default: { @@ -478,7 +716,7 @@ ssize_t local_sendto(FAR struct socket *psock, FAR const void *buf, return -EAFNOSUPPORT; } -#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL_DGRAM /* If this is a connected socket, then return EISCONN */ if (psock->s_type != SOCK_DGRAM) @@ -519,11 +757,11 @@ static int local_close(FAR struct socket *psock) switch (psock->s_type) { -#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) -#ifdef CONFIG_NET_TCP +#if defined(CONFIG_NET_LOCAL_STREAM) || defined(CONFIG_NET_LOCAL_DGRAM) +#ifdef CONFIG_NET_LOCAL_STREAM case SOCK_STREAM: #endif -#ifdef CONFIG_NET_UDP +#ifdef CONFIG_NET_LOCAL_DGRAM case SOCK_DGRAM: #endif { @@ -547,7 +785,7 @@ static int local_close(FAR struct socket *psock) return OK; } -#endif /* CONFIG_NET_TCP || CONFIG_NET_UDP*/ +#endif /* CONFIG_NET_LOCAL_STREAM || CONFIG_NET_LOCAL_DGRAM*/ default: return -EBADF; diff --git a/net/pkt/Kconfig b/net/pkt/Kconfig index ae9c7891f5..147933d1ad 100644 --- a/net/pkt/Kconfig +++ b/net/pkt/Kconfig @@ -8,6 +8,7 @@ menu "Raw Socket Support" config NET_PKT bool "Socket packet socket support" default n + depends on NET_ETHERNET || EXPERIMENTAL ---help--- Enable or disable support for packet sockets. @@ -17,6 +18,8 @@ config NET_PKT a packet socket will bypass the network altogether and be placed in the transmission buffer of the network interface driver. + REVISIT: Currently only implemented for Ethernet. + if NET_PKT config NET_PKT_CONNS diff --git a/net/pkt/pkt_poll.c b/net/pkt/pkt_poll.c index c289b146d8..fe195148af 100644 --- a/net/pkt/pkt_poll.c +++ b/net/pkt/pkt_poll.c @@ -86,7 +86,7 @@ void pkt_poll(FAR struct net_driver_s *dev, FAR struct pkt_conn_s *conn) { /* Setup for the application callback */ - dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN(dev) + IPv4UDP_HDRLEN]; + dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN(dev)]; dev->d_len = 0; dev->d_sndlen = 0; diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c index ae2542d619..c1af74ba93 100644 --- a/net/pkt/pkt_sockif.c +++ b/net/pkt/pkt_sockif.c @@ -41,11 +41,15 @@ #include #include +#include +#include #include #include #include #include +#include +#include #include "pkt/pkt.h" @@ -60,11 +64,17 @@ 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_getsockname(FAR struct socket *psock, + FAR struct sockaddr *addr, FAR 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); +#ifndef CONFIG_DISABLE_POLL +static int pkt_poll(FAR struct socket *psock, + FAR struct pollfd *fds, bool setup); +#endif 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, @@ -78,17 +88,24 @@ static int pkt_close(FAR struct socket *psock); 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 */ + pkt_setup, /* si_setup */ + pkt_sockcaps, /* si_sockcaps */ + pkt_addref, /* si_addref */ + pkt_bind, /* si_bind */ + pkt_getsockname, /* si_getsockname */ + pkt_listen, /* si_listen */ + pkt_connect, /* si_connect */ + pkt_accept, /* si_accept */ +#ifndef CONFIG_DISABLE_POLL + pkt_poll, /* si_poll */ +#endif + pkt_send, /* si_send */ + pkt_sendto, /* si_sendto */ +#ifdef CONFIG_NET_SENDFILE + NULL, /* si_sendfile */ +#endif + pkt_recvfrom, /* si_recvfrom */ + pkt_close /* si_close */ }; /**************************************************************************** @@ -294,7 +311,7 @@ static int pkt_connect(FAR struct socket *psock, ****************************************************************************/ static int pkt_accept(FAR struct socket *psock, FAR struct sockaddr *addr, - FAR socklen_t *addrlen, FAR struct socket *newsock) + FAR socklen_t *addrlen, FAR struct socket *newsock) { return -EAFNOSUPPORT; } @@ -336,10 +353,10 @@ static int pkt_bind(FAR struct socket *psock, FAR const struct sockaddr *addr, /* Verify that a valid address has been provided */ - if (addr->sa_family != AF_PACKET || addrlen < sizeof(struct sockaddr_ll) + if (addr->sa_family != AF_PACKET || addrlen < sizeof(struct sockaddr_ll)) { nerr("ERROR: Invalid address length: %d < %d\n", - addrlen, sizeof(struct sockaddr_ll); + addrlen, sizeof(struct sockaddr_ll)); return -EBADF; } @@ -351,7 +368,7 @@ static int pkt_bind(FAR struct socket *psock, FAR const struct sockaddr *addr, /* Look at the addr and identify network interface */ - ifindex = addr->sll_ifindex; + ifindex = ((struct sockaddr_ll*)addr)->sll_ifindex; #if 0 /* Get the MAC address of that interface */ @@ -375,6 +392,40 @@ static int pkt_bind(FAR struct socket *psock, FAR const struct sockaddr *addr, } } +/**************************************************************************** + * Name: pkt_getsockname + * + * Description: + * The pkt_getsockname() function retrieves the locally-bound name of the + * specified packet socket, stores this address in the sockaddr structure + * pointed to by the 'addr' argument, and stores the length of this + * address in the object pointed to by the 'addrlen' argument. + * + * If the actual length of the address is greater than the length of the + * supplied sockaddr structure, the stored address will be truncated. + * + * If the socket has not been bound to a local name, the value stored in + * the object pointed to by address is unspecified. + * + * Parameters: + * psock Socket structure of the socket to be queried + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + * Returned Value: + * On success, 0 is returned, the 'addr' argument points to the address + * of the socket, and the 'addrlen' argument points to the length of the + * address. Otherwise, a negated errno value is returned. See + * getsockname() for the list of appropriate error numbers. + * + ****************************************************************************/ + +static int pkt_getsockname(FAR struct socket *psock, + FAR struct sockaddr *addr, FAR socklen_t *addrlen) +{ + return -EAFNOSUPPORT; +} + /**************************************************************************** * Name: pkt_listen * @@ -405,6 +456,32 @@ int pkt_listen(FAR struct socket *psock, int backlog) return -EOPNOTSUPP; } +/**************************************************************************** + * Name: pkt_poll + * + * Description: + * The standard poll() operation redirects operations on socket descriptors + * to net_poll which, indiectly, calls to function. + * + * Input Parameters: + * psock - An instance of the internal socket structure. + * fds - The structure describing the events to be monitored, OR NULL if + * this is a request to stop monitoring events. + * setup - true: Setup up the poll; false: Teardown the poll + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_POLL +static int pkt_poll(FAR struct socket *psock, FAR struct pollfd *fds, + bool setup) +{ + return -ENOSYS; +} +#endif /* !CONFIG_DISABLE_POLL */ + /**************************************************************************** * Name: pkt_send * @@ -524,7 +601,6 @@ static int pkt_close(FAR struct socket *psock) return OK; } -#endif default: return -EBADF; diff --git a/net/socket/Make.defs b/net/socket/Make.defs index 1b9c99d5d1..b8e6bdec1a 100644 --- a/net/socket/Make.defs +++ b/net/socket/Make.defs @@ -47,12 +47,31 @@ 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 +else ifeq ($(CONFIG_NET_USRSOCK),y) +SOCK_CSRCS += inet_sockif.c inet_recvfrom.c inet_connect.c inet_close.c +endif + +ifeq ($(CONFIG_NET_IPv4),y) +SOCK_CSRCS += ipv4_getsockname.c +endif + +ifeq ($(CONFIG_NET_IPv6),y) +SOCK_CSRCS += ipv6_getsockname.c +endif + +ifeq ($(CONFIG_NET_SENDFILE),y) +ifeq ($(CONFIG_NET_TCP),y) +ifneq ($(CONFIG_NET_TCP_NO_STACK),y) +SOCK_CSRCS += inet_sendfile.c +endif +endif endif # TCP/IP support ifeq ($(CONFIG_NET_TCP),y) SOCK_CSRCS += listen.c accept.c + ifneq ($(CONFIG_NET_TCP_NO_STACK),y) SOCK_CSRCS += net_monitor.c endif diff --git a/net/socket/accept.c b/net/socket/accept.c index 48b76d15e0..f69fabf698 100644 --- a/net/socket/accept.c +++ b/net/socket/accept.c @@ -49,10 +49,7 @@ #include #include -#include "tcp/tcp.h" -#include "local/local.h" #include "socket/socket.h" -#include "usrsock/usrsock.h" #if defined(CONFIG_NET) && CONFIG_NSOCKET_DESCRIPTORS > 0 diff --git a/net/socket/bind.c b/net/socket/bind.c index 8d7270aee1..b2c3382255 100644 --- a/net/socket/bind.c +++ b/net/socket/bind.c @@ -92,9 +92,6 @@ int psock_bind(FAR struct socket *psock, const struct sockaddr *addr, socklen_t addrlen) { -#ifdef CONFIG_NET_PKT - FAR const struct sockaddr_ll *lladdr = (const struct sockaddr_ll *)addr; -#endif int errcode; int ret = OK; diff --git a/net/socket/getsockname.c b/net/socket/getsockname.c index 2356509de8..d51c230015 100644 --- a/net/socket/getsockname.c +++ b/net/socket/getsockname.c @@ -47,308 +47,11 @@ #include #include -#include -#include -#include "utils/utils.h" -#include "netdev/netdev.h" -#include "tcp/tcp.h" -#include "udp/udp.h" #include "socket/socket.h" -#include "usrsock/usrsock.h" #ifdef CONFIG_NET -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: get_ipv4_sockname - * - * Description: - * The getsockname() function retrieves the locally-bound name of the - * specified PF_NET socket. - * - * Parameters: - * psock Point to the socket structure instance [in] - * addr sockaddr structure to receive data [out] - * addrlen Length of sockaddr structure [in/out] - * - * Returned Value: - * On success, 0 is returned, the 'addr' argument points to the address - * of the socket, and the 'addrlen' argument points to the length of the - * address. Otherwise, -1 is returned and errno is set to indicate the error. - * Possible errno values that may be returned include: - * - * EBADF - The socket argument is not a valid file descriptor. - * EOPNOTSUPP - The operation is not supported for this socket's protocol. - * EINVAL - The socket has been shut down. - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IPv4 -int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, - FAR socklen_t *addrlen) -{ - FAR struct net_driver_s *dev; -#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) - FAR struct sockaddr_in *outaddr = (FAR struct sockaddr_in *)addr; -#endif -#ifdef CONFIG_NETDEV_MULTINIC - in_addr_t lipaddr; - in_addr_t ripaddr; -#endif - - /* Check if enough space has been provided for the full address */ - - if (*addrlen < sizeof(struct sockaddr_in)) - { - /* This function is supposed to return the partial address if - * a smaller buffer has been provided. This support has not - * been implemented. - */ - - return -ENOSYS; - } - - /* Set the port number */ - - switch (psock->s_type) - { -#ifdef NET_TCP_HAVE_STACK - case SOCK_STREAM: - { - FAR struct tcp_conn_s *tcp_conn = (FAR struct tcp_conn_s *)psock->s_conn; - outaddr->sin_port = tcp_conn->lport; /* Already in network byte order */ -#ifdef CONFIG_NETDEV_MULTINIC - lipaddr = tcp_conn->u.ipv4.laddr; - ripaddr = tcp_conn->u.ipv4.raddr; -#endif - } - break; -#endif - -#ifdef NET_UDP_HAVE_STACK - case SOCK_DGRAM: - { - FAR struct udp_conn_s *udp_conn = (FAR struct udp_conn_s *)psock->s_conn; - outaddr->sin_port = udp_conn->lport; /* Already in network byte order */ -#ifdef CONFIG_NETDEV_MULTINIC - lipaddr = udp_conn->u.ipv4.laddr; - ripaddr = udp_conn->u.ipv4.raddr; -#endif - } - break; -#endif - - default: - return -EOPNOTSUPP; - } - -#ifdef CONFIG_NETDEV_MULTINIC - /* The socket/connection does not know its IP address unless - * CONFIG_NETDEV_MULTINIC is selected. Otherwise the design supports only - * a single network device and only the network device knows the IP address. - */ - - if (lipaddr == 0) - { -#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) - outaddr->sin_family = AF_INET; - outaddr->sin_addr.s_addr = 0; - *addrlen = sizeof(struct sockaddr_in); -#endif - return OK; - } -#endif - - net_lock(); - -#ifdef CONFIG_NETDEV_MULTINIC - /* Find the device matching the IPv4 address in the connection structure. - * NOTE: listening sockets have no ripaddr. Work around is to use the - * lipaddr when ripaddr is not available. - */ - - if (ripaddr == 0) - { - ripaddr = lipaddr; - } - - dev = netdev_findby_ipv4addr(lipaddr, ripaddr); -#else - /* There is only one, the first network device in the list. */ - - dev = g_netdevices; -#endif - - if (!dev) - { - net_unlock(); - return -EINVAL; - } - - /* Set the address family and the IP address */ - -#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) - outaddr->sin_family = AF_INET; - outaddr->sin_addr.s_addr = dev->d_ipaddr; - *addrlen = sizeof(struct sockaddr_in); -#endif - net_unlock(); - - /* Return success */ - - return OK; -} -#endif - -/**************************************************************************** - * Name: ipv6_getsockname - * - * Description: - * The getsockname() function retrieves the locally-bound name of the - * specified PF_NET6 socket. - * - * Parameters: - * psock Point to the socket structure instance [in] - * addr sockaddr structure to receive data [out] - * addrlen Length of sockaddr structure [in/out] - * - * Returned Value: - * On success, 0 is returned, the 'addr' argument points to the address - * of the socket, and the 'addrlen' argument points to the length of the - * address. Otherwise, -1 is returned and errno is set to indicate the error. - * Possible errno values that may be returned include: - * - * EBADF - The socket argument is not a valid file descriptor. - * EOPNOTSUPP - The operation is not supported for this socket's protocol. - * EINVAL - The socket has been shut down. - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IPv6 -int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, - FAR socklen_t *addrlen) -{ - FAR struct net_driver_s *dev; -#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) - FAR struct sockaddr_in6 *outaddr = (FAR struct sockaddr_in6 *)addr; -#endif -#ifdef CONFIG_NETDEV_MULTINIC - net_ipv6addr_t *lipaddr; - net_ipv6addr_t *ripaddr; -#endif - - /* Check if enough space has been provided for the full address */ - - if (*addrlen < sizeof(struct sockaddr_in6)) - { - /* This function is supposed to return the partial address if - * a smaller buffer has been provided. This support has not - * been implemented. - */ - - return -ENOSYS; - } - - /* Set the port number */ - - switch (psock->s_type) - { -#ifdef NET_TCP_HAVE_STACK - case SOCK_STREAM: - { - FAR struct tcp_conn_s *tcp_conn = (FAR struct tcp_conn_s *)psock->s_conn; - outaddr->sin6_port = tcp_conn->lport; /* Already in network byte order */ -#ifdef CONFIG_NETDEV_MULTINIC - lipaddr = &tcp_conn->u.ipv6.laddr; - ripaddr = &tcp_conn->u.ipv6.raddr; -#endif - } - break; -#endif - -#ifdef NET_UDP_HAVE_STACK - case SOCK_DGRAM: - { - FAR struct udp_conn_s *udp_conn = (FAR struct udp_conn_s *)psock->s_conn; - outaddr->sin6_port = udp_conn->lport; /* Already in network byte order */ -#ifdef CONFIG_NETDEV_MULTINIC - lipaddr = &udp_conn->u.ipv6.laddr; - ripaddr = &udp_conn->u.ipv6.raddr; -#endif - } - break; -#endif - - default: - return -EOPNOTSUPP; - } - -#ifdef CONFIG_NETDEV_MULTINIC - /* The socket/connection does not know its IP address unless - * CONFIG_NETDEV_MULTINIC is selected. Otherwise the design supports only - * a single network device and only the network device knows the IP address. - */ - - if (net_ipv6addr_cmp(lipaddr, g_ipv6_allzeroaddr)) - { -#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) - outaddr->sin6_family = AF_INET6; - memcpy(outaddr->sin6_addr.in6_u.u6_addr8, g_ipv6_allzeroaddr, 16); - *addrlen = sizeof(struct sockaddr_in6); -#endif - return OK; - } -#endif - - net_lock(); - -#ifdef CONFIG_NETDEV_MULTINIC - /* Find the device matching the IPv6 address in the connection structure. - * NOTE: listening sockets have no ripaddr. Work around is to use the - * lipaddr when ripaddr is not available. - */ - - if (net_ipv6addr_cmp(ripaddr, g_ipv6_allzeroaddr)) - { - ripaddr = lipaddr; - } - - dev = netdev_findby_ipv6addr(*lipaddr, *ripaddr); -#else - /* There is only one, the first network device in the list. */ - - dev = g_netdevices; -#endif - - if (!dev) - { - net_unlock(); - return -EINVAL; - } - - /* Set the address family and the IP address */ - -#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) - outaddr->sin6_family = AF_INET6; - memcpy(outaddr->sin6_addr.in6_u.u6_addr8, dev->d_ipv6addr, 16); - *addrlen = sizeof(struct sockaddr_in6); -#endif - net_unlock(); - - /* Return success */ - - return OK; -} -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -379,11 +82,12 @@ int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, * address. Otherwise, -1 is returned and errno is set to indicate the error. * Possible errno values that may be returned include: * - * EBADF - The socket argument is not a valid file descriptor. + * EBADF - The socket argument is not a valid file descriptor. + * ENOTSOCK - The socket argument does not refer to a socket. * EOPNOTSUPP - The operation is not supported for this socket's protocol. - * EINVAL - The socket has been shut down. - * - * Assumptions: + * EINVAL - The socket has been shut down. + * ENOBUFS - Insufficient resources were available in the system to + * complete the function. * ****************************************************************************/ @@ -395,7 +99,7 @@ int getsockname(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) /* 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; @@ -406,54 +110,19 @@ int getsockname(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) */ #ifdef CONFIG_DEBUG_FEATURES - if (!addr || !addrlen) + if (addr == NULL || addrlen <= 0) { errcode = EINVAL; goto errout; } #endif -#ifdef CONFIG_NET_USRSOCK - if (psock->s_type == SOCK_USRSOCK_TYPE) - { - FAR struct usrsock_conn_s *conn = psock->s_conn; + /* Let the address family's send() method handle the operation */ - DEBUGASSERT(conn); + DEBUGASSERT(psock->s_sockif != NULL && + psock->s_sockif->si_getsockname != NULL); - /* Handle usrsock getsockname */ - - ret = usrsock_getsockname(conn, addr, addrlen); - if (ret < 0) - { - errcode = -ret; - goto errout; - } - - return OK; - } -#endif - - /* Handle by address domain */ - - switch (psock->s_domain) - { -#ifdef CONFIG_NET_IPv4 - case PF_INET: - ret = ipv4_getsockname(psock, addr, addrlen); - break; -#endif - -#ifdef CONFIG_NET_IPv6 - case PF_INET6: - ret = ipv6_getsockname(psock, addr, addrlen); - break; -#endif - - case PF_PACKET: - default: - errcode = EAFNOSUPPORT; - goto errout; - } + ret = psock->s_sockif->si_getsockname(psock, addr, addrlen); /* Check for failure */ diff --git a/net/socket/inet_connect.c b/net/socket/inet_connect.c index 49aa17cd75..cc187e2874 100644 --- a/net/socket/inet_connect.c +++ b/net/socket/inet_connect.c @@ -519,7 +519,7 @@ int inet_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, switch (psock->s_type) { -#ifdef CONFIG_NET_TCP +#if defined(CONFIG_NET_TCP) && defined(NET_TCP_HAVE_STACK) case SOCK_STREAM: { /* Verify that the socket is not already connected */ @@ -535,7 +535,7 @@ int inet_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, } #endif /* CONFIG_NET_TCP */ -#ifdef CONFIG_NET_UDP +#if defined(CONFIG_NET_UDP) && defined(NET_UDP_HAVE_STACK) case SOCK_DGRAM: { int ret = udp_connect(psock->s_conn, addr); diff --git a/net/socket/inet_getsockname.c b/net/socket/inet_getsockname.c new file mode 100644 index 0000000000..fafde3875a --- /dev/null +++ b/net/socket/inet_getsockname.c @@ -0,0 +1,442 @@ +/**************************************************************************** + * net/socket/getsockname.c + * + * Copyright (C) 2011-2012, 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "utils/utils.h" +#include "netdev/netdev.h" +#include "tcp/tcp.h" +#include "udp/udp.h" +#include "socket/socket.h" +#include "usrsock/usrsock.h" + +#ifdef CONFIG_NET + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: get_ipv4_sockname + * + * Description: + * The getsockname() function retrieves the locally-bound name of the + * specified PF_NET socket. + * + * Parameters: + * psock Point to the socket structure instance [in] + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + * Returned Value: + * On success, 0 is returned, the 'addr' argument points to the address + * of the socket, and the 'addrlen' argument points to the length of the + * address. Otherwise, -1 is returned and errno is set to indicate the error. + * Possible errno values that may be returned include: + * + * EBADF - The socket argument is not a valid file descriptor. + * EOPNOTSUPP - The operation is not supported for this socket's protocol. + * EINVAL - The socket has been shut down. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv4 +int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen) +{ + FAR struct net_driver_s *dev; +#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) + FAR struct sockaddr_in *outaddr = (FAR struct sockaddr_in *)addr; +#endif +#ifdef CONFIG_NETDEV_MULTINIC + in_addr_t lipaddr; + in_addr_t ripaddr; +#endif + + /* Check if enough space has been provided for the full address */ + + if (*addrlen < sizeof(struct sockaddr_in)) + { + /* This function is supposed to return the partial address if + * a smaller buffer has been provided. This support has not + * been implemented. + */ + + return -ENOSYS; + } + + /* Set the port number */ + + switch (psock->s_type) + { +#ifdef NET_TCP_HAVE_STACK + case SOCK_STREAM: + { + FAR struct tcp_conn_s *tcp_conn = (FAR struct tcp_conn_s *)psock->s_conn; + outaddr->sin_port = tcp_conn->lport; /* Already in network byte order */ +#ifdef CONFIG_NETDEV_MULTINIC + lipaddr = tcp_conn->u.ipv4.laddr; + ripaddr = tcp_conn->u.ipv4.raddr; +#endif + } + break; +#endif + +#ifdef NET_UDP_HAVE_STACK + case SOCK_DGRAM: + { + FAR struct udp_conn_s *udp_conn = (FAR struct udp_conn_s *)psock->s_conn; + outaddr->sin_port = udp_conn->lport; /* Already in network byte order */ +#ifdef CONFIG_NETDEV_MULTINIC + lipaddr = udp_conn->u.ipv4.laddr; + ripaddr = udp_conn->u.ipv4.raddr; +#endif + } + break; +#endif + + default: + return -EOPNOTSUPP; + } + +#ifdef CONFIG_NETDEV_MULTINIC + /* The socket/connection does not know its IP address unless + * CONFIG_NETDEV_MULTINIC is selected. Otherwise the design supports only + * a single network device and only the network device knows the IP address. + */ + + if (lipaddr == 0) + { +#if defined(CONFIG_NET_TCP) || defined(CONFIG_NET_UDP) + outaddr->sin_family = AF_INET; + outaddr->sin_addr.s_addr = 0; + *addrlen = sizeof(struct sockaddr_in); +#endif + return OK; + } +#endif + + net_lock(); + +#ifdef CONFIG_NETDEV_MULTINIC + /* Find the device matching the IPv4 address in the connection structure. + * NOTE: listening sockets have no ripaddr. Work around is to use the + * lipaddr when ripaddr is not available. + */ + + if (ripaddr == 0) + { + ripaddr = lipaddr; + } + + dev = netdev_findby_ipv4addr(lipaddr, ripaddr); +#else + /* There is only one, the first network device in the list. */ + + dev = g_netdevices; +#endif + + if (!dev) + { + net_unlock(); + return -EINVAL; + } + + /* Set the address family and the IP address */ + +#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) + outaddr->sin_family = AF_INET; + outaddr->sin_addr.s_addr = dev->d_ipaddr; + *addrlen = sizeof(struct sockaddr_in); +#endif + net_unlock(); + + /* Return success */ + + return OK; +} +#endif + +/**************************************************************************** + * Name: ipv6_getsockname + * + * Description: + * The getsockname() function retrieves the locally-bound name of the + * specified PF_NET6 socket. + * + * Parameters: + * psock Point to the socket structure instance [in] + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + * Returned Value: + * On success, 0 is returned, the 'addr' argument points to the address + * of the socket, and the 'addrlen' argument points to the length of the + * address. Otherwise, -1 is returned and errno is set to indicate the error. + * Possible errno values that may be returned include: + * + * EBADF - The socket argument is not a valid file descriptor. + * EOPNOTSUPP - The operation is not supported for this socket's protocol. + * EINVAL - The socket has been shut down. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv6 +int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen) +{ + FAR struct net_driver_s *dev; +#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) + FAR struct sockaddr_in6 *outaddr = (FAR struct sockaddr_in6 *)addr; +#endif +#ifdef CONFIG_NETDEV_MULTINIC + net_ipv6addr_t *lipaddr; + net_ipv6addr_t *ripaddr; +#endif + + /* Check if enough space has been provided for the full address */ + + if (*addrlen < sizeof(struct sockaddr_in6)) + { + /* This function is supposed to return the partial address if + * a smaller buffer has been provided. This support has not + * been implemented. + */ + + return -ENOSYS; + } + + /* Set the port number */ + + switch (psock->s_type) + { +#ifdef NET_TCP_HAVE_STACK + case SOCK_STREAM: + { + FAR struct tcp_conn_s *tcp_conn = (FAR struct tcp_conn_s *)psock->s_conn; + outaddr->sin6_port = tcp_conn->lport; /* Already in network byte order */ +#ifdef CONFIG_NETDEV_MULTINIC + lipaddr = &tcp_conn->u.ipv6.laddr; + ripaddr = &tcp_conn->u.ipv6.raddr; +#endif + } + break; +#endif + +#ifdef NET_UDP_HAVE_STACK + case SOCK_DGRAM: + { + FAR struct udp_conn_s *udp_conn = (FAR struct udp_conn_s *)psock->s_conn; + outaddr->sin6_port = udp_conn->lport; /* Already in network byte order */ +#ifdef CONFIG_NETDEV_MULTINIC + lipaddr = &udp_conn->u.ipv6.laddr; + ripaddr = &udp_conn->u.ipv6.raddr; +#endif + } + break; +#endif + + default: + return -EOPNOTSUPP; + } + +#ifdef CONFIG_NETDEV_MULTINIC + /* The socket/connection does not know its IP address unless + * CONFIG_NETDEV_MULTINIC is selected. Otherwise the design supports only + * a single network device and only the network device knows the IP address. + */ + + if (net_ipv6addr_cmp(lipaddr, g_ipv6_allzeroaddr)) + { +#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) + outaddr->sin6_family = AF_INET6; + memcpy(outaddr->sin6_addr.in6_u.u6_addr8, g_ipv6_allzeroaddr, 16); + *addrlen = sizeof(struct sockaddr_in6); +#endif + return OK; + } +#endif + + net_lock(); + +#ifdef CONFIG_NETDEV_MULTINIC + /* Find the device matching the IPv6 address in the connection structure. + * NOTE: listening sockets have no ripaddr. Work around is to use the + * lipaddr when ripaddr is not available. + */ + + if (net_ipv6addr_cmp(ripaddr, g_ipv6_allzeroaddr)) + { + ripaddr = lipaddr; + } + + dev = netdev_findby_ipv6addr(*lipaddr, *ripaddr); +#else + /* There is only one, the first network device in the list. */ + + dev = g_netdevices; +#endif + + if (!dev) + { + net_unlock(); + return -EINVAL; + } + + /* Set the address family and the IP address */ + +#if defined(NET_TCP_HAVE_STACK) || defined(NET_UDP_HAVE_STACK) + outaddr->sin6_family = AF_INET6; + memcpy(outaddr->sin6_addr.in6_u.u6_addr8, dev->d_ipv6addr, 16); + *addrlen = sizeof(struct sockaddr_in6); +#endif + net_unlock(); + + /* Return success */ + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: inet_getsockname + * + * Description: + * The getsockname() function retrieves the locally-bound name of the + * specified socket, stores this address in the sockaddr structure pointed + * to by the 'addr' argument, and stores the length of this address in the + * object pointed to by the 'addrlen' argument. + * + * If the actual length of the address is greater than the length of the + * supplied sockaddr structure, the stored address will be truncated. + * + * If the socket has not been bound to a local name, the value stored in + * the object pointed to by address is unspecified. + * + * Parameters: + * sockfd Socket descriptor of socket [in] + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + * Returned Value: + * On success, 0 is returned, the 'addr' argument points to the address + * of the socket, and the 'addrlen' argument points to the length of the + * address. Otherwise, -1 is returned and errno is set to indicate the error. + * Possible errno values that may be returned include: + * + * EBADF - The socket argument is not a valid file descriptor. + * EOPNOTSUPP - The operation is not supported for this socket's protocol. + * EINVAL - The socket has been shut down. + * + * Assumptions: + * + ****************************************************************************/ + +int inet_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen) +{ + int ret; + +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { + FAR struct usrsock_conn_s *conn = psock->s_conn; + + DEBUGASSERT(conn); + + /* Handle usrsock getsockname */ + + ret = usrsock_getsockname(conn, addr, addrlen); + if (ret < 0) + { + errcode = -ret; + goto errout; + } + + return OK; + } +#endif + + /* Handle by address domain */ + + switch (psock->s_domain) + { +#ifdef CONFIG_NET_IPv4 + case PF_INET: + ret = ipv4_getsockname(psock, addr, addrlen); + break; +#endif + +#ifdef CONFIG_NET_IPv6 + case PF_INET6: + ret = ipv6_getsockname(psock, addr, addrlen); + break; +#endif + + case PF_PACKET: + default: + errcode = EAFNOSUPPORT; + goto errout; + } + +errout: + set_errno(errcode); + return ERROR; +} + +#endif /* CONFIG_NET */ diff --git a/net/socket/inet_sendfile.c b/net/socket/inet_sendfile.c new file mode 100644 index 0000000000..daf693b7de --- /dev/null +++ b/net/socket/inet_sendfile.c @@ -0,0 +1,717 @@ +/**************************************************************************** + * net/socket/inet_sendfile.c + * + * Copyright (C) 2013 UVC Ingenieure. All rights reserved. + * Copyright (C) 2007-2017 Gregory Nutt. All rights reserved. + * Authors: Gregory Nutt + * Max Holtzberg + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "netdev/netdev.h" +#include "devif/devif.h" +#include "arp/arp.h" +#include "icmpv6/icmpv6.h" +#include "neighbor/neighbor.h" +#include "tcp/tcp.h" +#include "socket/socket.h" + +#if defined(CONFIG_NET_SENDFILE) && defined(CONFIG_NET_TCP) && \ + defined(NET_TCP_HAVE_STACK) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_NET_TCP_SPLIT) && !defined(CONFIG_NET_TCP_SPLIT_SIZE) +# define CONFIG_NET_TCP_SPLIT_SIZE 40 +#endif + +#define TCPIPv4BUF ((struct tcp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv4_HDRLEN]) +#define TCPIPv6BUF ((struct tcp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN]) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure holds the state of the send operation until it can be + * operated upon from the interrupt level. + */ + +struct sendfile_s +{ + FAR struct socket *snd_sock; /* Points to the parent socket structure */ + FAR struct devif_callback_s *snd_datacb; /* Data callback */ + FAR struct devif_callback_s *snd_ackcb; /* ACK callback */ + FAR struct file *snd_file; /* File structure of the input file */ + sem_t snd_sem; /* Used to wake up the waiting thread */ + off_t snd_foffset; /* Input file offset */ + size_t snd_flen; /* File length */ + ssize_t snd_sent; /* The number of bytes sent */ + uint32_t snd_isn; /* Initial sequence number */ + uint32_t snd_acked; /* The number of bytes acked */ +#ifdef CONFIG_NET_SOCKOPTS + systime_t snd_time; /* Last send time for determining timeout */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sendfile_timeout + * + * Description: + * Check for send timeout. + * + * Parameters: + * pstate - send state structure + * + * Returned Value: + * TRUE:timeout FALSE:no timeout + * + * Assumptions: + * Running at the interrupt level + * + ****************************************************************************/ + +#ifdef CONFIG_NET_SOCKOPTS +static inline int sendfile_timeout(FAR struct sendfile_s *pstate) +{ + FAR struct socket *psock = 0; + + /* Check for a timeout configured via setsockopts(SO_SNDTIMEO). + * If none... we well let the send wait forever. + */ + + psock = pstate->snd_sock; + if (psock && psock->s_sndtimeo != 0) + { + /* Check if the configured timeout has elapsed */ + + return net_timeo(pstate->snd_time, psock->s_sndtimeo); + } + + /* No timeout */ + + return FALSE; +} +#endif /* CONFIG_NET_SOCKOPTS */ + +static uint16_t ack_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct sendfile_s *pstate = (FAR struct sendfile_s *)pvpriv; + + ninfo("flags: %04x\n", flags); + + if ((flags & TCP_ACKDATA) != 0) + { + FAR struct tcp_hdr_s *tcp; + +#ifdef CONFIG_NET_SOCKOPTS + /* Update the timeout */ + + pstate->snd_time = clock_systimer(); +#endif + + /* Get the offset address of the TCP header */ + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + if (IFF_IS_IPv6(dev->d_flags)) +#endif + { + DEBUGASSERT(pstate->snd_sock == PF_INET6); + tcp = TCPIPv6BUF; + } +#endif /* CONFIG_NET_IPv6 */ + +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + else +#endif + { + DEBUGASSERT(pstate->snd_sock == PF_INET); + tcp = TCPIPv4BUF; + } +#endif /* CONFIG_NET_IPv4 */ + + /* The current acknowledgement number number is the (relative) offset + * of the of the next byte needed by the receiver. The snd_isn is the + * offset of the first byte to send to the receiver. The difference + * is the number of bytes to be acknowledged. + */ + + pstate->snd_acked = tcp_getsequence(tcp->ackno) - pstate->snd_isn; + ninfo("ACK: acked=%d sent=%d flen=%d\n", + pstate->snd_acked, pstate->snd_sent, pstate->snd_flen); + + dev->d_sndlen = 0; + + flags &= ~TCP_ACKDATA; + } + else if ((flags & TCP_REXMIT) != 0) + { + nwarn("WARNING: TCP_REXMIT\n"); + + /* Yes.. in this case, reset the number of bytes that have been sent + * to the number of bytes that have been ACKed. + */ + + pstate->snd_sent = pstate->snd_acked; + } + + /* Check for a loss of connection */ + + else if ((flags & TCP_DISCONN_EVENTS) != 0) + { + /* Report not connected */ + + nwarn("WARNING: Lost connection\n"); + + net_lostconnection(pstate->snd_sock, flags); + pstate->snd_sent = -ENOTCONN; + } + + /* Wake up the waiting thread */ + + sem_post(&pstate->snd_sem); + + return flags; +} + +/**************************************************************************** + * Name: sendfile_addrcheck + * + * Description: + * Check if the destination IP address is in the IPv4 ARP or IPv6 Neighbor + * tables. If not, then the send won't actually make it out... it will be + * replaced with an ARP request (IPv4) or a Neighbor Solicitation (IPv6). + * + * NOTE 1: This could be an expensive check if there are a lot of + * entries in the ARP or Neighbor tables. + * + * NOTE 2: If we are actually harvesting IP addresses on incoming IP + * packets, then this check should not be necessary; the MAC mapping + * should already be in the ARP table in many cases (IPv4 only). + * + * NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP + * address mapping is already in the ARP table. + * + * Parameters: + * conn - The TCP connection structure + * + * Returned Value: + * None + * + * Assumptions: + * Running at the interrupt level + * + ****************************************************************************/ + +#ifdef CONFIG_NET_ETHERNET +static inline bool sendfile_addrcheck(FAR struct tcp_conn_s *conn) +{ +#ifdef CONFIG_NET_IPv4 +#ifdef CONFIG_NET_IPv6 + if (conn->domain == PF_INET) +#endif + { +#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND) + return (arp_find(conn->u.ipv4.raddr) != NULL); +#else + return true; +#endif + } +#endif /* CONFIG_NET_IPv4 */ + +#ifdef CONFIG_NET_IPv6 +#ifdef CONFIG_NET_IPv4 + else +#endif + { +#if !defined(CONFIG_NET_ICMPv6_NEIGHBOR) + return (neighbor_findentry(conn->u.ipv6.raddr) != NULL); +#else + return true; +#endif + } +#endif /* CONFIG_NET_IPv6 */ +} + +#else /* CONFIG_NET_ETHERNET */ +# sendfile_addrcheck(r) (true) +#endif /* CONFIG_NET_ETHERNET */ + +/**************************************************************************** + * Name: sendfile_interrupt + * + * Description: + * This function is called from the interrupt level to perform the actual + * send operation when polled by the lower, device interfacing layer. + * + * Parameters: + * dev The structure of the network driver that caused the interrupt + * conn The connection structure associated with the socket + * flags Set of events describing why the callback was invoked + * + * Returned Value: + * None + * + * Assumptions: + * Running at the interrupt level + * + ****************************************************************************/ + +static uint16_t sendfile_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, + FAR void *pvpriv, uint16_t flags) +{ + FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn; + FAR struct sendfile_s *pstate = (FAR struct sendfile_s *)pvpriv; + int ret; + +#ifdef CONFIG_NETDEV_MULTINIC + /* The TCP socket is connected and, hence, should be bound to a device. + * Make sure that the polling device is the own that we are bound to. + */ + + DEBUGASSERT(conn->dev != NULL); + if (dev != conn->dev) + { + return flags; + } +#endif + + ninfo("flags: %04x acked: %d sent: %d\n", + flags, pstate->snd_acked, pstate->snd_sent); + + /* Check for a loss of connection */ + + if ((flags & TCP_DISCONN_EVENTS) != 0) + { + /* Report not connected */ + + nwarn("WARNING: Lost connection\n"); + + net_lostconnection(pstate->snd_sock, flags); + pstate->snd_sent = -ENOTCONN; + goto end_wait; + } + + /* We get here if (1) not all of the data has been ACKed, (2) we have been + * asked to retransmit data, (3) the connection is still healthy, and (4) + * the outgoing packet is available for our use. In this case, we are + * now free to send more data to receiver -- UNLESS the buffer contains + * unprocessing incoming data. In that event, we will have to wait for the + * next polling cycle. + */ + + if ((flags & TCP_NEWDATA) == 0 && pstate->snd_sent < pstate->snd_flen) + { + /* Get the amount of data that we can send in the next packet */ + + uint32_t sndlen = pstate->snd_flen - pstate->snd_sent; + + if (sndlen > conn->mss) + { + sndlen = conn->mss; + } + + /* Check if we have "space" in the window */ + + if ((pstate->snd_sent - pstate->snd_acked + sndlen) < conn->winsize) + { + uint32_t seqno; + + /* Then set-up to send that amount of data. (this won't actually + * happen until the polling cycle completes). + */ + + ret = file_seek(pstate->snd_file, + pstate->snd_foffset + pstate->snd_sent, SEEK_SET); + if (ret < 0) + { + int errcode = get_errno(); + nerr("ERROR: Failed to lseek: %d\n", errcode); + pstate->snd_sent = -errcode; + goto end_wait; + } + + ret = file_read(pstate->snd_file, dev->d_appdata, sndlen); + if (ret < 0) + { + int errcode = get_errno(); + nerr("ERROR: Failed to read from input file: %d\n", errcode); + pstate->snd_sent = -errcode; + goto end_wait; + } + + dev->d_sndlen = sndlen; + + /* Set the sequence number for this packet. NOTE: The network updates + * sndseq on recept of ACK *before* this function is called. In that + * case sndseq will point to the next unacknowledge byte (which might + * have already been sent). We will overwrite the value of sndseq + * here before the packet is sent. + */ + + seqno = pstate->snd_sent + pstate->snd_isn; + ninfo("SEND: sndseq %08x->%08x len: %d\n", conn->sndseq, seqno, ret); + + tcp_setsequence(conn->sndseq, seqno); + + /* Check if the destination IP address is in the ARP or Neighbor + * table. If not, then the send won't actually make it out... it + * will be replaced with an ARP request or Neighbor Solicitation. + */ + + if (pstate->snd_sent != 0 || sendfile_addrcheck(conn)) + { + /* Update the amount of data sent (but not necessarily ACKed) */ + + pstate->snd_sent += sndlen; + ninfo("pid: %d SEND: acked=%d sent=%d flen=%d\n", getpid(), + pstate->snd_acked, pstate->snd_sent, pstate->snd_flen); + } + } + else + { + nwarn("WARNING: Window full, wait for ack\n"); + goto wait; + } + } + +#ifdef CONFIG_NET_SOCKOPTS + /* All data has been send and we are just waiting for ACK or re-transmit + * indications to complete the send. Check for a timeout. + */ + + if (sendfile_timeout(pstate)) + { + /* Yes.. report the timeout */ + + nwarn("WARNING: SEND timeout\n"); + pstate->snd_sent = -ETIMEDOUT; + goto end_wait; + } +#endif /* CONFIG_NET_SOCKOPTS */ + + if (pstate->snd_sent >= pstate->snd_flen + && pstate->snd_acked < pstate->snd_flen) + { + /* All data has been sent, but there are outstanding ACK's */ + + goto wait; + } + +end_wait: + + /* Do not allow any further callbacks */ + + pstate->snd_datacb->flags = 0; + pstate->snd_datacb->priv = NULL; + pstate->snd_datacb->event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->snd_sem); + +wait: + return flags; +} + +/**************************************************************************** + * Name: sendfile_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 + * + ****************************************************************************/ + +static inline void sendfile_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 */ +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: inet_sendfile + * + * Description: + * The inet_sendfile() call may be used only when the INET socket is in a + * connected state (so that the intended recipient is known). + * + * 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 sendfile() for a list + * appropriate error return values. + * + ****************************************************************************/ + +ssize_t inet_sendfile(FAR struct socket *psock, FAR struct file *infile, + FAR off_t *offset, size_t count) +{ + FAR struct tcp_conn_s *conn; + struct sendfile_s state; + int ret; + + /* If this is an un-connected socket, then return ENOTCONN */ + + if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) + { + nerr("ERROR: Not connected\n"); + return -ENOTCONN; + } + + /* Make sure that we have the IP address mapping */ + + conn = (FAR struct tcp_conn_s *)psock->s_conn; + DEBUGASSERT(conn != NULL); + +#if defined(CONFIG_NET_ARP_SEND) || defined(CONFIG_NET_ICMPv6_NEIGHBOR) +#ifdef CONFIG_NET_ARP_SEND +#ifdef CONFIG_NET_ICMPv6_NEIGHBOR + if (psock->s_domain == PF_INET) +#endif + { + /* Make sure that the IP address mapping is in the ARP table */ + + ret = arp_send(conn->u.ipv4.raddr); + } +#endif /* CONFIG_NET_ARP_SEND */ +#ifdef CONFIG_NET_ICMPv6_NEIGHBOR +#ifdef CONFIG_NET_ARP_SEND + else +#endif + { + /* Make sure that the IP address mapping is in the Neighbor Table */ + + ret = icmpv6_neighbor(conn->u.ipv6.raddr); + } +#endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ + + /* Did we successfully get the address mapping? */ + + if (ret < 0) + { + nerr("ERROR: Not reachable\n"); + return -ENETUNREACH; + } +#endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ + + /* Set the socket state to sending */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); + + /* Initialize the state structure. This is done with interrupts + * disabled because we don't want anything to happen until we + * are ready. + */ + + net_lock(); + memset(&state, 0, sizeof(struct sendfile_s)); + + /* This semaphore is used for signaling and, hence, should not have + * priority inheritance enabled. + */ + + sem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */ + sem_setprotocol(&state.snd_sem, SEM_PRIO_NONE); + + state.snd_sock = psock; /* Socket descriptor to use */ + state.snd_foffset = offset ? *offset : 0; /* Input file offset */ + state.snd_flen = count; /* Number of bytes to send */ + state.snd_file = infile; /* File to read from */ + + /* Allocate resources to receive a callback */ + + state.snd_datacb = tcp_callback_alloc(conn); + + if (state.snd_datacb == NULL) + { + nerr("ERROR: Failed to allocate data callback\n"); + ret =- ENOMEM; + goto errout_locked; + } + + state.snd_ackcb = tcp_callback_alloc(conn); + + if (state.snd_ackcb == NULL) + { + nerr("ERROR: Failed to allocate ack callback\n"); + ret = -ENOMEM; + goto errout_datacb; + } + + /* Get the initial sequence number that will be used */ + + state.snd_isn = tcp_getsequence(conn->sndseq); + + /* There is no outstanding, unacknowledged data after this + * initial sequence number. + */ + + conn->unacked = 0; + +#ifdef CONFIG_NET_SOCKOPTS + /* Set the initial time for calculating timeouts */ + + state.snd_time = clock_systimer(); +#endif + + /* Set up the ACK callback in the connection */ + + state.snd_ackcb->flags = (TCP_ACKDATA | TCP_REXMIT | TCP_DISCONN_EVENTS); + state.snd_ackcb->priv = (FAR void *)&state; + state.snd_ackcb->event = ack_interrupt; + + /* Perform the TCP send operation */ + + do + { + state.snd_datacb->flags = TCP_POLL; + state.snd_datacb->priv = (FAR void *)&state; + state.snd_datacb->event = sendfile_interrupt; + + /* Notify the device driver of the availability of TX data */ + + sendfile_txnotify(psock, conn); + net_lockedwait(&state.snd_sem); + } + while (state.snd_sent >= 0 && state.snd_acked < state.snd_flen); + + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); + + tcp_callback_free(conn, state.snd_ackcb); + +errout_datacb: + tcp_callback_free(conn, state.snd_datacb); + +errout_locked: + + sem_destroy(&state. snd_sem); + net_unlock(); + +errout: + + if (ret < 0) + { + return ret; + } + else + { + return state.snd_sent; + } +} + +#endif /* CONFIG_NET_SENDFILE && CONFIG_NET_TCP && NET_TCP_HAVE_STACK */ diff --git a/net/socket/inet_sockif.c b/net/socket/inet_sockif.c index 6ef3f8b824..3e35e2df90 100644 --- a/net/socket/inet_sockif.c +++ b/net/socket/inet_sockif.c @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -52,7 +53,7 @@ #include "usrsock/usrsock.h" #include "socket/socket.h" -#if defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_IPv6) +#ifdef HAVE_INET_SOCKETS /**************************************************************************** * Private Function Prototypes @@ -63,10 +64,16 @@ static sockcaps_t inet_sockcaps(FAR struct socket *psock); static void inet_addref(FAR struct socket *psock); static int inet_bind(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen); +static int inet_getsockname(FAR struct socket *psock, + FAR struct sockaddr *addr, FAR socklen_t *addrlen); static int inet_listen(FAR struct socket *psock, int backlog); static int inet_accept(FAR struct socket *psock, FAR struct sockaddr *addr, FAR socklen_t *addrlen, FAR struct socket *newsock); +#ifndef CONFIG_DISABLE_POLL +static int inet_poll(FAR struct socket *psock, + FAR struct pollfd *fds, bool setup); +#endif static ssize_t inet_send(FAR struct socket *psock, FAR const void *buf, size_t len, int flags); static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, @@ -79,17 +86,28 @@ static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, const struct sock_intf_s g_inet_sockif = { - inet_setup, /* si_setup */ - inet_sockcaps, /* si_sockcaps */ - inet_addref, /* si_addref */ - inet_bind, /* si_bind */ - inet_listen, /* si_listen */ - inet_connect, /* si_connect */ - inet_accept, /* si_accept */ - inet_send, /* si_send */ - inet_sendto, /* si_sendto */ - inet_recvfrom, /* si_recvfrom */ - inet_close /* si_close */ + inet_setup, /* si_setup */ + inet_sockcaps, /* si_sockcaps */ + inet_addref, /* si_addref */ + inet_bind, /* si_bind */ + inet_getsockname, /* si_getsockname */ + inet_listen, /* si_listen */ + inet_connect, /* si_connect */ + inet_accept, /* si_accept */ +#ifndef CONFIG_DISABLE_POLL + inet_poll, /* si_poll */ +#endif + inet_send, /* si_send */ + inet_sendto, /* si_sendto */ +#ifdef CONFIG_NET_SENDFILE +#if defined(CONFIG_NET_TCP) && defined(NET_TCP_HAVE_STACK) + inet_sendfile, /* si_sendfile */ +#else + NULL, /* si_sendfile */ +#endif +#endif + inet_recvfrom, /* si_recvfrom */ + inet_close /* si_close */ }; /**************************************************************************** @@ -251,18 +269,20 @@ static int usrsock_socket_setup(int domain, int type, int protocol, static int inet_setup(FAR struct socket *psock, int protocol) { #ifdef CONFIG_NET_USRSOCK - /* Handle speical setup for user INET sockets */ + int ret; - ret = usrsock_socket_setup(domain, type, protocol, psock); + /* Handle special setup for user INET sockets */ + + ret = usrsock_socket_setup(psock->s_domain, psock->s_type, protocol, psock); if (ret < 0) { - if (ret = -ENETDOWN) + if (ret == -ENETDOWN) { /* -ENETDOWN means that usrsock daemon is not running. Attempt to * open socket with kernel networking stack. */ - warn("WARNING: usrsock daemon is not running\n"); + nwarn("WARNING: usrsock daemon is not running\n"); } else { @@ -293,8 +313,8 @@ static int inet_setup(FAR struct socket *psock, int protocol) return inet_tcp_alloc(psock); #else - warning("WARNING: SOCK_STREAM disabled\n"); - return = -ENETDOWN; + nwarn("WARNING: SOCK_STREAM disabled\n"); + return -ENETDOWN; #endif #endif /* CONFIG_NET_TCP */ @@ -311,7 +331,7 @@ static int inet_setup(FAR struct socket *psock, int protocol) return inet_udp_alloc(psock); #else - warning("WARNING: SOCK_DGRAM disabled\n"); + nwarn("WARNING: SOCK_DGRAM disabled\n"); return -ENETDOWN; #endif #endif /* CONFIG_NET_UDP */ @@ -544,6 +564,72 @@ static int inet_bind(FAR struct socket *psock, return ret; } +/**************************************************************************** + * Name: inet_getsockname + * + * Description: + * The inet_getsockname() function retrieves the locally-bound name of + * the specified INET socket, stores this address in the sockaddr + * structure pointed to by the 'addr' argument, and stores the length of + * this address in the object pointed to by the 'addrlen' argument. + * + * If the actual length of the address is greater than the length of the + * supplied sockaddr structure, the stored address will be truncated. + * + * If the socket has not been bound to a local name, the value stored in + * the object pointed to by address is unspecified. + * + * Parameters: + * psock Socket structure of the socket to be queried + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + * Returned Value: + * On success, 0 is returned, the 'addr' argument points to the address + * of the socket, and the 'addrlen' argument points to the length of the + * address. Otherwise, a negated errno value is returned. See + * getsockname() for the list of appropriate error numbers. + * + ****************************************************************************/ + +static int inet_getsockname(FAR struct socket *psock, + FAR struct sockaddr *addr, + FAR socklen_t *addrlen) +{ +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { + FAR struct usrsock_conn_s *conn = psock->s_conn; + + DEBUGASSERT(conn != NULL); + + /* Handle usrsock getsockname */ + + return usrsock_getsockname(conn, addr, addrlen); + } +#endif + + /* Handle by address domain */ + + switch (psock->s_domain) + { +#ifdef CONFIG_NET_IPv4 + case PF_INET: + return ipv4_getsockname(psock, addr, addrlen); + break; +#endif + +#ifdef CONFIG_NET_IPv6 + case PF_INET6: + return ipv6_getsockname(psock, addr, addrlen); + break; +#endif + + default: + return -EAFNOSUPPORT; + } +} + /**************************************************************************** * Name: inet_listen * @@ -793,6 +879,141 @@ errout_with_lock: #endif /* CONFIG_NET_TCP */ } +/**************************************************************************** + * Name: inet_pollsetup + * + * Description: + * Setup to monitor events on one socket + * + * Input Parameters: + * psock - The socket of interest + * fds - The structure describing the events to be monitored, OR NULL if + * this is a request to stop monitoring events. + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +#if defined(HAVE_TCP_POLL) || defined(HAVE_UDP_POLL) +static inline int inet_pollsetup(FAR struct socket *psock, + FAR struct pollfd *fds) +{ +#ifdef HAVE_TCP_POLL + if (psock->s_type == SOCK_STREAM) + { + return tcp_pollsetup(psock, fds); + } + else +#endif /* HAVE_TCP_POLL */ +#ifdef HAVE_UDP_POLL + if (psock->s_type != SOCK_STREAM) + { + return udp_pollsetup(psock, fds); + } + else +#endif /* HAVE_UDP_POLL */ + { + return -ENOSYS; + } +} +#endif /* HAVE_TCP_POLL || HAVE_UDP_POLL */ + +/**************************************************************************** + * Name: inet_pollteardown + * + * Description: + * Teardown monitoring of events on an socket + * + * Input Parameters: + * psock - The TCP/IP socket of interest + * fds - The structure describing the events to be monitored, OR NULL if + * this is a request to stop monitoring events. + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +#if defined(HAVE_TCP_POLL) || defined(HAVE_UDP_POLL) +static inline int inet_pollteardown(FAR struct socket *psock, + FAR struct pollfd *fds) +{ +#ifdef HAVE_TCP_POLL + if (psock->s_type == SOCK_STREAM) + { + return tcp_pollteardown(psock, fds); + } + else +#endif /* HAVE_TCP_POLL */ +#ifdef HAVE_UDP_POLL + if (psock->s_type == SOCK_DGRAM) + { + return udp_pollteardown(psock, fds); + } + else +#endif /* HAVE_UDP_POLL */ + { + return -ENOSYS; + } +} +#endif /* HAVE_TCP_POLL || HAVE_UDP_POLL */ + +/**************************************************************************** + * Name: inet_poll + * + * Description: + * The standard poll() operation redirects operations on socket descriptors + * to net_poll which, indiectly, calls to function. + * + * Input Parameters: + * psock - An instance of the internal socket structure. + * fds - The structure describing the events to be monitored, OR NULL if + * this is a request to stop monitoring events. + * setup - true: Setup up the poll; false: Teardown the poll + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_POLL +static int inet_poll(FAR struct socket *psock, FAR struct pollfd *fds, + bool setup) +{ +#ifdef CONFIG_NET_USRSOCK + if (psock->s_type == SOCK_USRSOCK_TYPE) + { + /* Perform usrsock setup/teardown. */ + + return usrsock_poll(psock, fds, setup); + } + else +#endif +#if defined(HAVE_TCP_POLL) || defined(HAVE_UDP_POLL) + + /* Check if we are setting up or tearing down the poll */ + + if (setup) + { + /* Perform the TCP/IP poll() setup */ + + return inet_pollsetup(psock, fds); + } + else + { + /* Perform the TCP/IP poll() teardown */ + + return inet_pollteardown(psock, fds); + } +#else + { + return -ENOSYS; + } +#endif /* HAVE_TCP_POLL || !HAVE_UDP_POLL */ +} +#endif /* !CONFIG_DISABLE_POLL */ + /**************************************************************************** * Name: inet_send * @@ -990,11 +1211,11 @@ static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, #elif defined(NET_UDP_HAVE_STACK) nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen); #else - nwarn("WARNING: UDP not available in this configuiration\n") + nwarn("WARNING: UDP not available in this configuiration\n"); nsent = -ENOSYS; #endif /* CONFIG_NET_6LOWPAN */ #else - nwarn("WARNING: UDP not enabled in this configuiration\n") + nwarn("WARNING: UDP not enabled in this configuiration\n"); nsent = -EISCONN; #endif /* CONFIG_NET_UDP */ } @@ -1019,4 +1240,4 @@ static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf, * ****************************************************************************/ -#endif /* CONFIG_NET_IPv4 || CONFIG_NET_IPv6 */ +#endif /* HAVE_INET_SOCKETS */ diff --git a/net/socket/ipv4_getsockname.c b/net/socket/ipv4_getsockname.c new file mode 100644 index 0000000000..4c604e22ec --- /dev/null +++ b/net/socket/ipv4_getsockname.c @@ -0,0 +1,196 @@ +/**************************************************************************** + * net/socket/ipv4_getsockname.c + * + * Copyright (C) 2011-2012, 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include "netdev/netdev.h" +#include "socket/socket.h" + +#ifdef CONFIG_NET_IPv4 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ipv4_getsockname + * + * Description: + * The ipv4_getsockname() function retrieves the locally-bound name of the + * specified PF_NET socket. + * + * Parameters: + * psock Point to the socket structure instance [in] + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + * Returned Value: + * On success, 0 is returned, the 'addr' argument points to the address + * of the socket, and the 'addrlen' argument points to the length of the + * address. Otherwise, a negated errno value is returned. See + * getsockname() for the list of returned error values. + * + ****************************************************************************/ + +int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen) +{ + FAR struct sockaddr_in *outaddr = (FAR struct sockaddr_in *)addr; + FAR struct net_driver_s *dev; +#ifdef CONFIG_NETDEV_MULTINIC + in_addr_t lipaddr; + in_addr_t ripaddr; +#endif + + /* Check if enough space has been provided for the full address */ + + if (*addrlen < sizeof(struct sockaddr_in)) + { + /* This function is supposed to return the partial address if + * a smaller buffer has been provided. This support has not + * been implemented. + */ + + return -ENOSYS; + } + + /* Set the port number */ + + switch (psock->s_type) + { +#ifdef NET_TCP_HAVE_STACK + case SOCK_STREAM: + { + FAR struct tcp_conn_s *tcp_conn = (FAR struct tcp_conn_s *)psock->s_conn; + + outaddr->sin_port = tcp_conn->lport; /* Already in network byte order */ + +#ifdef CONFIG_NETDEV_MULTINIC + lipaddr = tcp_conn->u.ipv4.laddr; + ripaddr = tcp_conn->u.ipv4.raddr; +#endif + } + break; +#endif + +#ifdef NET_UDP_HAVE_STACK + case SOCK_DGRAM: + { + FAR struct udp_conn_s *udp_conn = (FAR struct udp_conn_s *)psock->s_conn; + + outaddr->sin_port = udp_conn->lport; /* Already in network byte order */ + +#ifdef CONFIG_NETDEV_MULTINIC + lipaddr = udp_conn->u.ipv4.laddr; + ripaddr = udp_conn->u.ipv4.raddr; +#endif + } + break; +#endif + + default: + return -EOPNOTSUPP; + } + +#ifdef CONFIG_NETDEV_MULTINIC + /* The socket/connection does not know its IP address unless + * CONFIG_NETDEV_MULTINIC is selected. Otherwise the design supports only + * a single network device and only the network device knows the IP address. + */ + + if (lipaddr == 0) + { + outaddr->sin_family = psock->s_domain; + outaddr->sin_addr.s_addr = 0; + *addrlen = sizeof(struct sockaddr_in); + + return OK; + } +#endif + + net_lock(); + +#ifdef CONFIG_NETDEV_MULTINIC + /* Find the device matching the IPv4 address in the connection structure. + * NOTE: listening sockets have no ripaddr. Work around is to use the + * lipaddr when ripaddr is not available. + */ + + if (ripaddr == 0) + { + ripaddr = lipaddr; + } + + dev = netdev_findby_ipv4addr(lipaddr, ripaddr); +#else + /* There is only one, the first network device in the list. */ + + dev = g_netdevices; +#endif + + if (dev == NULL) + { + net_unlock(); + return -EINVAL; + } + + /* Set the address family and the IP address */ + + outaddr->sin_family = psock->s_domain; + outaddr->sin_addr.s_addr = dev->d_ipaddr; + *addrlen = sizeof(struct sockaddr_in); + + net_unlock(); + + /* Return success */ + + return OK; +} + +#endif /* CONFIG_NET_IPv4 */ diff --git a/net/socket/ipv6_getsockname.c b/net/socket/ipv6_getsockname.c new file mode 100644 index 0000000000..d57fd2c979 --- /dev/null +++ b/net/socket/ipv6_getsockname.c @@ -0,0 +1,194 @@ +/**************************************************************************** + * net/socket/ipv6_getsockname.c + * + * Copyright (C) 2011-2012, 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include "netdev/netdev.h" +#include "socket/socket.h" + +#ifdef CONFIG_NET_IPv6 + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ipv6_getsockname + * + * Description: + * The ipv6_getsockname() function retrieves the locally-bound name of the + * specified PF_NET6 socket. + * + * Parameters: + * psock Point to the socket structure instance [in] + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + * Returned Value: + * On success, 0 is returned, the 'addr' argument points to the address + * of the socket, and the 'addrlen' argument points to the length of the + * address. Otherwise, a negated errno value is returned. See + * getsockname() for the list of returned error values. + * + ****************************************************************************/ + +int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen) +{ + FAR struct sockaddr_in6 *outaddr = (FAR struct sockaddr_in6 *)addr; + FAR struct net_driver_s *dev; +#ifdef CONFIG_NETDEV_MULTINIC + net_ipv6addr_t *lipaddr; + net_ipv6addr_t *ripaddr; +#endif + + /* Check if enough space has been provided for the full address */ + + if (*addrlen < sizeof(struct sockaddr_in6)) + { + /* This function is supposed to return the partial address if + * a smaller buffer has been provided. This support has not + * been implemented. + */ + + return -ENOSYS; + } + + /* Set the port number */ + + switch (psock->s_type) + { +#ifdef NET_TCP_HAVE_STACK + case SOCK_STREAM: + { + FAR struct tcp_conn_s *tcp_conn = (FAR struct tcp_conn_s *)psock->s_conn; + outaddr->sin6_port = tcp_conn->lport; /* Already in network byte order */ + +#ifdef CONFIG_NETDEV_MULTINIC + lipaddr = &tcp_conn->u.ipv6.laddr; + ripaddr = &tcp_conn->u.ipv6.raddr; +#endif + } + break; +#endif + +#ifdef NET_UDP_HAVE_STACK + case SOCK_DGRAM: + { + FAR struct udp_conn_s *udp_conn = (FAR struct udp_conn_s *)psock->s_conn; + outaddr->sin6_port = udp_conn->lport; /* Already in network byte order */ + +#ifdef CONFIG_NETDEV_MULTINIC + lipaddr = &udp_conn->u.ipv6.laddr; + ripaddr = &udp_conn->u.ipv6.raddr; +#endif + } + break; +#endif + + default: + return -EOPNOTSUPP; + } + +#ifdef CONFIG_NETDEV_MULTINIC + /* The socket/connection does not know its IP address unless + * CONFIG_NETDEV_MULTINIC is selected. Otherwise the design supports only + * a single network device and only the network device knows the IP address. + */ + + if (net_ipv6addr_cmp(lipaddr, g_ipv6_allzeroaddr)) + { + outaddr->sin6_family = AF_INET6; + memcpy(outaddr->sin6_addr.in6_u.u6_addr8, g_ipv6_allzeroaddr, 16); + *addrlen = sizeof(struct sockaddr_in6); + + return OK; + } +#endif + + net_lock(); + +#ifdef CONFIG_NETDEV_MULTINIC + /* Find the device matching the IPv6 address in the connection structure. + * NOTE: listening sockets have no ripaddr. Work around is to use the + * lipaddr when ripaddr is not available. + */ + + if (net_ipv6addr_cmp(ripaddr, g_ipv6_allzeroaddr)) + { + ripaddr = lipaddr; + } + + dev = netdev_findby_ipv6addr(*lipaddr, *ripaddr); +#else + /* There is only one, the first network device in the list. */ + + dev = g_netdevices; +#endif + + if (!dev) + { + net_unlock(); + return -EINVAL; + } + + /* Set the address family and the IP address */ + + outaddr->sin6_family = AF_INET6; + memcpy(outaddr->sin6_addr.in6_u.u6_addr8, dev->d_ipv6addr, 16); + *addrlen = sizeof(struct sockaddr_in6); + + net_unlock(); + + /* Return success */ + + return OK; +} + +#endif /* CONFIG_NET_IPv6 */ diff --git a/net/socket/net_clone.c b/net/socket/net_clone.c index 7ab3852574..8139411529 100644 --- a/net/socket/net_clone.c +++ b/net/socket/net_clone.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/net_clone.c * - * Copyright (C) 2009, 2011-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2009, 2011-2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -48,12 +48,7 @@ #include #include -#include "tcp/tcp.h" -#include "udp/udp.h" -#include "pkt/pkt.h" -#include "local/local.h" #include "socket/socket.h" -#include "usrsock/usrsock.h" /**************************************************************************** * Public Functions diff --git a/net/socket/net_poll.c b/net/socket/net_poll.c index b8cbaf3e02..4365246f34 100644 --- a/net/socket/net_poll.c +++ b/net/socket/net_poll.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/net_poll.c * - * Copyright (C) 2008-2009, 2011-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2008-2009, 2011-2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -39,173 +39,15 @@ #include +#include #include -#include "tcp/tcp.h" -#include "udp/udp.h" -#include "local/local.h" +#include + #include "socket/socket.h" -#include "usrsock/usrsock.h" #if defined(CONFIG_NET) && !defined(CONFIG_DISABLE_POLL) -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Network polling can only be supported if poll support is provided by TCP, - * UDP, or LOCAL sockets. - */ - -#undef HAVE_NET_POLL -#if defined(HAVE_TCP_POLL) || defined(HAVE_UDP_POLL) || \ - defined(HAVE_LOCAL_POLL) || defined(CONFIG_NET_USRSOCK) -# define HAVE_NET_POLL 1 -#endif - -#ifdef HAVE_NET_POLL - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: net_pollsetup - * - * Description: - * Setup to monitor events on one socket - * - * Input Parameters: - * psock - The socket of interest - * fds - The structure describing the events to be monitored, OR NULL if - * this is a request to stop monitoring events. - * - * Returned Value: - * 0: Success; Negated errno on failure - * - ****************************************************************************/ - -static inline int net_pollsetup(FAR struct socket *psock, - FAR struct pollfd *fds) -{ -#if defined(HAVE_TCP_POLL) || defined(HAVE_LOCAL_POLL) - if (psock->s_type == SOCK_STREAM) - { -#ifdef HAVE_LOCAL_POLL -#ifdef HAVE_TCP_POLL - if (psock->s_domain == PF_LOCAL) -#endif - { - return local_pollsetup(psock, fds); - } -#endif /* HAVE_LOCAL_POLL */ - -#ifdef HAVE_TCP_POLL -#ifdef HAVE_LOCAL_POLL - else -#endif - { - return tcp_pollsetup(psock, fds); - } -#endif /* HAVE_TCP_POLL */ - } -#endif /* HAVE_TCP_POLL || HAVE_LOCAL_POLL */ - -#if defined(HAVE_UDP_POLL) || defined(HAVE_LOCAL_POLL) - if (psock->s_type != SOCK_STREAM) - { -#ifdef HAVE_LOCAL_POLL -#ifdef HAVE_UDP_POLL - if (psock->s_domain == PF_LOCAL) -#endif - { - return local_pollsetup(psock, fds); - } -#endif /* HAVE_LOCAL_POLL */ - -#ifdef HAVE_UDP_POLL -#ifdef HAVE_LOCAL_POLL - else -#endif - { - return udp_pollsetup(psock, fds); - } -#endif /* HAVE_UDP_POLL */ - } -#endif /* HAVE_UDP_POLL || HAVE_LOCAL_POLL */ - - return -ENOSYS; -} - -/**************************************************************************** - * Name: net_pollteardown - * - * Description: - * Teardown monitoring of events on an socket - * - * Input Parameters: - * psock - The TCP/IP socket of interest - * fds - The structure describing the events to be monitored, OR NULL if - * this is a request to stop monitoring events. - * - * Returned Value: - * 0: Success; Negated errno on failure - * - ****************************************************************************/ - -static inline int net_pollteardown(FAR struct socket *psock, - FAR struct pollfd *fds) -{ -#if defined(HAVE_TCP_POLL) || defined(HAVE_LOCAL_POLL) - if (psock->s_type == SOCK_STREAM) - { -#ifdef HAVE_LOCAL_POLL -#ifdef HAVE_TCP_POLL - if (psock->s_domain == PF_LOCAL) -#endif - { - return local_pollteardown(psock, fds); - } -#endif /* HAVE_LOCAL_POLL */ - -#ifdef HAVE_TCP_POLL -#ifdef HAVE_LOCAL_POLL - else -#endif - { - return tcp_pollteardown(psock, fds); - } -#endif /* HAVE_TCP_POLL */ - } -#endif /* HAVE_TCP_POLL || HAVE_LOCAL_POLL */ - -#if defined(HAVE_UDP_POLL) || defined(HAVE_LOCAL_POLL) - if (psock->s_type != SOCK_STREAM) - { -#ifdef HAVE_LOCAL_POLL -#ifdef HAVE_UDP_POLL - if (psock->s_domain == PF_LOCAL) -#endif - { - return local_pollteardown(psock, fds); - } -#endif /* HAVE_LOCAL_POLL */ - -#ifdef HAVE_UDP_POLL -#ifdef HAVE_LOCAL_POLL - else -#endif - { - return udp_pollteardown(psock, fds); - } -#endif /* HAVE_UDP_POLL */ - } -#endif /* HAVE_UDP_POLL || HAVE_LOCAL_POLL */ - - return -ENOSYS; -} -#endif /* HAVE_NET_POLL */ - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -230,37 +72,12 @@ static inline int net_pollteardown(FAR struct socket *psock, int psock_poll(FAR struct socket *psock, FAR struct pollfd *fds, bool setup) { -#ifndef HAVE_NET_POLL - return -ENOSYS; -#else - int ret; + DEBUGASSERT(psock != NULL && fds != NULL); -#ifdef CONFIG_NET_USRSOCK - if (psock->s_type == SOCK_USRSOCK_TYPE) - { - /* Perform usrsock setup/teardown. */ + /* Let the address family's poll() method handle the operation */ - return usrsock_poll(psock, fds, setup); - } -#endif - - /* Check if we are setting up or tearing down the poll */ - - if (setup) - { - /* Perform the TCP/IP poll() setup */ - - ret = net_pollsetup(psock, fds); - } - else - { - /* Perform the TCP/IP poll() teardown */ - - ret = net_pollteardown(psock, fds); - } - - return ret; -#endif /* HAVE_NET_POLL */ + DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_poll != NULL); + return psock->s_sockif->si_poll(psock, fds, setup); } /**************************************************************************** @@ -288,6 +105,8 @@ int net_poll(int sockfd, struct pollfd *fds, bool setup) #else FAR struct socket *psock; + DEBUGASSERT(fds != NULL); + /* Get the underlying socket structure and verify that the sockfd * corresponds to valid, allocated socket */ diff --git a/net/socket/net_sendfile.c b/net/socket/net_sendfile.c index 8f17f8a5c2..6348df24a7 100644 --- a/net/socket/net_sendfile.c +++ b/net/socket/net_sendfile.c @@ -40,497 +40,19 @@ ****************************************************************************/ #include -#if defined(CONFIG_NET) && defined(CONFIG_NET_TCP) #include #include #include -#include -#include -#include -#include -#include -#include #include #include -#include -#include -#include -#include #include -#include -#include -#include -#include "netdev/netdev.h" -#include "devif/devif.h" -#include "arp/arp.h" -#include "icmpv6/icmpv6.h" -#include "neighbor/neighbor.h" -#include "tcp/tcp.h" #include "socket/socket.h" -#ifdef NET_TCP_HAVE_STACK - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#if defined(CONFIG_NET_TCP_SPLIT) && !defined(CONFIG_NET_TCP_SPLIT_SIZE) -# define CONFIG_NET_TCP_SPLIT_SIZE 40 -#endif - -#define TCPIPv4BUF ((struct tcp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv4_HDRLEN]) -#define TCPIPv6BUF ((struct tcp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN]) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This structure holds the state of the send operation until it can be - * operated upon from the interrupt level. - */ - -struct sendfile_s -{ - FAR struct socket *snd_sock; /* Points to the parent socket structure */ - FAR struct devif_callback_s *snd_datacb; /* Data callback */ - FAR struct devif_callback_s *snd_ackcb; /* ACK callback */ - FAR struct file *snd_file; /* File structure of the input file */ - sem_t snd_sem; /* Used to wake up the waiting thread */ - off_t snd_foffset; /* Input file offset */ - size_t snd_flen; /* File length */ - ssize_t snd_sent; /* The number of bytes sent */ - uint32_t snd_isn; /* Initial sequence number */ - uint32_t snd_acked; /* The number of bytes acked */ -#ifdef CONFIG_NET_SOCKOPTS - systime_t snd_time; /* Last send time for determining timeout */ -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: sendfile_timeout - * - * Description: - * Check for send timeout. - * - * Parameters: - * pstate - send state structure - * - * Returned Value: - * TRUE:timeout FALSE:no timeout - * - * Assumptions: - * Running at the interrupt level - * - ****************************************************************************/ - -#ifdef CONFIG_NET_SOCKOPTS -static inline int sendfile_timeout(FAR struct sendfile_s *pstate) -{ - FAR struct socket *psock = 0; - - /* Check for a timeout configured via setsockopts(SO_SNDTIMEO). - * If none... we well let the send wait forever. - */ - - psock = pstate->snd_sock; - if (psock && psock->s_sndtimeo != 0) - { - /* Check if the configured timeout has elapsed */ - - return net_timeo(pstate->snd_time, psock->s_sndtimeo); - } - - /* No timeout */ - - return FALSE; -} -#endif /* CONFIG_NET_SOCKOPTS */ - -static uint16_t ack_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, - FAR void *pvpriv, uint16_t flags) -{ - FAR struct sendfile_s *pstate = (FAR struct sendfile_s *)pvpriv; - - ninfo("flags: %04x\n", flags); - - if ((flags & TCP_ACKDATA) != 0) - { - FAR struct tcp_hdr_s *tcp; - -#ifdef CONFIG_NET_SOCKOPTS - /* Update the timeout */ - - pstate->snd_time = clock_systimer(); -#endif - - /* Get the offset address of the TCP header */ - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - if (IFF_IS_IPv6(dev->d_flags)) -#endif - { - DEBUGASSERT(pstate->snd_sock == PF_INET6); - tcp = TCPIPv6BUF; - } -#endif /* CONFIG_NET_IPv6 */ - -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - else -#endif - { - DEBUGASSERT(pstate->snd_sock == PF_INET); - tcp = TCPIPv4BUF; - } -#endif /* CONFIG_NET_IPv4 */ - - /* The current acknowledgement number number is the (relative) offset - * of the of the next byte needed by the receiver. The snd_isn is the - * offset of the first byte to send to the receiver. The difference - * is the number of bytes to be acknowledged. - */ - - pstate->snd_acked = tcp_getsequence(tcp->ackno) - pstate->snd_isn; - ninfo("ACK: acked=%d sent=%d flen=%d\n", - pstate->snd_acked, pstate->snd_sent, pstate->snd_flen); - - dev->d_sndlen = 0; - - flags &= ~TCP_ACKDATA; - } - else if ((flags & TCP_REXMIT) != 0) - { - nwarn("WARNING: TCP_REXMIT\n"); - - /* Yes.. in this case, reset the number of bytes that have been sent - * to the number of bytes that have been ACKed. - */ - - pstate->snd_sent = pstate->snd_acked; - } - - /* Check for a loss of connection */ - - else if ((flags & TCP_DISCONN_EVENTS) != 0) - { - /* Report not connected */ - - nwarn("WARNING: Lost connection\n"); - - net_lostconnection(pstate->snd_sock, flags); - pstate->snd_sent = -ENOTCONN; - } - - /* Wake up the waiting thread */ - - sem_post(&pstate->snd_sem); - - return flags; -} - -/**************************************************************************** - * Name: sendfile_addrcheck - * - * Description: - * Check if the destination IP address is in the IPv4 ARP or IPv6 Neighbor - * tables. If not, then the send won't actually make it out... it will be - * replaced with an ARP request (IPv4) or a Neighbor Solicitation (IPv6). - * - * NOTE 1: This could be an expensive check if there are a lot of - * entries in the ARP or Neighbor tables. - * - * NOTE 2: If we are actually harvesting IP addresses on incoming IP - * packets, then this check should not be necessary; the MAC mapping - * should already be in the ARP table in many cases (IPv4 only). - * - * NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP - * address mapping is already in the ARP table. - * - * Parameters: - * conn - The TCP connection structure - * - * Returned Value: - * None - * - * Assumptions: - * Running at the interrupt level - * - ****************************************************************************/ - -#ifdef CONFIG_NET_ETHERNET -static inline bool sendfile_addrcheck(FAR struct tcp_conn_s *conn) -{ -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - if (conn->domain == PF_INET) -#endif - { -#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND) - return (arp_find(conn->u.ipv4.raddr) != NULL); -#else - return true; -#endif - } -#endif /* CONFIG_NET_IPv4 */ - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - else -#endif - { -#if !defined(CONFIG_NET_ICMPv6_NEIGHBOR) - return (neighbor_findentry(conn->u.ipv6.raddr) != NULL); -#else - return true; -#endif - } -#endif /* CONFIG_NET_IPv6 */ -} - -#else /* CONFIG_NET_ETHERNET */ -# sendfile_addrcheck(r) (true) -#endif /* CONFIG_NET_ETHERNET */ - -/**************************************************************************** - * Name: sendfile_interrupt - * - * Description: - * This function is called from the interrupt level to perform the actual - * send operation when polled by the lower, device interfacing layer. - * - * Parameters: - * dev The structure of the network driver that caused the interrupt - * conn The connection structure associated with the socket - * flags Set of events describing why the callback was invoked - * - * Returned Value: - * None - * - * Assumptions: - * Running at the interrupt level - * - ****************************************************************************/ - -static uint16_t sendfile_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, - FAR void *pvpriv, uint16_t flags) -{ - FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn; - FAR struct sendfile_s *pstate = (FAR struct sendfile_s *)pvpriv; - int ret; - -#ifdef CONFIG_NETDEV_MULTINIC - /* The TCP socket is connected and, hence, should be bound to a device. - * Make sure that the polling device is the own that we are bound to. - */ - - DEBUGASSERT(conn->dev != NULL); - if (dev != conn->dev) - { - return flags; - } -#endif - - ninfo("flags: %04x acked: %d sent: %d\n", - flags, pstate->snd_acked, pstate->snd_sent); - - /* Check for a loss of connection */ - - if ((flags & TCP_DISCONN_EVENTS) != 0) - { - /* Report not connected */ - - nwarn("WARNING: Lost connection\n"); - - net_lostconnection(pstate->snd_sock, flags); - pstate->snd_sent = -ENOTCONN; - goto end_wait; - } - - /* We get here if (1) not all of the data has been ACKed, (2) we have been - * asked to retransmit data, (3) the connection is still healthy, and (4) - * the outgoing packet is available for our use. In this case, we are - * now free to send more data to receiver -- UNLESS the buffer contains - * unprocessing incoming data. In that event, we will have to wait for the - * next polling cycle. - */ - - if ((flags & TCP_NEWDATA) == 0 && pstate->snd_sent < pstate->snd_flen) - { - /* Get the amount of data that we can send in the next packet */ - - uint32_t sndlen = pstate->snd_flen - pstate->snd_sent; - - if (sndlen > conn->mss) - { - sndlen = conn->mss; - } - - /* Check if we have "space" in the window */ - - if ((pstate->snd_sent - pstate->snd_acked + sndlen) < conn->winsize) - { - uint32_t seqno; - - /* Then set-up to send that amount of data. (this won't actually - * happen until the polling cycle completes). - */ - - ret = file_seek(pstate->snd_file, - pstate->snd_foffset + pstate->snd_sent, SEEK_SET); - if (ret < 0) - { - int errcode = get_errno(); - nerr("ERROR: Failed to lseek: %d\n", errcode); - pstate->snd_sent = -errcode; - goto end_wait; - } - - ret = file_read(pstate->snd_file, dev->d_appdata, sndlen); - if (ret < 0) - { - int errcode = get_errno(); - nerr("ERROR: Failed to read from input file: %d\n", errcode); - pstate->snd_sent = -errcode; - goto end_wait; - } - - dev->d_sndlen = sndlen; - - /* Set the sequence number for this packet. NOTE: The network updates - * sndseq on recept of ACK *before* this function is called. In that - * case sndseq will point to the next unacknowledge byte (which might - * have already been sent). We will overwrite the value of sndseq - * here before the packet is sent. - */ - - seqno = pstate->snd_sent + pstate->snd_isn; - ninfo("SEND: sndseq %08x->%08x len: %d\n", conn->sndseq, seqno, ret); - - tcp_setsequence(conn->sndseq, seqno); - - /* Check if the destination IP address is in the ARP or Neighbor - * table. If not, then the send won't actually make it out... it - * will be replaced with an ARP request or Neighbor Solicitation. - */ - - if (pstate->snd_sent != 0 || sendfile_addrcheck(conn)) - { - /* Update the amount of data sent (but not necessarily ACKed) */ - - pstate->snd_sent += sndlen; - ninfo("pid: %d SEND: acked=%d sent=%d flen=%d\n", getpid(), - pstate->snd_acked, pstate->snd_sent, pstate->snd_flen); - } - } - else - { - nwarn("WARNING: Window full, wait for ack\n"); - goto wait; - } - } - -#ifdef CONFIG_NET_SOCKOPTS - /* All data has been send and we are just waiting for ACK or re-transmit - * indications to complete the send. Check for a timeout. - */ - - if (sendfile_timeout(pstate)) - { - /* Yes.. report the timeout */ - - nwarn("WARNING: SEND timeout\n"); - pstate->snd_sent = -ETIMEDOUT; - goto end_wait; - } -#endif /* CONFIG_NET_SOCKOPTS */ - - if (pstate->snd_sent >= pstate->snd_flen - && pstate->snd_acked < pstate->snd_flen) - { - /* All data has been sent, but there are outstanding ACK's */ - - goto wait; - } - -end_wait: - - /* Do not allow any further callbacks */ - - pstate->snd_datacb->flags = 0; - pstate->snd_datacb->priv = NULL; - pstate->snd_datacb->event = NULL; - - /* Wake up the waiting thread */ - - sem_post(&pstate->snd_sem); - -wait: - return flags; -} - -/**************************************************************************** - * Name: sendfile_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 - * - ****************************************************************************/ - -static inline void sendfile_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 */ -} +#ifdef CONFIG_NET_SENDFILE /**************************************************************************** * Public Functions @@ -540,11 +62,8 @@ static inline void sendfile_txnotify(FAR struct socket *psock, * Name: net_sendfile * * Description: - * The send() call may be used only when the socket is in a connected state - * (so that the intended recipient is known). The only difference between - * send() and write() is the presence of flags. With zero flags parameter, - * send() is equivalent to write(). Also, send(sockfd,buf,len,flags) is - * equivalent to sendto(sockfd,buf,len,flags,NULL,0). + * The net_sendfile() call may be used only when the socket is in a + * connected state (so that the intended recipient is known). * * Parameters: * psock An instance of the internal socket structure. @@ -600,27 +119,33 @@ static inline void sendfile_txnotify(FAR struct socket *psock, * ****************************************************************************/ -ssize_t net_sendfile(int outfd, struct file *infile, off_t *offset, +ssize_t net_sendfile(int outfd, FAR struct file *infile, FAR off_t *offset, size_t count) { FAR struct socket *psock = sockfd_socket(outfd); - FAR struct tcp_conn_s *conn; - struct sendfile_s state; + ssize_t ret; int errcode; + DEBUGASSERT(psock->sock != NULL && infile != NULL); + /* Verify that the sockfd corresponds to valid, allocated socket */ - if (!psock || psock->s_crefs <= 0) + if (psock != NULL || psock->s_crefs <= 0) { nerr("ERROR: Invalid socket\n"); errcode = EBADF; goto errout; } -#ifdef CONFIG_NET_USRSOCK - /* If this is a usrsock socket, use generic sendfile implementation. */ + /* Check if the address family supports the optimized sendfile(). If not, + * revert to the slow version. + * + * The address family indicates is support with a non-NULL si_sendfile() + * method in the socket interface. + */ - if (psock->s_type == SOCK_USRSOCK_TYPE) + DEBUGASSERT(psock->sockif != NULL); + if (psock->sockif->s_sendfile == NULL) { int infd; @@ -630,169 +155,19 @@ ssize_t net_sendfile(int outfd, struct file *infile, off_t *offset, infd = infile - list->fl_files; return lib_sendfile(outfd, infd, offset, count); } -#endif /* CONFIG_NET_USRSOCK */ - - /* If this is an un-connected socket, then return ENOTCONN */ - - if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags)) - { - nerr("ERROR: Not connected\n"); - errcode = ENOTCONN; - goto errout; - } - - /* Make sure that we have the IP address mapping */ - - conn = (FAR struct tcp_conn_s *)psock->s_conn; - DEBUGASSERT(conn); - -#if defined(CONFIG_NET_ARP_SEND) || defined(CONFIG_NET_ICMPv6_NEIGHBOR) -#ifdef CONFIG_NET_ARP_SEND -#ifdef CONFIG_NET_ICMPv6_NEIGHBOR - if (psock->s_domain == PF_INET) -#endif - { - /* Make sure that the IP address mapping is in the ARP table */ - - ret = arp_send(conn->u.ipv4.raddr); - } -#endif /* CONFIG_NET_ARP_SEND */ - - -#ifdef CONFIG_NET_ICMPv6_NEIGHBOR -#ifdef CONFIG_NET_ARP_SEND - else -#endif - { - /* Make sure that the IP address mapping is in the Neighbor Table */ - - ret = icmpv6_neighbor(conn->u.ipv6.raddr); - } -#endif /* CONFIG_NET_ICMPv6_NEIGHBOR */ - - /* Did we successfully get the address mapping? */ - - if (ret < 0) - { - nerr("ERROR: Not reachable\n"); - errcode = ENETUNREACH; - goto errout; - } -#endif /* CONFIG_NET_ARP_SEND || CONFIG_NET_ICMPv6_NEIGHBOR */ - - /* Set the socket state to sending */ - - psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); - - /* Initialize the state structure. This is done with interrupts - * disabled because we don't want anything to happen until we - * are ready. - */ - - net_lock(); - memset(&state, 0, sizeof(struct sendfile_s)); - - /* This semaphore is used for signaling and, hence, should not have - * priority inheritance enabled. - */ - - sem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */ - sem_setprotocol(&state.snd_sem, SEM_PRIO_NONE); - - state.snd_sock = psock; /* Socket descriptor to use */ - state.snd_foffset = offset ? *offset : 0; /* Input file offset */ - state.snd_flen = count; /* Number of bytes to send */ - state.snd_file = infile; /* File to read from */ - - /* Allocate resources to receive a callback */ - - state.snd_datacb = tcp_callback_alloc(conn); - - if (state.snd_datacb == NULL) - { - nerr("ERROR: Failed to allocate data callback\n"); - errcode = ENOMEM; - goto errout_locked; - } - - state.snd_ackcb = tcp_callback_alloc(conn); - - if (state.snd_ackcb == NULL) - { - nerr("ERROR: Failed to allocate ack callback\n"); - errcode = ENOMEM; - goto errout_datacb; - } - - /* Get the initial sequence number that will be used */ - - state.snd_isn = tcp_getsequence(conn->sndseq); - - /* There is no outstanding, unacknowledged data after this - * initial sequence number. - */ - - conn->unacked = 0; - -#ifdef CONFIG_NET_SOCKOPTS - /* Set the initial time for calculating timeouts */ - - state.snd_time = clock_systimer(); -#endif - - /* Set up the ACK callback in the connection */ - - state.snd_ackcb->flags = (TCP_ACKDATA | TCP_REXMIT | TCP_DISCONN_EVENTS); - state.snd_ackcb->priv = (FAR void *)&state; - state.snd_ackcb->event = ack_interrupt; - - /* Perform the TCP send operation */ - - do - { - state.snd_datacb->flags = TCP_POLL; - state.snd_datacb->priv = (FAR void *)&state; - state.snd_datacb->event = sendfile_interrupt; - - /* Notify the device driver of the availability of TX data */ - - sendfile_txnotify(psock, conn); - net_lockedwait(&state.snd_sem); - } - while (state.snd_sent >= 0 && state.snd_acked < state.snd_flen); - - /* Set the socket state to idle */ - - psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); - - tcp_callback_free(conn, state.snd_ackcb); - -errout_datacb: - tcp_callback_free(conn, state.snd_datacb); - -errout_locked: - - sem_destroy(&state. snd_sem); - net_unlock(); - -errout: - - if (errcode) - { - set_errno(errcode); - return ERROR; - } - else if (state.snd_sent < 0) - { - set_errno(-state.snd_sent); - return ERROR; - } else { - return state.snd_sent; + /* The address family can handle the optimized file send */ + + ret = psock->sockif->s_sendfile(psock, offset, count); + if (ret < 0) + { + set_errno(-ret); + return ERROR; + } + + return ret; } } -#endif /* NET_TCP_HAVE_STACK */ - -#endif /* CONFIG_NET && CONFIG_NET_TCP */ +#endif /* CONFIG_NET_SENDFILE */ diff --git a/net/socket/net_sockif.c b/net/socket/net_sockif.c index 76e273ff97..48ccd0496a 100644 --- a/net/socket/net_sockif.c +++ b/net/socket/net_sockif.c @@ -49,8 +49,6 @@ #include "pkt/pkt.h" #include "socket/socket.h" -#ifdef CONFIG_NET - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -78,11 +76,11 @@ FAR const struct sock_intf_s *net_sockif(sa_family_t family) switch (family) { -#if defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_IPv6) -#ifdef CONFIG_NET_IPv4 +#ifdef HAVE_INET_SOCKETS +#ifdef HAVE_PFINET_SOCKETS case PF_INET: #endif -#ifdef CONFIG_NET_IPv6 +#ifdef HAVE_PFINET6_SOCKETS case PF_INET6: #endif sockif = &g_inet_sockif; @@ -107,5 +105,3 @@ FAR const struct sock_intf_s *net_sockif(sa_family_t family) return sockif; } - -#endif /* CONFIG_NET */ diff --git a/net/socket/net_vfcntl.c b/net/socket/net_vfcntl.c index d96988515f..54e5c8ac4a 100644 --- a/net/socket/net_vfcntl.c +++ b/net/socket/net_vfcntl.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include diff --git a/net/socket/send.c b/net/socket/send.c index 9af7e88cdb..4556f128d1 100644 --- a/net/socket/send.c +++ b/net/socket/send.c @@ -47,11 +47,6 @@ #include -#include "pkt/pkt.h" -#include "tcp/tcp.h" -#include "udp/udp.h" -#include "sixlowpan/sixlowpan.h" -#include "local/local.h" #include "socket/socket.h" /**************************************************************************** diff --git a/net/socket/sendto.c b/net/socket/sendto.c index 6ddf2a5958..341a7ecdc2 100644 --- a/net/socket/sendto.c +++ b/net/socket/sendto.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/sendto.c * - * Copyright (C) 2007-2009, 2011-2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -49,9 +49,6 @@ #include #include -#include "udp/udp.h" -#include "sixlowpan/sixlowpan.h" -#include "local/local.h" #include "socket/socket.h" /**************************************************************************** @@ -150,17 +147,17 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, /* Verify that the psock corresponds to valid, allocated socket */ - if (!psock || psock->s_crefs <= 0) + if (psock == NULL || psock->s_crefs <= 0) { nerr("ERROR: Invalid socket\n"); errcode = EBADF; goto errout; } - /* Let the address family's send() method handle the operation */ + /* Let the address family's sendto() method handle the operation */ - DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_send != NULL); - nsent = psock->s_sockif->si_send(psock, buf, len, flags); + DEBUGASSERT(psock->s_sockif != NULL && psock->s_sockif->si_sendto != NULL); + nsent = psock->s_sockif->si_sendto(psock, buf, len, flags, to, tolen); /* Check if the domain-specific sendto() logic failed */ diff --git a/net/socket/socket.h b/net/socket/socket.h index 3465f74b96..747856f7a6 100644 --- a/net/socket/socket.h +++ b/net/socket/socket.h @@ -49,12 +49,30 @@ #include #include -#include "tcp/tcp.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +/* Configuration */ + +#undef HAVE_INET_SOCKETS +#undef HAVE_PFINET_SOCKETS +#undef HAVE_PFINET6_SOCKETS + +#if defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_IPv6) || \ + defined(CONFIG_NET_USRSOCK) +# define HAVE_INET_SOCKETS + +# if defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_USRSOCK) +# define HAVE_PFINET_SOCKETS +# endif + +# if defined(CONFIG_NET_IPv6) || defined(CONFIG_NET_USRSOCK) +# define HAVE_PFINET6_SOCKETS +# endif +#endif + /* Definitions of 8-bit socket flags */ /* Bits 0-2: Socket state */ @@ -149,7 +167,7 @@ extern "C" #define EXTERN extern #endif -#if defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_IPv6) +#ifdef HAVE_INET_SOCKETS EXTERN const struct sock_intf_s g_inet_sockif; #endif @@ -157,7 +175,7 @@ EXTERN const struct sock_intf_s g_inet_sockif; * Public Function Prototypes ****************************************************************************/ -#ifdef NET_TCP_HAVE_STACK +#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK) struct tcp_conn_s; /* Forward reference */ #endif @@ -176,7 +194,7 @@ struct tcp_conn_s; /* Forward reference */ * ****************************************************************************/ -int sockfd_allocate(int minsd); +int sockfd_allocate(int minsd); /**************************************************************************** * Name: sock_release @@ -265,7 +283,7 @@ FAR const struct sock_intf_s *net_sockif(sa_family_t family); * ****************************************************************************/ -#ifdef NET_TCP_HAVE_STACK +#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK) int net_startmonitor(FAR struct socket *psock); #endif @@ -287,7 +305,7 @@ int net_startmonitor(FAR struct socket *psock); * ****************************************************************************/ -#ifdef NET_TCP_HAVE_STACK +#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK) void net_stopmonitor(FAR struct tcp_conn_s *conn); #endif @@ -309,7 +327,7 @@ void net_stopmonitor(FAR struct tcp_conn_s *conn); * ****************************************************************************/ -#ifdef NET_TCP_HAVE_STACK +#if defined(CONFIG_NET_TCP) && !defined(CONFIG_NET_TCP_NO_STACK) void net_lostconnection(FAR struct socket *psock, uint16_t flags); #endif @@ -436,6 +454,35 @@ int net_timeo(systime_t start_time, socktimeo_t timeo); ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, int flags); +/**************************************************************************** + * Name: ipv4_getsockname and ipv6_sockname + * + * Description: + * The ipv4_getsockname() and ipv6_getsocknam() function retrieve the + * locally-bound name of the specified INET socket. + * + * Parameters: + * psock Point to the socket structure instance [in] + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + * Returned Value: + * On success, 0 is returned, the 'addr' argument points to the address + * of the socket, and the 'addrlen' argument points to the length of the + * address. Otherwise, a negated errno value is returned. See + * getsockname() for the list of returned error values. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IPv4 +int ipv4_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen); +#endif +#ifdef CONFIG_NET_IPv6 +int ipv6_getsockname(FAR struct socket *psock, FAR struct sockaddr *addr, + FAR socklen_t *addrlen); +#endif + /**************************************************************************** * Name: inet_connect * @@ -471,6 +518,32 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, int inet_connect(FAR struct socket *psock, FAR const struct sockaddr *addr, socklen_t addrlen); +/**************************************************************************** + * Name: inet_sendfile + * + * Description: + * The inet_sendfile() call may be used only when the INET socket is in a + * connected state (so that the intended recipient is known). + * + * 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 sendfile() for a list + * appropriate error return values. + * + ****************************************************************************/ + +#if defined(CONFIG_NET_SENDFILE) && defined(CONFIG_NET_TCP) && \ + !defined(CONFIG_NET_TCP_NO_STACK) +ssize_t inet_sendfile(FAR struct socket *psock, FAR struct file *infile, + FAR off_t *offset, size_t count); +#endif + /**************************************************************************** * Name: inet_recvfrom *