This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 37381a9e7da net/pkt: add SOCK_DGRAM support
37381a9e7da is described below

commit 37381a9e7dad3608a708b676deabcb228f0b6dec
Author: zhanghongyu <[email protected]>
AuthorDate: Mon Jun 9 20:28:59 2025 +0800

    net/pkt: add SOCK_DGRAM support
    
    According to the definitions of PF_PACKET and SOCK_DGRAM,
    extend the current protocol stack pkt protocol to support SOCK_DGRAM mode.
    
    Some third-party network libraries use AF_PACKET, SOCK_DGRAM type sockets
    to construct packets and send/receive data, This patch can add support
    for this.
    
    Signed-off-by: zhanghongyu <[email protected]>
---
 Documentation/components/net/pkt.rst | 24 +++++++++++-
 net/pkt/pkt.h                        | 20 ++++++++++
 net/pkt/pkt_conn.c                   | 75 ++++++++++++++++++++++++++++++++++++
 net/pkt/pkt_recvmsg.c                | 35 ++++++++++++++---
 net/pkt/pkt_sendmsg_buffered.c       | 66 ++++++++++++++-----------------
 net/pkt/pkt_sendmsg_unbuffered.c     | 70 ++++++++++++++++-----------------
 net/pkt/pkt_setsockopt.c             |  4 +-
 net/pkt/pkt_sockif.c                 |  7 +++-
 8 files changed, 215 insertions(+), 86 deletions(-)

diff --git a/Documentation/components/net/pkt.rst 
b/Documentation/components/net/pkt.rst
index 9df38f43c35..f0ec185c1ff 100644
--- a/Documentation/components/net/pkt.rst
+++ b/Documentation/components/net/pkt.rst
@@ -17,6 +17,8 @@ Configuration Options
   Dynamic memory allocations for packet connections.
 ``CONFIG_NET_PKT_MAX_CONNS``
   Maximum number of packet connections.
+``NET_PKT_WRITE_BUFFERS``
+  Use write buffers for packet sockets, support SOCK_NONBLOCK mode.
 
 Usage
 =====
@@ -25,7 +27,7 @@ Usage
 
   struct sockaddr_ll addr;
   uint8_t buffer[BUFSIZE];
-  int sd = socket(AF_PACKET, SOCK_RAW, 0); /* Create a packet socket */
+  int sd = socket(AF_PACKET, SOCK_RAW, 0); /* Create a Raw packet socket */
 
   addr.sll_family = AF_PACKET;
   addr.sll_ifindex = if_nametoindex("eth0");
@@ -36,3 +38,23 @@ Usage
   send(sd, buffer, sizeof(buffer), 0); /* write(sd, buffer, sizeof(buffer)); */
 
   close(sd); /* Close the socket */
+
+.. code-block:: c
+
+  struct sockaddr_ll addr;
+  uint8_t buffer[BUFSIZE];
+  int sd = socket(AF_PACKET, SOCK_DGRAM, 0); /* Create a Dgram packet socket */
+
+  addr.sll_family = AF_PACKET;
+  addr.sll_ifindex = if_nametoindex("eth0");
+  addr.sll_protocol = htons(ETH_P_IP);
+  bind(sd, (FAR struct sockaddr *)&addr, sizeof(addr)); /* Bind to device */
+
+  recv(sd, buffer, sizeof(buffer), 0); /* read(sd, buffer, sizeof(buffer)); */
+
+  memset(addr.sll_addr, 0xff, sizeof(addr.sll_addr)); /* Destination MAC 
address */
+  addr.sll_halen = ETH_ALEN;
+  sendto(sd, buffer, sizeof(buffer), 0, /* SOCK_DGRAM can not use write() */
+         (struct sockaddr *)&addr, sizeof(addr));
+
+  close(sd); /* Close the socket */
diff --git a/net/pkt/pkt.h b/net/pkt/pkt.h
index 1fa27860e22..16f1c5f6199 100644
--- a/net/pkt/pkt.h
+++ b/net/pkt/pkt.h
@@ -196,6 +196,26 @@ FAR struct pkt_conn_s *pkt_active(FAR struct net_driver_s 
*dev);
 
 FAR struct pkt_conn_s *pkt_nextconn(FAR struct pkt_conn_s *conn);
 
