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 <zhanghon...@xiaomi.com> AuthorDate: Wed Aug 24 14:55:56 2022 +0800 udp: add IPVx_PKTINFO related support Signed-off-by: zhanghongyu <zhanghon...@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