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 <zhanghongyu@xiaomi.com>
This commit is contained in:
zhanghongyu
2025-06-09 20:28:59 +08:00
committed by Alan C. Assis
parent 07247be9f6
commit 37381a9e7d
8 changed files with 216 additions and 87 deletions

View File

@@ -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 */

View File

@@ -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
*

View File

@@ -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 */

View File

@@ -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();

View File

@@ -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);

View File

@@ -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 */
/* Validity check */
if (msg->msg_iovlen != 1)
ret = pkt_sendmsg_is_valid(psock, msg, &dev);
if (ret != OK)
{
return -ENOTSUP;
return ret;
}
if (msg->msg_name != NULL)
conn = psock->s_conn;
if (psock->s_type == SOCK_DGRAM)
{
/* pkt_sendto */
/* Set the interface index for devif_poll can match the conn */
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;
}
/* 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);

View File

@@ -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;
}

View File

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