+/****************************************************************************
+ * Name: pkt_sendmsg_is_valid
+ *
+ * Description:
+ *   Validate the sendmsg() parameters for a packet socket.
+ *
+ * Input Parameters:
+ *   psock - The socket structure to validate
+ *   msg   - The message header containing the data to be sent
+ *   dev   - The network device to be used to send the packet
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int pkt_sendmsg_is_valid(FAR struct socket *psock,
+                         FAR const struct msghdr *msg,
+                         FAR struct net_driver_s **dev);
+
 /****************************************************************************
  * Name: pkt_callback
  *
diff --git a/net/pkt/pkt_conn.c b/net/pkt/pkt_conn.c
index 2acda198926..bd81a10f1b1 100644
--- a/net/pkt/pkt_conn.c
+++ b/net/pkt/pkt_conn.c
@@ -33,6 +33,7 @@
 
 #include <arch/irq.h>
 #include <netinet/if_ether.h>
+#include <netpacket/packet.h>
 
 #include <nuttx/kmalloc.h>
 #include <nuttx/mutex.h>
@@ -42,6 +43,7 @@
 #include <nuttx/net/ethernet.h>
 
 #include "devif/devif.h"
+#include "netdev/netdev.h"
 #include "pkt/pkt.h"
 #include "utils/utils.h"
 
@@ -217,4 +219,77 @@ FAR struct pkt_conn_s *pkt_nextconn(FAR struct pkt_conn_s 
*conn)
     }
 }
 
+/****************************************************************************
+ * Name: pkt_sendmsg_is_valid
+ *
+ * Description:
+ *   Validate the sendmsg() parameters for a packet socket.
+ *
+ * Input Parameters:
+ *   psock - The socket structure to validate
+ *   msg   - The message header containing the data to be sent
+ *   dev   - The network device to be used to send the packet
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int pkt_sendmsg_is_valid(FAR struct socket *psock,
+                         FAR const struct msghdr *msg,
+                         FAR struct net_driver_s **dev)
+{
+  FAR struct sockaddr_ll *addr = msg->msg_name;
+
+  /* Only single iov supported */
+
+  if (msg->msg_iovlen != 1)
+    {
+      return -ENOTSUP;
+    }
+
+  /* Verify that the sockfd corresponds to valid, allocated socket */
+
+  if (psock == NULL || psock->s_conn == NULL)
+    {
+      return -EBADF;
+    }
+
+  if (psock->s_type == SOCK_DGRAM)
+    {
+      if (msg->msg_name == NULL ||
+          msg->msg_namelen < sizeof(struct sockaddr_ll) ||
+          addr->sll_halen < ETHER_ADDR_LEN)
+        {
+          return -EINVAL;
+        }
+
+      /* Get the device driver that will service this transfer */
+
+      *dev = netdev_findbyindex(addr->sll_ifindex);
+    }
+  else if (psock->s_type == SOCK_RAW)
+    {
+      if (msg->msg_name != NULL)
+        {
+          return -EAFNOSUPPORT;
+        }
+
+      /* Get the device driver that will service this transfer */
+
+      *dev = pkt_find_device(psock->s_conn);
+    }
+  else
+    {
+      return -ENOTSUP;
+    }
+
+  if (*dev == NULL)
+    {
+      return -ENODEV;
+    }
+
+  return OK;
+}
+
 #endif /* CONFIG_NET && CONFIG_NET_PKT */
