You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/09/07 02:49:53 UTC
[incubator-nuttx] branch master updated: udp: add IPVx_PKTINFO related support
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 9bff29d7e7 udp: add IPVx_PKTINFO related support
9bff29d7e7 is described below
commit 9bff29d7e7af930edf8771d4f3a5c7c579dd39c6
Author: zhanghongyu <zh...@xiaomi.com>
AuthorDate: Wed Aug 24 14:55:56 2022 +0800
udp: add IPVx_PKTINFO related support
Signed-off-by: zhanghongyu <zh...@xiaomi.com>
---
include/netinet/in.h | 2 +
net/inet/inet_sockif.c | 12 +-
net/inet/ipv4_setsockopt.c | 28 +++++
net/inet/ipv6_setsockopt.c | 30 +++++
net/tcp/tcp.h | 10 +-
net/tcp/tcp_recvfrom.c | 14 +--
net/udp/udp.h | 11 +-
net/udp/udp_callback.c | 25 ++++-
net/udp/udp_recvfrom.c | 268 ++++++++++++++++++++++++++++-----------------
9 files changed, 269 insertions(+), 131 deletions(-)
diff --git a/include/netinet/in.h b/include/netinet/in.h
index 59af8f807d..f3531031b2 100644
--- a/include/netinet/in.h
+++ b/include/netinet/in.h
@@ -127,6 +127,8 @@
* to IPv6 communications only */
#define IPV6_PKTINFO (__SO_PROTOCOL + 8) /* Get some information about
* the incoming packet */
+#define IPV6_RECVPKTINFO (__SO_PROTOCOL + 9) /* It functions just same as
+ * IPV6_PKTINFO for now */
/* Values used with SIOCSIFMCFILTER and SIOCGIFMCFILTER ioctl's */
diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c
index d63cd40873..3823cf488e 100644
--- a/net/inet/inet_sockif.c
+++ b/net/inet/inet_sockif.c
@@ -1569,17 +1569,13 @@ static ssize_t inet_sendfile(FAR struct socket *psock,
static ssize_t inet_recvmsg(FAR struct socket *psock,
FAR struct msghdr *msg, int flags)
{
- FAR void *buf = msg->msg_iov->iov_base;
- size_t len = msg->msg_iov->iov_len;
- FAR struct sockaddr *from = msg->msg_name;
- FAR socklen_t *fromlen = &msg->msg_namelen;
ssize_t ret;
/* If a 'from' address has been provided, verify that it is large
* enough to hold this address family.
*/
- if (from)
+ if (msg->msg_name)
{
socklen_t minlen;
@@ -1608,7 +1604,7 @@ static ssize_t inet_recvmsg(FAR struct socket *psock,
return -EINVAL;
}
- if (*fromlen < minlen)
+ if (msg->msg_namelen < minlen)
{
return -EINVAL;
}
@@ -1624,7 +1620,7 @@ static ssize_t inet_recvmsg(FAR struct socket *psock,
case SOCK_STREAM:
{
#ifdef NET_TCP_HAVE_STACK
- ret = psock_tcp_recvfrom(psock, buf, len, flags, from, fromlen);
+ ret = psock_tcp_recvfrom(psock, msg, flags);
#else
ret = -ENOSYS;
#endif
@@ -1636,7 +1632,7 @@ static ssize_t inet_recvmsg(FAR struct socket *psock,
case SOCK_DGRAM:
{
#ifdef NET_UDP_HAVE_STACK
- ret = psock_udp_recvfrom(psock, buf, len, flags, from, fromlen);
+ ret = psock_udp_recvfrom(psock, msg, flags);
#else
ret = -ENOSYS;
#endif
diff --git a/net/inet/ipv4_setsockopt.c b/net/inet/ipv4_setsockopt.c
index de2f21fd86..9a24727a4d 100644
--- a/net/inet/ipv4_setsockopt.c
+++ b/net/inet/ipv4_setsockopt.c
@@ -203,6 +203,34 @@ int ipv4_setsockopt(FAR struct socket *psock, int option,
}
break;
+ case IP_PKTINFO:
+ {
+ FAR struct udp_conn_s *conn;
+ int enable;
+
+ if (psock->s_type != SOCK_DGRAM ||
+ value == NULL || value_len == 0)
+ {
+ ret = -EINVAL;
+ break;
+ }
+
+ enable = (value_len >= sizeof(int)) ?
+ *(FAR int *)value : (int)*(FAR unsigned char *)value;
+ conn = (FAR struct udp_conn_s *)psock->s_conn;
+ if (enable)
+ {
+ conn->flags |= _UDP_FLAG_PKTINFO;
+ }
+ else
+ {
+ conn->flags &= ~_UDP_FLAG_PKTINFO;
+ }
+
+ ret = OK;
+ }
+ break;
+
/* The following IPv4 socket options are defined, but not implemented */
case IP_MULTICAST_IF: /* Set local device for a multicast
diff --git a/net/inet/ipv6_setsockopt.c b/net/inet/ipv6_setsockopt.c
index 11e0cd53ef..17bbdb695d 100644
--- a/net/inet/ipv6_setsockopt.c
+++ b/net/inet/ipv6_setsockopt.c
@@ -34,6 +34,7 @@
#include "mld/mld.h"
#include "inet/inet.h"
+#include "udp/udp.h"
#ifdef CONFIG_NET_IPv6
@@ -110,6 +111,35 @@ int ipv6_setsockopt(FAR struct socket *psock, int option,
}
break;
+ case IPV6_PKTINFO:
+ case IPV6_RECVPKTINFO:
+ {
+ FAR struct udp_conn_s *conn;
+ int enable;
+
+ if (psock->s_type != SOCK_DGRAM ||
+ value == NULL || value_len == 0)
+ {
+ ret = -EINVAL;
+ break;
+ }
+
+ enable = (value_len >= sizeof(int)) ?
+ *(FAR int *)value : (int)*(FAR unsigned char *)value;
+ conn = (FAR struct udp_conn_s *)psock->s_conn;
+ if (enable)
+ {
+ conn->flags |= _UDP_FLAG_PKTINFO;
+ }
+ else
+ {
+ conn->flags &= ~_UDP_FLAG_PKTINFO;
+ }
+
+ ret = OK;
+ }
+ break;
+
/* The following IPv6 socket options are defined, but not implemented */
case IPV6_MULTICAST_HOPS: /* Multicast hop limit */
diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h
index fec08800a9..8c3068768f 100644
--- a/net/tcp/tcp.h
+++ b/net/tcp/tcp.h
@@ -1378,11 +1378,8 @@ int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
*
* Input Parameters:
* psock Pointer to the socket structure for the SOCK_DRAM socket
- * buf Buffer to receive data
- * len Length of buffer
+ * msg Receive info and buffer for receive data
* flags Receive flags
- * from INET address of source (may be NULL)
- * fromlen The length of the address structure
*
* Returned Value:
* On success, returns the number of characters received. On error,
@@ -1392,9 +1389,8 @@ int psock_tcp_accept(FAR struct socket *psock, FAR struct sockaddr *addr,
*
****************************************************************************/
-ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR void *buf,
- size_t len, int flags, FAR struct sockaddr *from,
- FAR socklen_t *fromlen);
+ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR struct msghdr *msg,
+ int flags);
/****************************************************************************
* Name: psock_tcp_send
diff --git a/net/tcp/tcp_recvfrom.c b/net/tcp/tcp_recvfrom.c
index 24a2b5b081..a32a7fef71 100644
--- a/net/tcp/tcp_recvfrom.c
+++ b/net/tcp/tcp_recvfrom.c
@@ -594,11 +594,8 @@ static ssize_t tcp_recvfrom_result(int result, struct tcp_recvfrom_s *pstate)
*
* Input Parameters:
* psock Pointer to the socket structure for the SOCK_DRAM socket
- * buf Buffer to receive data
- * len Length of buffer
+ * msg Receive info and buffer for receive data
* flags Receive flags
- * from INET address of source (may be NULL)
- * fromlen The length of the address structure
*
* Returned Value:
* On success, returns the number of characters received. On error,
@@ -608,10 +605,13 @@ static ssize_t tcp_recvfrom_result(int result, struct tcp_recvfrom_s *pstate)
*
****************************************************************************/
-ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR void *buf,
- size_t len, int flags, FAR struct sockaddr *from,
- FAR socklen_t *fromlen)
+ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR struct msghdr *msg,
+ int flags)
{
+ FAR struct sockaddr *from = msg->msg_name;
+ FAR socklen_t *fromlen = &msg->msg_namelen;
+ FAR void *buf = msg->msg_iov->iov_base;
+ size_t len = msg->msg_iov->iov_len;
struct tcp_recvfrom_s state;
FAR struct tcp_conn_s *conn;
int ret;
diff --git a/net/udp/udp.h b/net/udp/udp.h
index a95ff706d7..cdee725683 100644
--- a/net/udp/udp.h
+++ b/net/udp/udp.h
@@ -69,6 +69,7 @@
/* Definitions for the UDP connection struct flag field */
#define _UDP_FLAG_CONNECTMODE (1 << 0) /* Bit 0: UDP connection-mode */
+#define _UDP_FLAG_PKTINFO (1 << 1) /* Bit 1: UDP PKTINFO */
#define _UDP_ISCONNECTMODE(f) (((f) & _UDP_FLAG_CONNECTMODE) != 0)
@@ -689,11 +690,8 @@ uint16_t udp_callback(FAR struct net_driver_s *dev,
*
* Input Parameters:
* psock Pointer to the socket structure for the SOCK_DRAM socket
- * buf Buffer to receive data
- * len Length of buffer
+ * msg Receive info and buffer for receive data
* flags Receive flags
- * from INET address of source (may be NULL)
- * fromlen The length of the address structure
*
* Returned Value:
* On success, returns the number of characters received. On error,
@@ -703,9 +701,8 @@ uint16_t udp_callback(FAR struct net_driver_s *dev,
*
****************************************************************************/
-ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR void *buf,
- size_t len, int flags, FAR struct sockaddr *from,
- FAR socklen_t *fromlen);
+ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR struct msghdr *msg,
+ int flags);
/****************************************************************************
* Name: psock_udp_sendto
diff --git a/net/udp/udp_callback.c b/net/udp/udp_callback.c
index 07210e3eac..2d5aec9774 100644
--- a/net/udp/udp_callback.c
+++ b/net/udp/udp_callback.c
@@ -82,6 +82,7 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev,
FAR void *src_addr;
uint8_t src_addr_size;
+ uint8_t offset = 0;
#if CONFIG_NET_RECV_BUFSIZE > 0
while (iob_get_queue_size(&conn->readahead) > conn->rcvbufs)
@@ -172,7 +173,8 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev,
*/
ret = iob_trycopyin(iob, (FAR const uint8_t *)&src_addr_size,
- sizeof(uint8_t), 0, true);
+ sizeof(uint8_t), offset, true);
+ offset += sizeof(uint8_t);
if (ret < 0)
{
/* On a failure, iob_trycopyin return a negated error value but does
@@ -185,7 +187,8 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev,
}
ret = iob_trycopyin(iob, (FAR const uint8_t *)src_addr, src_addr_size,
- sizeof(uint8_t), true);
+ offset, true);
+ offset += src_addr_size;
if (ret < 0)
{
/* On a failure, iob_trycopyin return a negated error value but does
@@ -197,12 +200,26 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev,
return 0;
}
+#ifdef CONFIG_NETDEV_IFINDEX
+ ret = iob_trycopyin(iob, &dev->d_ifindex, sizeof(uint8_t), offset, true);
+ offset += sizeof(uint8_t);
+ if (ret < 0)
+ {
+ /* On a failure, iob_trycopyin return a negated error value but does
+ * not free any I/O buffers.
+ */
+
+ nerr("ERROR: Failed to add dindex to the I/O buffer chain: %d\n", ret);
+ iob_free_chain(iob);
+ return 0;
+ }
+#endif
+
if (buflen > 0)
{
/* Copy the new appdata into the I/O buffer chain */
- ret = iob_trycopyin(iob, buffer, buflen,
- src_addr_size + sizeof(uint8_t), true);
+ ret = iob_trycopyin(iob, buffer, buflen, offset, true);
if (ret < 0)
{
/* On a failure, iob_trycopyin return a negated error value but
diff --git a/net/udp/udp_recvfrom.c b/net/udp/udp_recvfrom.c
index de56b32c65..c9a9098d7d 100644
--- a/net/udp/udp_recvfrom.c
+++ b/net/udp/udp_recvfrom.c
@@ -36,6 +36,7 @@
#include <nuttx/net/netdev.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/udp.h>
+#include <netinet/in.h>
#include "netdev/netdev.h"
#include "devif/devif.h"
@@ -60,11 +61,8 @@ struct udp_recvfrom_s
{
FAR struct udp_conn_s *ir_conn; /* Connection associated with the socket */
FAR struct devif_callback_s *ir_cb; /* Reference to callback instance */
+ FAR struct msghdr *ir_msg; /* Receive info and buffer */
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 */
};
@@ -99,8 +97,64 @@ static inline void udp_update_recvlen(FAR struct udp_recvfrom_s *pstate,
}
pstate->ir_recvlen += recvlen;
- pstate->ir_buffer += recvlen;
- pstate->ir_buflen -= recvlen;
+}
+
+static void udp_recvpktinfo(FAR struct udp_recvfrom_s *pstate,
+ FAR void *srcaddr, uint8_t ifindex)
+{
+ FAR struct msghdr *msg = pstate->ir_msg;
+ FAR struct udp_conn_s *conn = pstate->ir_conn;
+ FAR struct cmsghdr *control = msg->msg_control;
+ size_t cmsg_len = 0;
+
+ if (!(conn->flags & _UDP_FLAG_PKTINFO))
+ {
+ goto out;
+ }
+
+#ifdef CONFIG_NET_IPv4
+ if (conn->domain == PF_INET)
+ {
+ FAR struct sockaddr_in *infrom = srcaddr;
+ FAR struct in_pktinfo *pkt_info = CMSG_DATA(control);
+
+ if (msg->msg_controllen < CMSG_LEN(sizeof(struct in_pktinfo)))
+ {
+ goto out;
+ }
+
+ cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+ control->cmsg_level = IPPROTO_IP;
+ control->cmsg_type = IP_PKTINFO;
+ control->cmsg_len = cmsg_len;
+ pkt_info->ipi_ifindex = ifindex;
+ pkt_info->ipi_addr.s_addr = infrom->sin_addr.s_addr;
+ pkt_info->ipi_spec_dst.s_addr = conn->u.ipv4.laddr;
+ }
+#endif
+
+#ifdef CONFIG_NET_IPv6
+ if (conn->domain == PF_INET6)
+ {
+ FAR struct sockaddr_in6 *infrom = srcaddr;
+ FAR struct in6_pktinfo *pkt_info = CMSG_DATA(control);
+
+ if (msg->msg_controllen < CMSG_LEN(sizeof(struct in6_pktinfo)))
+ {
+ goto out;
+ }
+
+ cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ control->cmsg_level = IPPROTO_IPV6;
+ control->cmsg_type = IPV6_PKTINFO;
+ control->cmsg_len = cmsg_len;
+ pkt_info->ipi6_ifindex = ifindex;
+ net_ipv6addr_copy(&pkt_info->ipi6_addr, infrom->sin6_addr.s6_addr);
+ }
+#endif
+
+out:
+ msg->msg_controllen = cmsg_len;
}
/****************************************************************************
@@ -128,9 +182,9 @@ static size_t udp_recvfrom_newdata(FAR struct net_driver_s *dev,
/* Get the length of the data to return */
- if (dev->d_len > pstate->ir_buflen)
+ if (dev->d_len > pstate->ir_msg->msg_iov->iov_len)
{
- recvlen = pstate->ir_buflen;
+ recvlen = pstate->ir_msg->msg_iov->iov_len;
}
else
{
@@ -139,7 +193,7 @@ static size_t udp_recvfrom_newdata(FAR struct net_driver_s *dev,
/* Copy the new appdata into the user buffer */
- memcpy(pstate->ir_buffer, dev->d_appdata, recvlen);
+ memcpy(pstate->ir_msg->msg_iov->iov_base, 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 */
@@ -194,7 +248,14 @@ static inline void udp_readahead(struct udp_recvfrom_s *pstate)
if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
{
FAR struct iob_s *tmp;
+#ifdef CONFIG_NET_IPv6
+ uint8_t srcaddr[sizeof(struct sockaddr_in6)];
+#else
+ uint8_t srcaddr[sizeof(struct sockaddr_in)];
+#endif
uint8_t src_addr_size;
+ uint8_t offset = 0;
+ uint8_t ifindex = 0;
DEBUGASSERT(iob->io_pktlen > 0);
@@ -202,11 +263,28 @@ static inline void udp_readahead(struct udp_recvfrom_s *pstate)
* the user buffer.
*/
- recvlen = iob_copyout(&src_addr_size, iob, sizeof(uint8_t), 0);
+ recvlen = iob_copyout(&src_addr_size, iob, sizeof(uint8_t), offset);
+ offset += sizeof(uint8_t);
+ if (recvlen != sizeof(uint8_t))
+ {
+ goto out;
+ }
+
+ recvlen = iob_copyout(srcaddr, iob, src_addr_size, offset);
+ offset += src_addr_size;
+ if (recvlen != src_addr_size)
+ {
+ goto out;
+ }
+
+#ifdef CONFIG_NETDEV_IFINDEX
+ recvlen = iob_copyout(&ifindex, iob, sizeof(uint8_t), offset);
+ offset += sizeof(uint8_t);
if (recvlen != sizeof(uint8_t))
{
goto out;
}
+#endif
if (0
#ifdef CONFIG_NET_IPv6
@@ -217,40 +295,36 @@ static inline void udp_readahead(struct udp_recvfrom_s *pstate)
#endif
)
{
- if (pstate->ir_from)
+ if (pstate->ir_msg->msg_name)
{
- 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;
- }
+ pstate->ir_msg->msg_namelen =
+ src_addr_size > pstate->ir_msg->msg_namelen ?
+ pstate->ir_msg->msg_namelen : src_addr_size;
+
+ memcpy(pstate->ir_msg->msg_name, srcaddr,
+ pstate->ir_msg->msg_namelen);
}
}
- if (pstate->ir_buflen > 0)
+ if (pstate->ir_msg->msg_iov->iov_len > 0)
{
- recvlen = iob_copyout(pstate->ir_buffer, iob, pstate->ir_buflen,
- src_addr_size + sizeof(uint8_t));
+ recvlen = iob_copyout(pstate->ir_msg->msg_iov->iov_base,
+ iob, pstate->ir_msg->msg_iov->iov_len,
+ offset);
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;
- *pstate->ir_fromlen = src_addr_size;
+ pstate->ir_recvlen = recvlen;
}
else
{
pstate->ir_recvlen = 0;
}
+ udp_recvpktinfo(pstate, srcaddr, ifindex);
+
out:
/* Remove the I/O buffer chain from the head of the read-ahead
* buffer queue.
@@ -287,6 +361,13 @@ out:
static inline void udp_sender(FAR struct net_driver_s *dev,
FAR struct udp_recvfrom_s *pstate)
{
+#ifdef CONFIG_NET_IPv6
+ uint8_t srcaddr[sizeof(struct sockaddr_in6)];
+#else
+ uint8_t srcaddr[sizeof(struct sockaddr_in)];
+#endif
+ socklen_t fromlen = 0;
+
/* Get the family from the packet type, IP address from the IP header, and
* the port number from the UDP header.
*/
@@ -296,21 +377,15 @@ static inline void udp_sender(FAR struct net_driver_s *dev,
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;
+ FAR struct sockaddr_in6 *infrom = (FAR struct sockaddr_in6 *)srcaddr;
+ 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);
+ 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);
- }
+ net_ipv6addr_copy(infrom->sin6_addr.s6_addr, ipv6->srcipaddr);
}
#endif /* CONFIG_NET_IPv6 */
@@ -319,53 +394,59 @@ static inline void udp_sender(FAR struct net_driver_s *dev,
else
#endif
{
- FAR struct sockaddr_in *infrom =
- (FAR struct sockaddr_in *)pstate->ir_from;
- FAR socklen_t *fromlen = pstate->ir_fromlen;
-
- if (infrom)
- {
#ifdef CONFIG_NET_IPv6
- FAR struct udp_conn_s *conn = pstate->ir_conn;
+ FAR struct udp_conn_s *conn = pstate->ir_conn;
+ if (conn->domain == PF_INET6)
+ {
/* 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 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 */
+ FAR struct sockaddr_in6 *infrom6 =
+ (FAR struct sockaddr_in6 *)srcaddr;
+ FAR struct udp_hdr_s *udp = UDPIPv6BUF;
+ FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
+ in_addr_t ipv4addr;
- infrom6->sin6_family = AF_INET6;
- infrom6->sin6_port = udp->srcport;
- *fromlen = sizeof(struct sockaddr_in6);
+ /* Encode the IPv4 address as an IPv4-mapped IPv6 address */
- ipv4addr = net_ip4addr_conv32(ipv6->srcipaddr);
- ip6_map_ipv4addr(ipv4addr, infrom6->sin6_addr.s6_addr16);
- }
- else
+ 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;
+ {
+ FAR struct sockaddr_in *infrom = (FAR struct sockaddr_in *)srcaddr;
+ FAR struct udp_hdr_s *udp = UDPIPv4BUF;
+ FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
- infrom->sin_family = AF_INET;
- infrom->sin_port = udp->srcport;
- *fromlen = sizeof(struct sockaddr_in);
+ infrom->sin_family = AF_INET;
+ infrom->sin_port = udp->srcport;
+ fromlen = sizeof(struct sockaddr_in);
- net_ipv4addr_copy(infrom->sin_addr.s_addr,
- net_ip4addr_conv32(ipv4->srcipaddr));
- memset(infrom->sin_zero, 0, sizeof(infrom->sin_zero));
- }
+ net_ipv4addr_copy(infrom->sin_addr.s_addr,
+ net_ip4addr_conv32(ipv4->srcipaddr));
+ memset(infrom->sin_zero, 0, sizeof(infrom->sin_zero));
}
}
#endif /* CONFIG_NET_IPv4 */
+
+ if (pstate->ir_msg->msg_name)
+ {
+ pstate->ir_msg->msg_namelen = fromlen > pstate->ir_msg->msg_namelen ?
+ pstate->ir_msg->msg_namelen : fromlen;
+ memcpy(pstate->ir_msg->msg_name, srcaddr, pstate->ir_msg->msg_namelen);
+ }
+
+#ifdef CONFIG_NETDEV_IFINDEX
+ udp_recvpktinfo(pstate, srcaddr, dev->d_ifindex);
+#else
+ udp_recvpktinfo(pstate, srcaddr, 0);
+#endif
}
/****************************************************************************
@@ -387,13 +468,13 @@ 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;
+ 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;
+ pstate->ir_result = result;
/* Wake up the waiting thread, returning the number of bytes
* actually read.
@@ -482,8 +563,7 @@ static uint16_t udp_eventhandler(FAR struct net_driver_s *dev,
*
* Input Parameters:
* conn The UDP connection of interest
- * buf Buffer to receive data
- * len Length of buffer
+ * msg Receive info and buffer for receive data
* pstate A pointer to the state structure to be initialized
*
* Returned Value:
@@ -494,9 +574,7 @@ static uint16_t udp_eventhandler(FAR struct net_driver_s *dev,
****************************************************************************/
static void udp_recvfrom_initialize(FAR struct udp_conn_s *conn,
- FAR void *buf, size_t len,
- FAR struct sockaddr *infrom,
- FAR socklen_t *fromlen,
+ FAR struct msghdr *msg,
FAR struct udp_recvfrom_s *pstate)
{
/* Initialize the state structure. */
@@ -510,14 +588,11 @@ static void udp_recvfrom_initialize(FAR struct udp_conn_s *conn,
nxsem_init(&pstate->ir_sem, 0, 0); /* Doesn't really fail */
nxsem_set_protocol(&pstate->ir_sem, SEM_PRIO_NONE);
- pstate->ir_buflen = len;
- pstate->ir_buffer = buf;
- pstate->ir_from = infrom;
- pstate->ir_fromlen = fromlen;
+ pstate->ir_msg = msg;
/* Set up the start time for the timeout */
- pstate->ir_conn = conn;
+ pstate->ir_conn = conn;
}
/* The only un-initialization that has to be performed is destroying the
@@ -583,9 +658,7 @@ static ssize_t udp_recvfrom_result(int result, struct udp_recvfrom_s *pstate)
*
* 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)
+ * msg Receive info and buffer for receive data
*
* Returned Value:
* On success, returns the number of characters received. On error,
@@ -595,9 +668,8 @@ static ssize_t udp_recvfrom_result(int result, struct udp_recvfrom_s *pstate)
*
****************************************************************************/
-ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR void *buf,
- size_t len, int flags, FAR struct sockaddr *from,
- FAR socklen_t *fromlen)
+ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR struct msghdr *msg,
+ int flags)
{
FAR struct udp_conn_s *conn = (FAR struct udp_conn_s *)psock->s_conn;
FAR struct net_driver_s *dev;
@@ -611,7 +683,7 @@ ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR void *buf,
*/
net_lock();
- udp_recvfrom_initialize(conn, buf, len, from, fromlen, &state);
+ udp_recvfrom_initialize(conn, msg, &state);
/* Copy the read-ahead data from the packet */
@@ -665,9 +737,9 @@ ssize_t psock_udp_recvfrom(FAR struct socket *psock, FAR void *buf,
{
/* 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;
+ 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