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