diff --git a/net/pkt/pkt_recvmsg.c b/net/pkt/pkt_recvmsg.c
index 08b93092de9..8d3b179ca4d 100644
--- a/net/pkt/pkt_recvmsg.c
+++ b/net/pkt/pkt_recvmsg.c
@@ -61,6 +61,7 @@ struct pkt_recvfrom_s
   sem_t                        pr_sem;     /* Semaphore signals recv 
completion */
   ssize_t                      pr_recvlen; /* The received length */
   int                          pr_result;  /* Success:OK, failure:negated 
errno */
+  uint8_t                      pr_type;    /* Protocol type */
 };
 
 /****************************************************************************
@@ -152,7 +153,7 @@ static inline void pkt_add_recvlen(FAR struct 
pkt_recvfrom_s *pstate,
 static void pkt_recvfrom_newdata(FAR struct net_driver_s *dev,
                                  FAR struct pkt_recvfrom_s *pstate)
 {
-  unsigned int offset;
+  unsigned int offset = 0;
   size_t recvlen;
 
 #ifdef CONFIG_NET_TIMESTAMP
@@ -169,7 +170,10 @@ static void pkt_recvfrom_newdata(FAR struct net_driver_s 
*dev,
 
   /* Copy the new packet data into the user buffer */
 
-  offset = (dev->d_appdata - dev->d_iob->io_data) - dev->d_iob->io_offset;
+  if (pstate->pr_type == SOCK_RAW)
+    {
+      offset = -NET_LL_HDRLEN(dev);
+    }
 
   recvlen = iob_copyout(pstate->pr_msg->msg_iov->iov_base,
                         dev->d_iob, recvlen, offset);
@@ -270,6 +274,7 @@ static uint16_t pkt_recvfrom_eventhandler(FAR struct 
net_driver_s *dev,
  *   conn     The PKT connection of interest
  *   msg      Receive info and buffer for receive data
  *   pstate   A pointer to the state structure to be initialized
+ *   type     Protocol type
  *
  * Returned Value:
  *   None
@@ -280,7 +285,8 @@ static uint16_t pkt_recvfrom_eventhandler(FAR struct 
net_driver_s *dev,
 
 static void pkt_recvfrom_initialize(FAR struct pkt_conn_s *conn,
                                     FAR struct msghdr *msg,
-                                    FAR struct pkt_recvfrom_s *pstate)
+                                    FAR struct pkt_recvfrom_s *pstate,
+                                    uint8_t type)
 {
   /* Initialize the state structure. */
 
@@ -289,6 +295,7 @@ static void pkt_recvfrom_initialize(FAR struct pkt_conn_s 
*conn,
 
   pstate->pr_conn = conn;
   pstate->pr_msg  = msg;
+  pstate->pr_type = type;
 }
 
 /* The only un-initialization that has to be performed is destroying the
@@ -365,6 +372,7 @@ static inline void pkt_readahead(FAR struct pkt_recvfrom_s 
*pstate)
   FAR struct pkt_conn_s *conn = pstate->pr_conn;
   FAR struct iob_s *iob;
   int recvlen;
+  int offset = 0;
 
   /* Check there is any packets already buffered in a read-ahead buffer. */
 
@@ -394,8 +402,23 @@ static inline void pkt_readahead(FAR struct pkt_recvfrom_s 
*pstate)
 
       /* Copy to user */
 
+      if (pstate->pr_type == SOCK_DGRAM)
+        {
+          FAR struct net_driver_s *dev = pkt_find_device(conn);
+          if (dev != NULL)
+            {
+              /* For SOCK_DGRAM, we need skip the l2 header */
+
+              offset = NET_LL_HDRLEN(dev);
+            }
+          else
+            {
+              offset = sizeof(struct eth_hdr_s);
+            }
+        }
+
       recvlen = iob_copyout(pstate->pr_msg->msg_iov->iov_base, iob,
-                            pstate->pr_msg->msg_iov->iov_len, 0);
+                            pstate->pr_msg->msg_iov->iov_len, offset);
 
       /* Update the accumulated size of the data read */
 
@@ -471,7 +494,7 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct 
msghdr *msg,
       return -ENOTSUP;
     }
 
