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:
{