You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/01/21 14:30:59 UTC
[incubator-nuttx] 03/04: net/tcp and udp: Move tcp/udp recvfrom
into tcp/udp folder
This is an automated email from the ASF dual-hosted git repository.
gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit e75b5e9d86db281e22a97c58605aea5192c6035a
Author: Xiang Xiao <xi...@xiaomi.com>
AuthorDate: Tue Jan 21 15:50:39 2020 +0800
net/tcp and udp: Move tcp/udp recvfrom into tcp/udp folder
Move tcp/udp recvfrom into tcp/udp folder and remove inet_recvfrom.c
---
net/inet/Make.defs | 4 +-
net/inet/inet.h | 35 --
net/inet/inet_sockif.c | 120 ++++
net/tcp/Make.defs | 2 +-
net/tcp/tcp.h | 25 +
net/{inet/inet_recvfrom.c => tcp/tcp_recvfrom.c} | 708 ++---------------------
net/udp/Make.defs | 2 +
net/udp/udp.h | 24 +
net/udp/udp_recvfrom.c | 707 ++++++++++++++++++++++
9 files changed, 930 insertions(+), 697 deletions(-)
diff --git a/net/inet/Make.defs b/net/inet/Make.defs
index c27b728..6503ff9 100644
--- a/net/inet/Make.defs
+++ b/net/inet/Make.defs
@@ -38,10 +38,10 @@
SOCK_CSRCS += inet_txdrain.c
ifeq ($(CONFIG_NET_IPv4),y)
-SOCK_CSRCS += inet_sockif.c inet_recvfrom.c
+SOCK_CSRCS += inet_sockif.c
SOCK_CSRCS += inet_globals.c
else ifeq ($(CONFIG_NET_IPv6),y)
-SOCK_CSRCS += inet_sockif.c inet_recvfrom.c
+SOCK_CSRCS += inet_sockif.c
SOCK_CSRCS += inet_globals.c
endif
diff --git a/net/inet/inet.h b/net/inet/inet.h
index eef1f36..81f923c 100644
--- a/net/inet/inet.h
+++ b/net/inet/inet.h
@@ -241,41 +241,6 @@ int ipv6_getpeername(FAR struct socket *psock, FAR struct sockaddr *addr,
#endif
/****************************************************************************
- * Name: inet_recvfrom
- *
- * Description:
- * Implements the socket recvfrom interface for the case of the AF_INET
- * and AF_INET6 address families. inet_recvfrom() receives messages from
- * a socket, and may be used to receive data on a socket whether or not it
- * is connection-oriented.
- *
- * If 'from' is not NULL, and the underlying protocol provides the source
- * address, this source address is filled in. The argument 'fromlen' is
- * initialized to the size of the buffer associated with from, and
- * modified on return to indicate the actual size of the address stored
- * there.
- *
- * Input Parameters:
- * psock A pointer to a NuttX-specific, internal socket structure
- * buf Buffer to receive data
- * len Length of buffer
- * flags Receive flags
- * from Address of source (may be NULL)
- * fromlen The length of the address structure
- *
- * Returned Value:
- * On success, returns the number of characters received. If no data is
- * available to be received and the peer has performed an orderly shutdown,
- * recv() will return 0. Otherwise, on errors, a negated errno value is
- * returned (see recvfrom() for the list of appropriate error values).
- *
- ****************************************************************************/
-
-ssize_t inet_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
- int flags, FAR struct sockaddr *from,
- FAR socklen_t *fromlen);
-
-/****************************************************************************
* Name: inet_close
*
* Description:
diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c
index 5ce865f..8a66b89 100644
--- a/net/inet/inet_sockif.c
+++ b/net/inet/inet_sockif.c
@@ -90,6 +90,9 @@ static ssize_t inet_sendto(FAR struct socket *psock, FAR const void *buf,
static ssize_t inet_sendfile(FAR struct socket *psock, FAR struct file *infile,
FAR off_t *offset, size_t count);
#endif
+static ssize_t inet_recvfrom(FAR struct socket *psock, FAR void *buf,
+ size_t len, int flags, FAR struct sockaddr *from,
+ FAR socklen_t *fromlen);
/****************************************************************************
* Private Data
@@ -1274,6 +1277,123 @@ static ssize_t inet_sendfile(FAR struct socket *psock,
}
#endif
+/****************************************************************************
+ * Name: inet_recvfrom
+ *
+ * Description:
+ * Implements the socket recvfrom interface for the case of the AF_INET
+ * and AF_INET6 address families. inet_recvfrom() receives messages from
+ * a socket, and may be used to receive data on a socket whether or not it
+ * is connection-oriented.
+ *
+ * If 'from' is not NULL, and the underlying protocol provides the source
+ * address, this source address is filled in. The argument 'fromlen' is
+ * initialized to the size of the buffer associated with from, and
+ * modified on return to indicate the actual size of the address stored
+ * there.
+ *
+ * Input Parameters:
+ * psock A pointer to a NuttX-specific, internal socket structure
+ * buf Buffer to receive data
+ * len Length of buffer
+ * flags Receive flags
+ * from Address of source (may be NULL)
+ * fromlen The length of the address structure
+ *
+ * Returned Value:
+ * On success, returns the number of characters received. If no data is
+ * available to be received and the peer has performed an orderly shutdown,
+ * recv() will return 0. Otherwise, on errors, a negated errno value is
+ * returned (see recvfrom() for the list of appropriate error values).
+ *
+ ****************************************************************************/
+
+static ssize_t inet_recvfrom(FAR struct socket *psock, FAR void *buf,
+ size_t len, int flags, FAR struct sockaddr *from,
+ FAR socklen_t *fromlen)
+{
+ ssize_t ret;
+
+ /* If a 'from' address has been provided, verify that it is large
+ * enough to hold this address family.
+ */
+
+ if (from)
+ {
+ socklen_t minlen;
+
+ /* Get the minimum socket length */
+
+ switch (psock->s_domain)
+ {
+#ifdef CONFIG_NET_IPv4
+ case PF_INET:
+ {
+ minlen = sizeof(struct sockaddr_in);
+ }
+ break;
+#endif
+
+#ifdef CONFIG_NET_IPv6
+ case PF_INET6:
+ {
+ minlen = sizeof(struct sockaddr_in6);
+ }
+ break;
+#endif
+
+ default:
+ DEBUGPANIC();
+ return -EINVAL;
+ }
+
+ if (*fromlen < minlen)
+ {
+ return -EINVAL;
+ }
+ }
+
+ /* Read from the network interface driver buffer.
+ * Or perform the TCP/IP or UDP recv() operation.
+ */
+
+ switch (psock->s_type)
+ {
+#ifdef CONFIG_NET_TCP
+ case SOCK_STREAM:
+ {
+#ifdef NET_TCP_HAVE_STACK
+ ret = psock_tcp_recvfrom(psock, buf, len, from, fromlen);
+#else
+ ret = -ENOSYS;
+#endif
+ }
+ break;
+#endif /* CONFIG_NET_TCP */
+
+#ifdef CONFIG_NET_UDP
+ case SOCK_DGRAM:
+ {
+#ifdef NET_UDP_HAVE_STACK
+ ret = psock_udp_recvfrom(psock, buf, len, from, fromlen);
+#else
+ ret = -ENOSYS;
+#endif
+ }
+ break;
+#endif /* CONFIG_NET_UDP */
+
+ default:
+ {
+ nerr("ERROR: Unsupported socket type: %d\n", psock->s_type);
+ ret = -ENOSYS;
+ }
+ break;
+ }
+
+ return ret;
+}
+
#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */
/****************************************************************************
diff --git a/net/tcp/Make.defs b/net/tcp/Make.defs
index 8b165da..595f137 100644
--- a/net/tcp/Make.defs
+++ b/net/tcp/Make.defs
@@ -40,7 +40,7 @@ ifneq ($(CONFIG_NET_TCP_NO_STACK),y)
# Socket layer
-SOCK_CSRCS += tcp_connect.c tcp_accept.c
+SOCK_CSRCS += tcp_connect.c tcp_accept.c tcp_recvfrom.c
ifeq ($(CONFIG_NET_TCP_WRITE_BUFFERS),y)
SOCK_CSRCS += tcp_send_buffered.c
diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h
index 93e3cf6..e1ae766 100644
--- a/net/tcp/tcp.h
+++ b/net/tcp/tcp.h
@@ -1267,6 +1267,31 @@ int tcp_backlogdelete(FAR struct tcp_conn_s *conn,
int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
FAR socklen_t *addrlen, FAR void **newconn);
+
+/****************************************************************************
+ * Name: psock_tcp_recvfrom
+ *
+ * Description:
+ * Perform the recvfrom operation for a TCP/IP SOCK_STREAM
+ *
+ * Input Parameters:
+ * psock Pointer to the socket structure for the SOCK_DRAM socket
+ * buf Buffer to receive data
+ * len Length of buffer
+ * from INET address of source (may be NULL)
+ *
+ * Returned Value:
+ * On success, returns the number of characters received. On error,
+ * -errno is returned (see recvfrom for list of errnos).
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR void *buf,
+ size_t len, FAR struct sockaddr *from,
+ FAR socklen_t *fromlen);
+
/****************************************************************************
* Name: psock_tcp_send
*
diff --git a/net/inet/inet_recvfrom.c b/net/tcp/tcp_recvfrom.c
similarity index 52%
rename from net/inet/inet_recvfrom.c
rename to net/tcp/tcp_recvfrom.c
index 7d56b54..e3aa345 100644
--- a/net/inet/inet_recvfrom.c
+++ b/net/tcp/tcp_recvfrom.c
@@ -1,7 +1,7 @@
/****************************************************************************
- * net/inet/inet_recvfrom.c
+ * net/tcp/tcp_recvfrom.c
*
- * Copyright (C) 2007-2009, 2011-2018 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2020 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gn...@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -38,37 +38,23 @@
****************************************************************************/
#include <nuttx/config.h>
+#ifdef CONFIG_NET_TCP
-#ifdef CONFIG_NET
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <debug.h>
#include <assert.h>
-#include <arch/irq.h>
-
-#include <nuttx/semaphore.h>
-#include <nuttx/cancelpt.h>
#include <nuttx/net/net.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/tcp.h>
-#include <nuttx/net/udp.h>
#include "netdev/netdev.h"
#include "devif/devif.h"
#include "tcp/tcp.h"
-#include "udp/udp.h"
-#include "pkt/pkt.h"
-#include "local/local.h"
#include "socket/socket.h"
-#include "usrsock/usrsock.h"
-#include "inet/inet.h"
/****************************************************************************
* Pre-processor Definitions
@@ -77,9 +63,6 @@
#define IPv4BUF ((struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
#define IPv6BUF ((struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
-#define UDPIPv4BUF ((struct udp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv4_HDRLEN])
-#define UDPIPv6BUF ((struct udp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN])
-
#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])
@@ -87,8 +70,7 @@
* Private Types
****************************************************************************/
-#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK)
-struct inet_recvfrom_s
+struct tcp_recvfrom_s
{
FAR struct socket *ir_sock; /* The parent socket structure */
FAR struct devif_callback_s *ir_cb; /* Reference to callback instance */
@@ -100,19 +82,17 @@ struct inet_recvfrom_s
ssize_t ir_recvlen; /* The received length */
int ir_result; /* Success:OK, failure:negated errno */
};
-#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
- * Name: inet_update_recvlen
+ * Name: tcp_update_recvlen
*
* Description:
* Update information about space available for new data and update size
- * of data in buffer, This logic accounts for the case where
- * inet_udp_readahead() sets state.ir_recvlen == -1 .
+ * of data in buffer.
*
* Input Parameters:
* pstate recvfrom state structure
@@ -123,10 +103,8 @@ struct inet_recvfrom_s
*
****************************************************************************/
-#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK)
-
-static inline void inet_update_recvlen(FAR struct inet_recvfrom_s *pstate,
- size_t recvlen)
+static inline void tcp_update_recvlen(FAR struct tcp_recvfrom_s *pstate,
+ size_t recvlen)
{
if (pstate->ir_recvlen < 0)
{
@@ -137,10 +115,9 @@ static inline void inet_update_recvlen(FAR struct inet_recvfrom_s *pstate,
pstate->ir_buffer += recvlen;
pstate->ir_buflen -= recvlen;
}
-#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */
/****************************************************************************
- * Name: inet_recvfrom_newdata
+ * Name: tcp_recvfrom_newdata
*
* Description:
* Copy the read data from the packet
@@ -157,9 +134,8 @@ static inline void inet_update_recvlen(FAR struct inet_recvfrom_s *pstate,
*
****************************************************************************/
-#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK)
-static size_t inet_recvfrom_newdata(FAR struct net_driver_s *dev,
- FAR struct inet_recvfrom_s *pstate)
+static size_t tcp_recvfrom_newdata(FAR struct net_driver_s *dev,
+ FAR struct tcp_recvfrom_s *pstate)
{
size_t recvlen;
@@ -181,14 +157,13 @@ static size_t inet_recvfrom_newdata(FAR struct net_driver_s *dev,
/* Update the accumulated size of the data read */
- inet_update_recvlen(pstate, recvlen);
+ tcp_update_recvlen(pstate, recvlen);
return recvlen;
}
-#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */
/****************************************************************************
- * Name: inet_tcp_newdata
+ * Name: tcp_newdata
*
* Description:
* Copy the read data from the packet
@@ -205,13 +180,12 @@ static size_t inet_recvfrom_newdata(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#ifdef NET_TCP_HAVE_STACK
-static inline void inet_tcp_newdata(FAR struct net_driver_s *dev,
- FAR struct inet_recvfrom_s *pstate)
+static inline void tcp_newdata(FAR struct net_driver_s *dev,
+ FAR struct tcp_recvfrom_s *pstate)
{
/* Take as much data from the packet as we can */
- size_t recvlen = inet_recvfrom_newdata(dev, pstate);
+ size_t recvlen = tcp_recvfrom_newdata(dev, pstate);
/* If there is more data left in the packet that we could not buffer, then
* add it to the read-ahead buffers.
@@ -253,42 +227,9 @@ static inline void inet_tcp_newdata(FAR struct net_driver_s *dev,
dev->d_len = 0;
}
-#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
- * Name: inet_udp_newdata
- *
- * Description:
- * Copy the read data from the packet
- *
- * Input Parameters:
- * dev The sructure of the network driver that generated the event
- * pstate recvfrom state structure
- *
- * Returned Value:
- * None.
- *
- * Assumptions:
- * The network is locked.
- *
- ****************************************************************************/
-
-#ifdef NET_UDP_HAVE_STACK
-static inline void inet_udp_newdata(FAR struct net_driver_s *dev,
- FAR struct inet_recvfrom_s *pstate)
-{
- /* Take as much data from the packet as we can */
-
- inet_recvfrom_newdata(dev, pstate);
-
- /* Indicate no data in the buffer */
-
- dev->d_len = 0;
-}
-#endif /* NET_UDP_HAVE_STACK */
-
-/****************************************************************************
- * Name: inet_tcp_readahead and inet_udp_readahead
+ * Name: tcp_readahead
*
* Description:
* Copy the read-ahead data from the packet
@@ -304,8 +245,7 @@ static inline void inet_udp_newdata(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#ifdef NET_TCP_HAVE_STACK
-static inline void inet_tcp_readahead(struct inet_recvfrom_s *pstate)
+static inline void tcp_readahead(struct tcp_recvfrom_s *pstate)
{
FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pstate->ir_sock->s_conn;
FAR struct iob_s *iob;
@@ -329,7 +269,7 @@ static inline void inet_tcp_readahead(struct inet_recvfrom_s *pstate)
/* Update the accumulated size of the data read */
- inet_update_recvlen(pstate, recvlen);
+ tcp_update_recvlen(pstate, recvlen);
/* If we took all of the data from the I/O buffer chain is empty, then
* release it. If there is still data available in the I/O buffer
@@ -365,98 +305,9 @@ static inline void inet_tcp_readahead(struct inet_recvfrom_s *pstate)
}
}
}
-#endif /* NET_TCP_HAVE_STACK */
-
-#ifdef NET_UDP_HAVE_STACK
-
-static inline void inet_udp_readahead(struct inet_recvfrom_s *pstate)
-{
- FAR struct udp_conn_s *conn = (FAR struct udp_conn_s *)pstate->ir_sock->s_conn;
- FAR struct iob_s *iob;
- int recvlen;
-
- /* Check there is any UDP datagram already buffered in a read-ahead
- * buffer.
- */
-
- pstate->ir_recvlen = -1;
-
- if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
- {
- FAR struct iob_s *tmp;
- uint8_t src_addr_size;
-
- DEBUGASSERT(iob->io_pktlen > 0);
-
- /* Transfer that buffered data from the I/O buffer chain into
- * the user buffer.
- */
-
- recvlen = iob_copyout(&src_addr_size, iob, sizeof(uint8_t), 0);
- if (recvlen != sizeof(uint8_t))
- {
- goto out;
- }
-
- if (0
-#ifdef CONFIG_NET_IPv6
- || src_addr_size == sizeof(struct sockaddr_in6)
-#endif
-#ifdef CONFIG_NET_IPv4
- || src_addr_size == sizeof(struct sockaddr_in)
-#endif
- )
- {
- if (pstate->ir_from)
- {
- socklen_t len = *pstate->ir_fromlen;
- len = (socklen_t)src_addr_size > len ? len : (socklen_t)src_addr_size;
-
- recvlen = iob_copyout((FAR uint8_t *)pstate->ir_from, iob,
- len, sizeof(uint8_t));
- if (recvlen != len)
- {
- goto out;
- }
- }
- }
-
- if (pstate->ir_buflen > 0)
- {
- recvlen = iob_copyout(pstate->ir_buffer, iob, pstate->ir_buflen,
- src_addr_size + sizeof(uint8_t));
-
- ninfo("Received %d bytes (of %d)\n", recvlen, iob->io_pktlen);
-
- /* Update the accumulated size of the data read */
-
- pstate->ir_recvlen = recvlen;
- pstate->ir_buffer += recvlen;
- pstate->ir_buflen -= recvlen;
- }
- else
- {
- pstate->ir_recvlen = 0;
- }
-
-out:
- /* Remove the I/O buffer chain from the head of the read-ahead
- * buffer queue.
- */
-
- tmp = iob_remove_queue(&conn->readahead);
- DEBUGASSERT(tmp == iob);
- UNUSED(tmp);
-
- /* And free the I/O buffer chain */
-
- iob_free_chain(iob, IOBUSER_NET_UDP_READAHEAD);
- }
-}
-#endif
/****************************************************************************
- * Name: inet_tcp_sender
+ * Name: tcp_sender
*
* Description:
* Getting the sender's address from the UDP packet
@@ -473,9 +324,8 @@ out:
*
****************************************************************************/
-#ifdef NET_TCP_HAVE_STACK
-static inline void inet_tcp_sender(FAR struct net_driver_s *dev,
- FAR struct inet_recvfrom_s *pstate)
+static inline void tcp_sender(FAR struct net_driver_s *dev,
+ FAR struct tcp_recvfrom_s *pstate)
{
/* Get the family from the packet type, IP address from the IP header, and
* the port number from the TCP header.
@@ -524,10 +374,9 @@ static inline void inet_tcp_sender(FAR struct net_driver_s *dev,
}
#endif /* CONFIG_NET_IPv4 */
}
-#endif /* NET_TCP_HAVE_STACK */
/****************************************************************************
- * Name: inet_tcp_eventhandler
+ * Name: tcp_eventhandler
*
* Description:
* This function is called with the network locked to perform the actual
@@ -546,12 +395,11 @@ static inline void inet_tcp_sender(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#ifdef NET_TCP_HAVE_STACK
-static uint16_t inet_tcp_eventhandler(FAR struct net_driver_s *dev,
- FAR void *pvconn, FAR void *pvpriv,
- uint16_t flags)
+static uint16_t tcp_eventhandler(FAR struct net_driver_s *dev,
+ FAR void *pvconn, FAR void *pvpriv,
+ uint16_t flags)
{
- FAR struct inet_recvfrom_s *pstate = (struct inet_recvfrom_s *)pvpriv;
+ FAR struct tcp_recvfrom_s *pstate = (struct tcp_recvfrom_s *)pvpriv;
#if 0 /* REVISIT: The assertion fires. Why? */
FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn;
@@ -581,11 +429,11 @@ static uint16_t inet_tcp_eventhandler(FAR struct net_driver_s *dev,
* packet in the read-ahead buffer).
*/
- inet_tcp_newdata(dev, pstate);
+ tcp_newdata(dev, pstate);
/* Save the sender's address in the caller's 'from' location */
- inet_tcp_sender(dev, pstate);
+ tcp_sender(dev, pstate);
/* Indicate that the data has been consumed and that an ACK
* should be sent.
@@ -672,223 +520,9 @@ static uint16_t inet_tcp_eventhandler(FAR struct net_driver_s *dev,
return flags;
}
-#endif /* NET_TCP_HAVE_STACK */
-
-/****************************************************************************
- * Name: inet_udp_sender
- *
- * Description:
- * Getting the sender's address from the UDP packet
- *
- * Input Parameters:
- * dev - The device driver data structure
- * pstate - the recvfrom state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * The network is locked.
- *
- ****************************************************************************/
-
-#ifdef NET_UDP_HAVE_STACK
-static inline void inet_udp_sender(FAR struct net_driver_s *dev,
- FAR struct inet_recvfrom_s *pstate)
-{
- /* Get the family from the packet type, IP address from the IP header, and
- * the port number from the UDP header.
- */
-
-#ifdef CONFIG_NET_IPv6
-#ifdef CONFIG_NET_IPv4
- if (IFF_IS_IPv6(dev->d_flags))
-#endif
- {
- FAR struct sockaddr_in6 *infrom =
- (FAR struct sockaddr_in6 *)pstate->ir_from;
- FAR socklen_t *fromlen = pstate->ir_fromlen;
-
- if (infrom)
- {
- FAR struct udp_hdr_s *udp = UDPIPv6BUF;
- FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
-
- infrom->sin6_family = AF_INET6;
- infrom->sin6_port = udp->srcport;
- *fromlen = sizeof(struct sockaddr_in6);
-
- net_ipv6addr_copy(infrom->sin6_addr.s6_addr, ipv6->srcipaddr);
- }
- }
-#endif /* CONFIG_NET_IPv6 */
-
-#ifdef CONFIG_NET_IPv4
-#ifdef CONFIG_NET_IPv6
- else
-#endif
- {
- FAR struct sockaddr_in *infrom =
- (FAR struct sockaddr_in *)pstate->ir_from;
-
- if (infrom)
- {
-#ifdef CONFIG_NET_IPv6
- FAR struct udp_conn_s *conn =
- (FAR struct udp_conn_s *)pstate->ir_sock->s_conn;
-
- /* Hybrid dual-stack IPv6/IPv4 implementations recognize a special
- * class of addresses, the IPv4-mapped IPv6 addresses.
- */
-
- if (conn->domain == PF_INET6)
- {
- FAR struct sockaddr_in6 *infrom6 = (FAR struct sockaddr_in6 *)infrom;
- FAR socklen_t *fromlen = pstate->ir_fromlen;
- FAR struct udp_hdr_s *udp = UDPIPv6BUF;
- FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
- in_addr_t ipv4addr;
-
- /* Encode the IPv4 address as an IPv4-mapped IPv6 address */
-
- infrom6->sin6_family = AF_INET6;
- infrom6->sin6_port = udp->srcport;
- *fromlen = sizeof(struct sockaddr_in6);
-
- ipv4addr = net_ip4addr_conv32(ipv6->srcipaddr);
- ip6_map_ipv4addr(ipv4addr, infrom6->sin6_addr.s6_addr16);
- }
- else
-#endif
- {
- FAR struct udp_hdr_s *udp = UDPIPv4BUF;
- FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
-
- infrom->sin_family = AF_INET;
- infrom->sin_port = udp->srcport;
-
- net_ipv4addr_copy(infrom->sin_addr.s_addr,
- net_ip4addr_conv32(ipv4->srcipaddr));
- }
- }
- }
-#endif /* CONFIG_NET_IPv4 */
-}
-#endif /* NET_UDP_HAVE_STACK */
-
-/****************************************************************************
- * Name: inet_udp_terminate
- *
- * Description:
- * Terminate the UDP transfer.
- *
- * Input Parameters:
- * pstate - The recvfrom state structure
- * result - The result of the operation
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
-
-#ifdef NET_UDP_HAVE_STACK
-static void inet_udp_terminate(FAR struct inet_recvfrom_s *pstate, int result)
-{
- /* Don't allow any further UDP call backs. */
-
- pstate->ir_cb->flags = 0;
- pstate->ir_cb->priv = NULL;
- pstate->ir_cb->event = NULL;
-
- /* Save the result of the transfer */
-
- pstate->ir_result = result;
-
- /* Wake up the waiting thread, returning the number of bytes
- * actually read.
- */
-
- nxsem_post(&pstate->ir_sem);
-}
-#endif /* NET_UDP_HAVE_STACK */
-
-/****************************************************************************
- * Name: inet_udp_eventhandler
- *
- * Description:
- * This function is called with the network locked to perform the actual
- * UDP receive operation via by the lower, device interfacing layer.
- *
- * Input Parameters:
- * dev The structure of the network driver that generated the event.
- * pvconn The connection structure associated with the socket
- * flags Set of events describing why the callback was invoked
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * The network is locked.
- *
- ****************************************************************************/
-
-#ifdef NET_UDP_HAVE_STACK
-static uint16_t inet_udp_eventhandler(FAR struct net_driver_s *dev,
- FAR void *pvconn, FAR void *pvpriv,
- uint16_t flags)
-{
- FAR struct inet_recvfrom_s *pstate = (FAR struct inet_recvfrom_s *)pvpriv;
-
- ninfo("flags: %04x\n", flags);
-
- /* 'priv' might be null in some race conditions (?) */
-
- if (pstate)
- {
- /* If the network device has gone down, then we will have terminate
- * the wait now with an error.
- */
-
- if ((flags & NETDEV_DOWN) != 0)
- {
- /* Terminate the transfer with an error. */
-
- nerr("ERROR: Network is down\n");
- inet_udp_terminate(pstate, -ENETUNREACH);
- }
-
- /* If new data is available, then complete the read action. */
-
- else if ((flags & UDP_NEWDATA) != 0)
- {
- /* Copy the data from the packet */
-
- inet_udp_newdata(dev, pstate);
-
- /* We are finished. */
-
- ninfo("UDP done\n");
-
- /* Save the sender's address in the caller's 'from' location */
-
- inet_udp_sender(dev, pstate);
-
- /* Don't allow any further UDP call backs. */
-
- inet_udp_terminate(pstate, OK);
-
- /* Indicate that the data has been consumed */
-
- flags &= ~UDP_NEWDATA;
- }
- }
-
- return flags;
-}
-#endif /* NET_UDP_HAVE_STACK */
/****************************************************************************
- * Name: inet_recvfrom_initialize
+ * Name: tcp_recvfrom_initialize
*
* Description:
* Initialize the state structure
@@ -906,15 +540,14 @@ static uint16_t inet_udp_eventhandler(FAR struct net_driver_s *dev,
*
****************************************************************************/
-#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK)
-static void inet_recvfrom_initialize(FAR struct socket *psock, FAR void *buf,
- size_t len, FAR struct sockaddr *infrom,
- FAR socklen_t *fromlen,
- FAR struct inet_recvfrom_s *pstate)
+static void tcp_recvfrom_initialize(FAR struct socket *psock, FAR void *buf,
+ size_t len, FAR struct sockaddr *infrom,
+ FAR socklen_t *fromlen,
+ FAR struct tcp_recvfrom_s *pstate)
{
/* Initialize the state structure. */
- memset(pstate, 0, sizeof(struct inet_recvfrom_s));
+ memset(pstate, 0, sizeof(struct tcp_recvfrom_s));
/* This semaphore is used for signaling and, hence, should not have
* priority inheritance enabled.
@@ -937,12 +570,10 @@ static void inet_recvfrom_initialize(FAR struct socket *psock, FAR void *buf,
* semaphore.
*/
-#define inet_recvfrom_uninitialize(s) nxsem_destroy(&(s)->ir_sem)
-
-#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */
+#define tcp_recvfrom_uninitialize(s) nxsem_destroy(&(s)->ir_sem)
/****************************************************************************
- * Name: inet_recvfrom_result
+ * Name: tcp_recvfrom_result
*
* Description:
* Evaluate the result of the recv operations
@@ -958,8 +589,7 @@ static void inet_recvfrom_initialize(FAR struct socket *psock, FAR void *buf,
*
****************************************************************************/
-#if defined(NET_UDP_HAVE_STACK) || defined(NET_TCP_HAVE_STACK)
-static ssize_t inet_recvfrom_result(int result, struct inet_recvfrom_s *pstate)
+static ssize_t tcp_recvfrom_result(int result, struct tcp_recvfrom_s *pstate)
{
/* Check for a error/timeout detected by the event handler. Errors are
* signaled by negative errno values for the rcv length
@@ -985,131 +615,13 @@ static ssize_t inet_recvfrom_result(int result, struct inet_recvfrom_s *pstate)
return pstate->ir_recvlen;
}
-#endif /* NET_UDP_HAVE_STACK || NET_TCP_HAVE_STACK */
/****************************************************************************
- * Name: inet_udp_recvfrom
- *
- * Description:
- * Perform the recvfrom operation for a UDP SOCK_DGRAM
- *
- * Input Parameters:
- * psock Pointer to the socket structure for the SOCK_DRAM socket
- * buf Buffer to receive data
- * len Length of buffer
- * from INET address of source (may be NULL)
- *
- * Returned Value:
- * On success, returns the number of characters received. On error,
- * -errno is returned (see recvfrom for list of errnos).
- *
- * Assumptions:
- *
+ * Public Functions
****************************************************************************/
-#ifdef NET_UDP_HAVE_STACK
-static ssize_t inet_udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
- FAR struct sockaddr *from, FAR socklen_t *fromlen)
-{
- FAR struct udp_conn_s *conn = (FAR struct udp_conn_s *)psock->s_conn;
- FAR struct net_driver_s *dev;
- struct inet_recvfrom_s state;
- int ret;
-
- /* Perform the UDP recvfrom() operation */
-
- /* Initialize the state structure. This is done with the network locked
- * because we don't want anything to happen until we are ready.
- */
-
- net_lock();
- inet_recvfrom_initialize(psock, buf, len, from, fromlen, &state);
-
- /* Copy the read-ahead data from the packet */
-
- inet_udp_readahead(&state);
-
- /* The default return value is the number of bytes that we just copied
- * into the user buffer. We will return this if the socket has become
- * disconnected or if the user request was completely satisfied with
- * data from the readahead buffers.
- */
-
- ret = state.ir_recvlen;
-
- /* Handle non-blocking UDP sockets */
-
- if (_SS_ISNONBLOCK(psock->s_flags))
- {
- /* Return the number of bytes read from the read-ahead buffer if
- * something was received (already in 'ret'); EAGAIN if not.
- */
-
- if (ret < 0)
- {
- /* Nothing was received */
-
- ret = -EAGAIN;
- }
- }
-
- /* It is okay to block if we need to. If there is space to receive anything
- * more, then we will wait to receive the data. Otherwise return the number
- * of bytes read from the read-ahead buffer (already in 'ret').
- *
- * NOTE: that inet_udp_readahead() may set state.ir_recvlen == -1.
- */
-
- else if (state.ir_recvlen <= 0)
- {
- /* Get the device that will handle the packet transfers. This may be
- * NULL if the UDP socket is bound to INADDR_ANY. In that case, no
- * NETDEV_DOWN notifications will be received.
- */
-
- dev = udp_find_laddr_device(conn);
-
- /* Set up the callback in the connection */
-
- state.ir_cb = udp_callback_alloc(dev, conn);
- if (state.ir_cb)
- {
- /* Set up the callback in the connection */
-
- state.ir_cb->flags = (UDP_NEWDATA | NETDEV_DOWN);
- state.ir_cb->priv = (FAR void *)&state;
- state.ir_cb->event = inet_udp_eventhandler;
-
- /* Wait for either the receive to complete or for an error/timeout
- * to occur. net_timedwait will also terminate if a signal is
- * received.
- */
-
- ret = net_timedwait(&state. ir_sem, _SO_TIMEOUT(psock->s_rcvtimeo));
- if (ret == -ETIMEDOUT)
- {
- ret = -EAGAIN;
- }
-
- /* Make sure that no further events are processed */
-
- udp_callback_free(dev, conn, state.ir_cb);
- ret = inet_recvfrom_result(ret, &state);
- }
- else
- {
- ret = -EBUSY;
- }
- }
-
- net_unlock();
- inet_recvfrom_uninitialize(&state);
- return ret;
-}
-#endif /* NET_UDP_HAVE_STACK */
-
/****************************************************************************
- * Name: inet_tcp_recvfrom
+ * Name: psock_tcp_recvfrom
*
* Description:
* Perform the recvfrom operation for a TCP/IP SOCK_STREAM
@@ -1128,11 +640,11 @@ static ssize_t inet_udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t
*
****************************************************************************/
-#ifdef NET_TCP_HAVE_STACK
-static ssize_t inet_tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
- FAR struct sockaddr *from, FAR socklen_t *fromlen)
+ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR void *buf,
+ size_t len, FAR struct sockaddr *from,
+ FAR socklen_t *fromlen)
{
- struct inet_recvfrom_s state;
+ struct tcp_recvfrom_s state;
int ret;
/* Initialize the state structure. This is done with the network locked
@@ -1140,14 +652,14 @@ static ssize_t inet_tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t
*/
net_lock();
- inet_recvfrom_initialize(psock, buf, len, from, fromlen, &state);
+ tcp_recvfrom_initialize(psock, buf, len, from, fromlen, &state);
/* Handle any any TCP data already buffered in a read-ahead buffer. NOTE
* that there may be read-ahead data to be retrieved even after the
* socket has been disconnected.
*/
- inet_tcp_readahead(&state);
+ tcp_readahead(&state);
/* The default return value is the number of bytes that we just copied
* into the user buffer. We will return this if the socket has become
@@ -1232,7 +744,7 @@ static ssize_t inet_tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t
{
state.ir_cb->flags = (TCP_NEWDATA | TCP_DISCONN_EVENTS);
state.ir_cb->priv = (FAR void *)&state;
- state.ir_cb->event = inet_tcp_eventhandler;
+ state.ir_cb->event = tcp_eventhandler;
/* Wait for either the receive to complete or for an error/timeout
* to occur. net_timedwait will also terminate if a signal isi
@@ -1248,7 +760,7 @@ static ssize_t inet_tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t
/* Make sure that no further events are processed */
tcp_callback_free(conn, state.ir_cb);
- ret = inet_recvfrom_result(ret, &state);
+ ret = tcp_recvfrom_result(ret, &state);
}
else
{
@@ -1257,130 +769,8 @@ static ssize_t inet_tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t
}
net_unlock();
- inet_recvfrom_uninitialize(&state);
+ tcp_recvfrom_uninitialize(&state);
return (ssize_t)ret;
}
-#endif /* NET_TCP_HAVE_STACK */
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: inet_recvfrom
- *
- * Description:
- * Implements the socket recvfrom interface for the case of the AF_INET
- * and AF_INET6 address families. inet_recvfrom() receives messages from
- * a socket, and may be used to receive data on a socket whether or not it
- * is connection-oriented.
- *
- * If 'from' is not NULL, and the underlying protocol provides the source
- * address, this source address is filled in. The argument 'fromlen' is
- * initialized to the size of the buffer associated with from, and
- * modified on return to indicate the actual size of the address stored
- * there.
- *
- * Input Parameters:
- * psock A pointer to a NuttX-specific, internal socket structure
- * buf Buffer to receive data
- * len Length of buffer
- * flags Receive flags
- * from Address of source (may be NULL)
- * fromlen The length of the address structure
- *
- * Returned Value:
- * On success, returns the number of characters received. If no data is
- * available to be received and the peer has performed an orderly shutdown,
- * recv() will return 0. Otherwise, on errors, a negated errno value is
- * returned (see recvfrom() for the list of appropriate error values).
- *
- ****************************************************************************/
-
-ssize_t inet_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
- int flags, FAR struct sockaddr *from,
- FAR socklen_t *fromlen)
-{
- ssize_t ret;
-
- /* If a 'from' address has been provided, verify that it is large
- * enough to hold this address family.
- */
-
- if (from)
- {
- socklen_t minlen;
-
- /* Get the minimum socket length */
-
- switch (psock->s_domain)
- {
-#ifdef CONFIG_NET_IPv4
- case PF_INET:
- {
- minlen = sizeof(struct sockaddr_in);
- }
- break;
-#endif
-#ifdef CONFIG_NET_IPv6
- case PF_INET6:
- {
- minlen = sizeof(struct sockaddr_in6);
- }
- break;
-#endif
-
- default:
- DEBUGPANIC();
- return -EINVAL;
- }
-
- if (*fromlen < minlen)
- {
- return -EINVAL;
- }
- }
-
- /* Read from the network interface driver buffer.
- * Or perform the TCP/IP or UDP recv() operation.
- */
-
- switch (psock->s_type)
- {
-#ifdef CONFIG_NET_TCP
- case SOCK_STREAM:
- {
-#ifdef NET_TCP_HAVE_STACK
- ret = inet_tcp_recvfrom(psock, buf, len, from, fromlen);
-#else
- ret = -ENOSYS;
-#endif
- }
- break;
#endif /* CONFIG_NET_TCP */
-
-#ifdef CONFIG_NET_UDP
- case SOCK_DGRAM:
- {
-#ifdef NET_UDP_HAVE_STACK
- ret = inet_udp_recvfrom(psock, buf, len, from, fromlen);
-#else
- ret = -ENOSYS;
-#endif
- }
- break;
-#endif /* CONFIG_NET_UDP */
-
- default:
- {
- nerr("ERROR: Unsupported socket type: %d\n", psock->s_type);
- ret = -ENOSYS;
- }
- break;
- }
-
- return ret;
-}
-
-#endif /* CONFIG_NET */
diff --git a/net/udp/Make.defs b/net/udp/Make.defs
index 1c9487a..39ca293 100644
--- a/net/udp/Make.defs
+++ b/net/udp/Make.defs
@@ -40,6 +40,8 @@ ifneq ($(CONFIG_NET_UDP_NO_STACK),y)
# Socket layer
+SOCK_CSRCS += udp_recvfrom.c
+
ifeq ($(CONFIG_NET_UDPPROTO_OPTIONS),y)
SOCK_CSRCS += udp_setsockopt.c
endif
diff --git a/net/udp/udp.h b/net/udp/udp.h
index 40d3a97..454b29f 100644
--- a/net/udp/udp.h
+++ b/net/udp/udp.h
@@ -638,6 +638,30 @@ uint16_t udp_callback(FAR struct net_driver_s *dev,
FAR struct udp_conn_s *conn, uint16_t flags);
/****************************************************************************
+ * Name: psock_udp_recvfrom
+ *
+ * Description:
+ * Perform the recvfrom operation for a UDP SOCK_DGRAM
+ *
+ * Input Parameters:
+ * psock Pointer to the socket structure for the SOCK_DRAM socket
+ * buf Buffer to receive data
+ * len Length of buffer
+ * from INET address of source (may be NULL)
+ *
+ * Returned Value:
+ * On success, returns the number of characters received. On error,
+ * -errno is returned (see recvfrom for list of errnos).
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR void *buf,
+ size_t len, FAR struct sockaddr *from,
+ FAR socklen_t *fromlen);
+
+/****************************************************************************
* Name: psock_udp_sendto
*
* Description:
diff --git a/net/udp/udp_recvfrom.c b/net/udp/udp_recvfrom.c
new file mode 100644
index 0000000..3060162
--- /dev/null
+++ b/net/udp/udp_recvfrom.c
@@ -0,0 +1,707 @@
+/****************************************************************************
+ * net/udp/udp_recvfrom.c
+ *
+ * Copyright (C) 2020 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#if defined(CONFIG_NET) && defined(CONFIG_NET_UDP)
+
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+#include <assert.h>
+
+#include <nuttx/net/net.h>
+#include <nuttx/mm/iob.h>
+#include <nuttx/net/netdev.h>
+#include <nuttx/net/ip.h>
+#include <nuttx/net/udp.h>
+
+#include "netdev/netdev.h"
+#include "devif/devif.h"
+#include "udp/udp.h"
+#include "socket/socket.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define IPv4BUF ((struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
+#define IPv6BUF ((struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
+
+#define UDPIPv4BUF ((struct udp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv4_HDRLEN])
+#define UDPIPv6BUF ((struct udp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN])
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct udp_recvfrom_s
+{
+ FAR struct socket *ir_sock; /* The parent socket structure */
+ FAR struct devif_callback_s *ir_cb; /* Reference to callback instance */
+ sem_t ir_sem; /* Semaphore signals recv completion */
+ size_t ir_buflen; /* Length of receive buffer */
+ uint8_t *ir_buffer; /* Pointer to receive buffer */
+ FAR struct sockaddr *ir_from; /* Address of sender */
+ FAR socklen_t *ir_fromlen; /* Number of bytes allocated for address of sender */
+ ssize_t ir_recvlen; /* The received length */
+ int ir_result; /* Success:OK, failure:negated errno */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: udp_update_recvlen
+ *
+ * Description:
+ * Update information about space available for new data and update size
+ * of data in buffer, This logic accounts for the case where
+ * udp_readahead() sets state.ir_recvlen == -1 .
+ *
+ * Input Parameters:
+ * pstate recvfrom state structure
+ * recvlen size of new data appended to buffer
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static inline void udp_update_recvlen(FAR struct udp_recvfrom_s *pstate,
+ size_t recvlen)
+{
+ if (pstate->ir_recvlen < 0)
+ {
+ pstate->ir_recvlen = 0;
+ }
+
+ pstate->ir_recvlen += recvlen;
+ pstate->ir_buffer += recvlen;
+ pstate->ir_buflen -= recvlen;
+}
+
+/****************************************************************************
+ * Name: udp_recvfrom_newdata
+ *
+ * Description:
+ * Copy the read data from the packet
+ *
+ * Input Parameters:
+ * dev The structure of the network driver that generated the event.
+ * pstate recvfrom state structure
+ *
+ * Returned Value:
+ * The number of bytes taken from the packet.
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static size_t udp_recvfrom_newdata(FAR struct net_driver_s *dev,
+ FAR struct udp_recvfrom_s *pstate)
+{
+ size_t recvlen;
+
+ /* Get the length of the data to return */
+
+ if (dev->d_len > pstate->ir_buflen)
+ {
+ recvlen = pstate->ir_buflen;
+ }
+ else
+ {
+ recvlen = dev->d_len;
+ }
+
+ /* Copy the new appdata into the user buffer */
+
+ memcpy(pstate->ir_buffer, dev->d_appdata, recvlen);
+ ninfo("Received %d bytes (of %d)\n", (int)recvlen, (int)dev->d_len);
+
+ /* Update the accumulated size of the data read */
+
+ udp_update_recvlen(pstate, recvlen);
+
+ return recvlen;
+}
+
+/****************************************************************************
+ * Name: udp_newdata
+ *
+ * Description:
+ * Copy the read data from the packet
+ *
+ * Input Parameters:
+ * dev The sructure of the network driver that generated the event
+ * pstate recvfrom state structure
+ *
+ * Returned Value:
+ * None.
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static inline void udp_newdata(FAR struct net_driver_s *dev,
+ FAR struct udp_recvfrom_s *pstate)
+{
+ /* Take as much data from the packet as we can */
+
+ udp_recvfrom_newdata(dev, pstate);
+
+ /* Indicate no data in the buffer */
+
+ dev->d_len = 0;
+}
+
+static inline void udp_readahead(struct udp_recvfrom_s *pstate)
+{
+ FAR struct udp_conn_s *conn = (FAR struct udp_conn_s *)pstate->ir_sock->s_conn;
+ FAR struct iob_s *iob;
+ int recvlen;
+
+ /* Check there is any UDP datagram already buffered in a read-ahead
+ * buffer.
+ */
+
+ pstate->ir_recvlen = -1;
+
+ if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
+ {
+ FAR struct iob_s *tmp;
+ uint8_t src_addr_size;
+
+ DEBUGASSERT(iob->io_pktlen > 0);
+
+ /* Transfer that buffered data from the I/O buffer chain into
+ * the user buffer.
+ */
+
+ recvlen = iob_copyout(&src_addr_size, iob, sizeof(uint8_t), 0);
+ if (recvlen != sizeof(uint8_t))
+ {
+ goto out;
+ }
+
+ if (0
+#ifdef CONFIG_NET_IPv6
+ || src_addr_size == sizeof(struct sockaddr_in6)
+#endif
+#ifdef CONFIG_NET_IPv4
+ || src_addr_size == sizeof(struct sockaddr_in)
+#endif
+ )
+ {
+ if (pstate->ir_from)
+ {
+ socklen_t len = *pstate->ir_fromlen;
+ len = (socklen_t)src_addr_size > len ? len : (socklen_t)src_addr_size;
+
+ recvlen = iob_copyout((FAR uint8_t *)pstate->ir_from, iob,
+ len, sizeof(uint8_t));
+ if (recvlen != len)
+ {
+ goto out;
+ }
+ }
+ }
+
+ if (pstate->ir_buflen > 0)
+ {
+ recvlen = iob_copyout(pstate->ir_buffer, iob, pstate->ir_buflen,
+ src_addr_size + sizeof(uint8_t));
+
+ ninfo("Received %d bytes (of %d)\n", recvlen, iob->io_pktlen);
+
+ /* Update the accumulated size of the data read */
+
+ pstate->ir_recvlen = recvlen;
+ pstate->ir_buffer += recvlen;
+ pstate->ir_buflen -= recvlen;
+ }
+ else
+ {
+ pstate->ir_recvlen = 0;
+ }
+
+out:
+ /* Remove the I/O buffer chain from the head of the read-ahead
+ * buffer queue.
+ */
+
+ tmp = iob_remove_queue(&conn->readahead);
+ DEBUGASSERT(tmp == iob);
+ UNUSED(tmp);
+
+ /* And free the I/O buffer chain */
+
+ iob_free_chain(iob, IOBUSER_NET_UDP_READAHEAD);
+ }
+}
+
+/****************************************************************************
+ * Name: udp_sender
+ *
+ * Description:
+ * Getting the sender's address from the UDP packet
+ *
+ * Input Parameters:
+ * dev - The device driver data structure
+ * pstate - the recvfrom state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static inline void udp_sender(FAR struct net_driver_s *dev,
+ FAR struct udp_recvfrom_s *pstate)
+{
+ /* Get the family from the packet type, IP address from the IP header, and
+ * the port number from the UDP header.
+ */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+ if (IFF_IS_IPv6(dev->d_flags))
+#endif
+ {
+ FAR struct sockaddr_in6 *infrom =
+ (FAR struct sockaddr_in6 *)pstate->ir_from;
+ FAR socklen_t *fromlen = pstate->ir_fromlen;
+
+ if (infrom)
+ {
+ FAR struct udp_hdr_s *udp = UDPIPv6BUF;
+ FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
+
+ infrom->sin6_family = AF_INET6;
+ infrom->sin6_port = udp->srcport;
+ *fromlen = sizeof(struct sockaddr_in6);
+
+ net_ipv6addr_copy(infrom->sin6_addr.s6_addr, ipv6->srcipaddr);
+ }
+ }
+#endif /* CONFIG_NET_IPv6 */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+ else
+#endif
+ {
+ FAR struct sockaddr_in *infrom =
+ (FAR struct sockaddr_in *)pstate->ir_from;
+
+ if (infrom)
+ {
+#ifdef CONFIG_NET_IPv6
+ FAR struct udp_conn_s *conn =
+ (FAR struct udp_conn_s *)pstate->ir_sock->s_conn;
+
+ /* Hybrid dual-stack IPv6/IPv4 implementations recognize a special
+ * class of addresses, the IPv4-mapped IPv6 addresses.
+ */
+
+ if (conn->domain == PF_INET6)
+ {
+ FAR struct sockaddr_in6 *infrom6 = (FAR struct sockaddr_in6 *)infrom;
+ FAR socklen_t *fromlen = pstate->ir_fromlen;
+ FAR struct udp_hdr_s *udp = UDPIPv6BUF;
+ FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
+ in_addr_t ipv4addr;
+
+ /* Encode the IPv4 address as an IPv4-mapped IPv6 address */
+
+ infrom6->sin6_family = AF_INET6;
+ infrom6->sin6_port = udp->srcport;
+ *fromlen = sizeof(struct sockaddr_in6);
+
+ ipv4addr = net_ip4addr_conv32(ipv6->srcipaddr);
+ ip6_map_ipv4addr(ipv4addr, infrom6->sin6_addr.s6_addr16);
+ }
+ else
+#endif
+ {
+ FAR struct udp_hdr_s *udp = UDPIPv4BUF;
+ FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
+
+ infrom->sin_family = AF_INET;
+ infrom->sin_port = udp->srcport;
+
+ net_ipv4addr_copy(infrom->sin_addr.s_addr,
+ net_ip4addr_conv32(ipv4->srcipaddr));
+ }
+ }
+ }
+#endif /* CONFIG_NET_IPv4 */
+}
+
+/****************************************************************************
+ * Name: udp_terminate
+ *
+ * Description:
+ * Terminate the UDP transfer.
+ *
+ * Input Parameters:
+ * pstate - The recvfrom state structure
+ * result - The result of the operation
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void udp_terminate(FAR struct udp_recvfrom_s *pstate, int result)
+{
+ /* Don't allow any further UDP call backs. */
+
+ pstate->ir_cb->flags = 0;
+ pstate->ir_cb->priv = NULL;
+ pstate->ir_cb->event = NULL;
+
+ /* Save the result of the transfer */
+
+ pstate->ir_result = result;
+
+ /* Wake up the waiting thread, returning the number of bytes
+ * actually read.
+ */
+
+ nxsem_post(&pstate->ir_sem);
+}
+
+/****************************************************************************
+ * Name: udp_eventhandler
+ *
+ * Description:
+ * This function is called with the network locked to perform the actual
+ * UDP receive operation via by the lower, device interfacing layer.
+ *
+ * Input Parameters:
+ * dev The structure of the network driver that generated the event.
+ * pvconn The connection structure associated with the socket
+ * flags Set of events describing why the callback was invoked
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static uint16_t udp_eventhandler(FAR struct net_driver_s *dev,
+ FAR void *pvconn, FAR void *pvpriv,
+ uint16_t flags)
+{
+ FAR struct udp_recvfrom_s *pstate = (FAR struct udp_recvfrom_s *)pvpriv;
+
+ ninfo("flags: %04x\n", flags);
+
+ /* 'priv' might be null in some race conditions (?) */
+
+ if (pstate)
+ {
+ /* If the network device has gone down, then we will have terminate
+ * the wait now with an error.
+ */
+
+ if ((flags & NETDEV_DOWN) != 0)
+ {
+ /* Terminate the transfer with an error. */
+
+ nerr("ERROR: Network is down\n");
+ udp_terminate(pstate, -ENETUNREACH);
+ }
+
+ /* If new data is available, then complete the read action. */
+
+ else if ((flags & UDP_NEWDATA) != 0)
+ {
+ /* Copy the data from the packet */
+
+ udp_newdata(dev, pstate);
+
+ /* We are finished. */
+
+ ninfo("UDP done\n");
+
+ /* Save the sender's address in the caller's 'from' location */
+
+ udp_sender(dev, pstate);
+
+ /* Don't allow any further UDP call backs. */
+
+ udp_terminate(pstate, OK);
+
+ /* Indicate that the data has been consumed */
+
+ flags &= ~UDP_NEWDATA;
+ }
+ }
+
+ return flags;
+}
+
+/****************************************************************************
+ * Name: udp_recvfrom_initialize
+ *
+ * Description:
+ * Initialize the state structure
+ *
+ * Input Parameters:
+ * psock Pointer to the socket structure for the socket
+ * buf Buffer to receive data
+ * len Length of buffer
+ * pstate A pointer to the state structure to be initialized
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void udp_recvfrom_initialize(FAR struct socket *psock, FAR void *buf,
+ size_t len, FAR struct sockaddr *infrom,
+ FAR socklen_t *fromlen,
+ FAR struct udp_recvfrom_s *pstate)
+{
+ /* Initialize the state structure. */
+
+ memset(pstate, 0, sizeof(struct udp_recvfrom_s));
+
+ /* This semaphore is used for signaling and, hence, should not have
+ * priority inheritance enabled.
+ */
+
+ nxsem_init(&pstate->ir_sem, 0, 0); /* Doesn't really fail */
+ nxsem_setprotocol(&pstate->ir_sem, SEM_PRIO_NONE);
+
+ pstate->ir_buflen = len;
+ pstate->ir_buffer = buf;
+ pstate->ir_from = infrom;
+ pstate->ir_fromlen = fromlen;
+
+ /* Set up the start time for the timeout */
+
+ pstate->ir_sock = psock;
+}
+
+/* The only un-initialization that has to be performed is destroying the
+ * semaphore.
+ */
+
+#define udp_recvfrom_uninitialize(s) nxsem_destroy(&(s)->ir_sem)
+
+/****************************************************************************
+ * Name: udp_recvfrom_result
+ *
+ * Description:
+ * Evaluate the result of the recv operations
+ *
+ * Input Parameters:
+ * result The result of the net_timedwait operation (may indicate EINTR)
+ * pstate A pointer to the state structure to be initialized
+ *
+ * Returned Value:
+ * The result of the recv operation with errno set appropriately
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static ssize_t udp_recvfrom_result(int result, struct udp_recvfrom_s *pstate)
+{
+ /* Check for a error/timeout detected by the event handler. Errors are
+ * signaled by negative errno values for the rcv length
+ */
+
+ if (pstate->ir_result < 0)
+ {
+ /* This might return EAGAIN on a timeout or ENOTCONN on loss of
+ * connection (TCP only)
+ */
+
+ return pstate->ir_result;
+ }
+
+ /* If net_timedwait failed, then we were probably reawakened by a signal. In
+ * this case, net_timedwait will have returned negated errno appropriately.
+ */
+
+ if (result < 0)
+ {
+ return result;
+ }
+
+ return pstate->ir_recvlen;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: psock_udp_recvfrom
+ *
+ * Description:
+ * Perform the recvfrom operation for a UDP SOCK_DGRAM
+ *
+ * Input Parameters:
+ * psock Pointer to the socket structure for the SOCK_DRAM socket
+ * buf Buffer to receive data
+ * len Length of buffer
+ * from INET address of source (may be NULL)
+ *
+ * Returned Value:
+ * On success, returns the number of characters received. On error,
+ * -errno is returned (see recvfrom for list of errnos).
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR void *buf,
+ size_t len, FAR struct sockaddr *from,
+ FAR socklen_t *fromlen)
+{
+ FAR struct udp_conn_s *conn = (FAR struct udp_conn_s *)psock->s_conn;
+ FAR struct net_driver_s *dev;
+ struct udp_recvfrom_s state;
+ int ret;
+
+ /* Perform the UDP recvfrom() operation */
+
+ /* Initialize the state structure. This is done with the network locked
+ * because we don't want anything to happen until we are ready.
+ */
+
+ net_lock();
+ udp_recvfrom_initialize(psock, buf, len, from, fromlen, &state);
+
+ /* Copy the read-ahead data from the packet */
+
+ udp_readahead(&state);
+
+ /* The default return value is the number of bytes that we just copied
+ * into the user buffer. We will return this if the socket has become
+ * disconnected or if the user request was completely satisfied with
+ * data from the readahead buffers.
+ */
+
+ ret = state.ir_recvlen;
+
+ /* Handle non-blocking UDP sockets */
+
+ if (_SS_ISNONBLOCK(psock->s_flags))
+ {
+ /* Return the number of bytes read from the read-ahead buffer if
+ * something was received (already in 'ret'); EAGAIN if not.
+ */
+
+ if (ret < 0)
+ {
+ /* Nothing was received */
+
+ ret = -EAGAIN;
+ }
+ }
+
+ /* It is okay to block if we need to. If there is space to receive anything
+ * more, then we will wait to receive the data. Otherwise return the number
+ * of bytes read from the read-ahead buffer (already in 'ret').
+ *
+ * NOTE: that udp_readahead() may set state.ir_recvlen == -1.
+ */
+
+ else if (state.ir_recvlen <= 0)
+ {
+ /* Get the device that will handle the packet transfers. This may be
+ * NULL if the UDP socket is bound to INADDR_ANY. In that case, no
+ * NETDEV_DOWN notifications will be received.
+ */
+
+ dev = udp_find_laddr_device(conn);
+
+ /* Set up the callback in the connection */
+
+ state.ir_cb = udp_callback_alloc(dev, conn);
+ if (state.ir_cb)
+ {
+ /* Set up the callback in the connection */
+
+ state.ir_cb->flags = (UDP_NEWDATA | NETDEV_DOWN);
+ state.ir_cb->priv = (FAR void *)&state;
+ state.ir_cb->event = udp_eventhandler;
+
+ /* Wait for either the receive to complete or for an error/timeout
+ * to occur. net_timedwait will also terminate if a signal is
+ * received.
+ */
+
+ ret = net_timedwait(&state. ir_sem, _SO_TIMEOUT(psock->s_rcvtimeo));
+ if (ret == -ETIMEDOUT)
+ {
+ ret = -EAGAIN;
+ }
+
+ /* Make sure that no further events are processed */
+
+ udp_callback_free(dev, conn, state.ir_cb);
+ ret = udp_recvfrom_result(ret, &state);
+ }
+ else
+ {
+ ret = -EBUSY;
+ }
+ }
+
+ net_unlock();
+ udp_recvfrom_uninitialize(&state);
+ return ret;
+}
+
+#endif /* CONFIG_NET && CONFIG_NET_UDP */