-  if (psock->s_type != SOCK_RAW)
+  if (psock->s_type != SOCK_DGRAM && psock->s_type != SOCK_RAW)
     {
       nerr("ERROR: Unsupported socket type: %d\n", psock->s_type);
       ret = -ENOSYS;
@@ -483,7 +506,7 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct 
msghdr *msg,
    * locked because we don't want anything to happen until we are ready.
    */
 
-  pkt_recvfrom_initialize(conn, msg, &state);
+  pkt_recvfrom_initialize(conn, msg, &state, psock->s_type);
 
   net_lock();
 
diff --git a/net/pkt/pkt_sendmsg_buffered.c b/net/pkt/pkt_sendmsg_buffered.c
index 5a13642fe80..baf4d89aaa0 100644
--- a/net/pkt/pkt_sendmsg_buffered.c
+++ b/net/pkt/pkt_sendmsg_buffered.c
@@ -36,6 +36,7 @@
 #include <debug.h>
 
 #include <arch/irq.h>
+#include <netpacket/packet.h>
 
 #include <nuttx/semaphore.h>
 #include <nuttx/net/netdev.h>
@@ -208,43 +209,20 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const 
struct msghdr *msg,
 {
   FAR const void *buf = msg->msg_iov->iov_base;
   size_t len = msg->msg_iov->iov_len;
+  FAR struct sockaddr_ll *addr = msg->msg_name;
   FAR struct net_driver_s *dev;
   FAR struct pkt_conn_s *conn;
   FAR struct iob_s *iob;
   bool nonblock;
+  int offset = 0;
   int ret = OK;
 
-  /* Validity check, only single iov supported */
+  /* Validity check */
 
-  if (msg->msg_iovlen != 1)
+  ret = pkt_sendmsg_is_valid(psock, msg, &dev);
+  if (ret != OK)
     {
-      return -ENOTSUP;
-    }
-
-  if (msg->msg_name != NULL)
-    {
-      /* pkt_sendto */
-
-      nerr("ERROR: sendto() not supported for raw packet sockets\n");
-      return -EAFNOSUPPORT;
-    }
-
-  /* Verify that the sockfd corresponds to valid, allocated socket */
-
-  if (psock == NULL || psock->s_conn == NULL)
-    {
-      return -EBADF;
-    }
-
-  /* Only SOCK_RAW is supported */
-
-  if (psock->s_type != SOCK_RAW)
-    {
-      /* EDESTADDRREQ.  Signifies that the socket is not connection-mode and
-       * no peer address is set.
-       */
-
-      return -EDESTADDRREQ;
+      return ret;
     }
 
   if (len <= 0)
@@ -254,16 +232,14 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const 
struct msghdr *msg,
 
   net_lock();
 
-  /* Get the device driver that will service this transfer */
-
-  dev = pkt_find_device(psock->s_conn);
-  if (dev == NULL)
+  conn = psock->s_conn;
+  if (psock->s_type == SOCK_DGRAM)
     {
-      ret = -ENODEV;
-      goto errout_with_lock;
+      /* Set the interface index for devif_poll can match the conn */
+
+      conn->ifindex = addr->sll_ifindex;
     }
 
-  conn = psock->s_conn;
   nonblock = _SS_ISNONBLOCK(conn->sconn.s_flags) ||
              (flags & MSG_DONTWAIT) != 0;
 
@@ -322,9 +298,14 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const 
struct msghdr *msg,
    * buffer space if the socket was opened non-blocking.
    */
 
+  if (psock->s_type == SOCK_RAW)
+    {
+      offset = -NET_LL_HDRLEN(dev);
+    }
+
   if (nonblock)
     {
-      ret = iob_trycopyin(iob, buf, len, -NET_LL_HDRLEN(dev), false);
+      ret = iob_trycopyin(iob, buf, len, offset, false);
     }
   else
     {
@@ -337,7 +318,7 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const 
struct msghdr *msg,
        */
 
       blresult = net_breaklock(&count);
-      ret = iob_copyin(iob, buf, len, -NET_LL_HDRLEN(dev), false);
+      ret = iob_copyin(iob, buf, len, offset, false);
       if (blresult >= 0)
         {
           net_restorelock(count);
@@ -350,6 +331,15 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const 
struct msghdr *msg,
       goto errout_with_iob;
     }
 
+  if (psock->s_type == SOCK_DGRAM)
+    {
+      FAR struct eth_hdr_s *ethhdr =
+          (FAR struct eth_hdr_s *)(IOB_DATA(iob) - NET_LL_HDRLEN(dev));
+      memcpy(ethhdr->dest, addr->sll_addr, ETHER_ADDR_LEN);
+      memcpy(ethhdr->src, &dev->d_mac.ether, ETHER_ADDR_LEN);
+      ethhdr->type = addr->sll_protocol;
+    }
+
   if (nonblock)
     {
       ret = iob_tryadd_queue(iob, &conn->write_q);
diff --git a/net/pkt/pkt_sendmsg_unbuffered.c b/net/pkt/pkt_sendmsg_unbuffered.c
index b7d7bb510b4..ee70d64eb1e 100644
--- a/net/pkt/pkt_sendmsg_unbuffered.c
+++ b/net/pkt/pkt_sendmsg_unbuffered.c
@@ -37,6 +37,7 @@
 #include <debug.h>
 
 #include <arch/irq.h>
+#include <netpacket/packet.h>
 
 #include <nuttx/semaphore.h>
 #include <nuttx/net/netdev.h>
@@ -65,6 +66,7 @@ struct send_s
   FAR const uint8_t      *snd_buffer;  /* Points to the buffer of data to send 
*/
   size_t                  snd_buflen;  /* Number of bytes in the buffer to 
send */
   ssize_t                 snd_sent;    /* The number of bytes sent */
+  FAR struct sockaddr_ll *addr;        /* The address of the destination */
 };
 
 /****************************************************************************
@@ -108,8 +110,16 @@ static uint16_t psock_send_eventhandler(FAR struct 
net_driver_s *dev,
         {
           /* Copy the packet data into the device packet buffer and send it */
 
-          int ret = devif_send(dev, pstate->snd_buffer,
-                               pstate->snd_buflen, -NET_LL_HDRLEN(dev));
+          int ret;
+          int offset = -NET_LL_HDRLEN(dev);
+
+          if (pstate->snd_sock->s_type == SOCK_DGRAM)
+            {
+              offset = 0;
+            }
+
+          ret = devif_send(dev, pstate->snd_buffer,
+                           pstate->snd_buflen, offset);
           if (ret <= 0)
             {
               pstate->snd_sent = ret;
@@ -120,6 +130,15 @@ static uint16_t psock_send_eventhandler(FAR struct 
net_driver_s *dev,
           pstate->snd_sent          = pstate->snd_buflen;
           pstate->snd_conn->pendiob = dev->d_iob;
 
+          if (pstate->snd_sock->s_type == SOCK_DGRAM)
+            {
+              FAR struct eth_hdr_s *ethhdr = NETLLBUF;
+              memcpy(ethhdr->dest, pstate->addr->sll_addr, ETHER_ADDR_LEN);
+              memcpy(ethhdr->src, &dev->d_mac.ether, ETHER_ADDR_LEN);
+              ethhdr->type = pstate->addr->sll_protocol;
+              dev->d_len += NET_LL_HDRLEN(dev);
+            }
+
           /* Make sure no ARP request overwrites this ARP request.  This
            * flag will be cleared in arp_out().
            */
@@ -171,49 +190,27 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR struct 
msghdr *msg,
 {
   FAR const void *buf = msg->msg_iov->iov_base;
   size_t len = msg->msg_iov->iov_len;
+  FAR struct sockaddr_ll *addr = msg->msg_name;
   FAR struct net_driver_s *dev;
+  FAR struct pkt_conn_s *conn;
   struct send_s state;
   int ret = OK;
 
-  /* Validity check, only single iov supported */
-
-  if (msg->msg_iovlen != 1)
-    {
-      return -ENOTSUP;
-    }
-
-  if (msg->msg_name != NULL)
-    {
-      /* pkt_sendto */
-
-      nerr("ERROR: sendto() not supported for raw packet sockets\n");
-      return -EAFNOSUPPORT;
-    }
+  /* Validity check */
 
-  /* Verify that the sockfd corresponds to valid, allocated socket */
-
-  if (psock == NULL || psock->s_conn == NULL)
+  ret = pkt_sendmsg_is_valid(psock, msg, &dev);
+  if (ret != OK)
     {
-      return -EBADF;
+      return ret;
     }
 
-  /* Only SOCK_RAW is supported */
+  conn = psock->s_conn;
 
-  if (psock->s_type != SOCK_RAW)
+  if (psock->s_type == SOCK_DGRAM)
     {
-      /* EDESTADDRREQ.  Signifies that the socket is not connection-mode and
-       * no peer address is set.
-       */
+      /* Set the interface index for devif_poll can match the conn */
 
-      return -EDESTADDRREQ;
-    }
-
-  /* Get the device driver that will service this transfer */
-
-  dev = pkt_find_device(psock->s_conn);
-  if (dev == NULL)
-    {
-      return -ENODEV;
+      conn->ifindex = addr->sll_ifindex;
     }
 
   /* Perform the send operation */
@@ -229,12 +226,11 @@ ssize_t pkt_sendmsg(FAR struct socket *psock, FAR struct 
msghdr *msg,
   state.snd_sock   = psock;          /* Socket descriptor to use */
   state.snd_buflen = len;            /* Number of bytes to send */
   state.snd_buffer = buf;            /* Buffer to send from */
-  state.snd_conn   = psock->s_conn;  /* Connection info */
+  state.snd_conn   = conn;           /* Connection info */
+  state.addr       = addr;           /* Destination address */
 
   if (len > 0)
     {
-      FAR struct pkt_conn_s *conn = psock->s_conn;
-
       /* Allocate resource to receive a callback */
 
       state.snd_cb = pkt_callback_alloc(dev, conn);
diff --git a/net/pkt/pkt_setsockopt.c b/net/pkt/pkt_setsockopt.c
index 9c340117404..b3f1015ef32 100644
--- a/net/pkt/pkt_setsockopt.c
+++ b/net/pkt/pkt_setsockopt.c
@@ -82,9 +82,9 @@ int pkt_setsockopt(FAR struct socket *psock, int level, int 
option,
       return -ENOPROTOOPT;
     }
 
-  if (psock->s_type != SOCK_RAW)
+  if (psock->s_type != SOCK_DGRAM && psock->s_type != SOCK_RAW)
     {
-      nerr("ERROR:  Not a RAW PKT socket\n");
+      nerr("ERROR:  Not a valid PKT socket\n");
       return -ENOTCONN;
     }
 
diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c
index eabd02218d1..f720eb3eed5 100644
--- a/net/pkt/pkt_sockif.c
+++ b/net/pkt/pkt_sockif.c
@@ -165,7 +165,8 @@ static int pkt_setup(FAR struct socket *psock)
    * SOCK_RAW and SOCK_CTRL are supported.
    */
 
-  if (psock->s_type == SOCK_RAW || psock->s_type == SOCK_CTRL)
+  if (psock->s_type == SOCK_DGRAM || psock->s_type == SOCK_RAW ||
+      psock->s_type == SOCK_CTRL)
     {
       return pkt_sockif_alloc(psock);
     }
@@ -255,7 +256,8 @@ static int pkt_bind(FAR struct socket *psock,
 
   /* Bind a raw socket to a network device. */
 
-  if (psock->s_type == SOCK_RAW || psock->s_type == SOCK_CTRL)
+  if (psock->s_type == SOCK_DGRAM || psock->s_type == SOCK_RAW ||
+      psock->s_type == SOCK_CTRL)
     {
       FAR struct pkt_conn_s *conn = psock->s_conn;
       FAR struct net_driver_s *dev;
@@ -347,6 +349,7 @@ static int pkt_close(FAR struct socket *psock)
 
   switch (psock->s_type)
     {
+      case SOCK_DGRAM:
       case SOCK_RAW:
       case SOCK_CTRL:
         {

Reply via email to