mirror of
https://github.com/apache/nuttx.git
synced 2026-05-19 03:03:37 +08:00
net/ethernet: add timestamp for socket packet
add timestamp for socket packet Signed-off-by: gaohedong <gaohedong@xiaomi.com>
This commit is contained in:
@@ -212,7 +212,7 @@
|
||||
#define SO_TYPE 15 /* Reports the socket type (get only).
|
||||
* return: int
|
||||
*/
|
||||
#define SO_TIMESTAMP 16 /* Generates a timestamp for each incoming packet
|
||||
#define SO_TIMESTAMP 16 /* Generates a timestamp in us for each incoming packet
|
||||
* arg: integer value
|
||||
*/
|
||||
#define SO_BINDTODEVICE 17 /* Bind this socket to a specific network device.
|
||||
@@ -220,6 +220,9 @@
|
||||
#define SO_PEERCRED 18 /* Return the credentials of the peer process
|
||||
* connected to this socket.
|
||||
*/
|
||||
#define SO_TIMESTAMPNS 20 /* Generates a timestamp in ns for each incoming packet
|
||||
* arg: integer value
|
||||
*/
|
||||
|
||||
/* The options are unsupported but included for compatibility
|
||||
* and portability
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include "devif/devif.h"
|
||||
#include "pkt/pkt.h"
|
||||
#include "socket/socket.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@@ -68,6 +69,22 @@ static uint16_t pkt_datahandler(FAR struct net_driver_s *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_TIMESTAMP
|
||||
if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) ||
|
||||
_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPNS))
|
||||
{
|
||||
ret = iob_trycopyin(iob, (FAR const uint8_t *)&dev->d_rxtime,
|
||||
sizeof(struct timespec), 0, true);
|
||||
if (ret != sizeof(struct timespec))
|
||||
{
|
||||
nerr("ERROR: Failed to write timestamp: %d\n", ret);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
iob_reserve(iob, sizeof(struct timespec));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Clone an I/O buffer chain of the L2 data, use throttled IOB to avoid
|
||||
* overconsumption.
|
||||
* TODO: Optimize IOB clone after we support shared IOB.
|
||||
@@ -139,6 +156,16 @@ static int pkt_in(FAR struct net_driver_s *dev)
|
||||
{
|
||||
uint16_t flags;
|
||||
|
||||
#if defined(CONFIG_NET_TIMESTAMP) && !defined(CONFIG_ARCH_HAVE_NETDEV_TIMESTAMP)
|
||||
/* Get system as timestamp if no hardware timestamp */
|
||||
|
||||
if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) ||
|
||||
_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPNS))
|
||||
{
|
||||
clock_gettime(CLOCK_REALTIME, &dev->d_rxtime);
|
||||
}
|
||||
#endif /* CONFIG_NET_TIMESTAMP */
|
||||
|
||||
/* Setup for the application callback */
|
||||
|
||||
dev->d_appdata = dev->d_buf;
|
||||
|
||||
+101
-43
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
@@ -54,18 +55,54 @@
|
||||
|
||||
struct pkt_recvfrom_s
|
||||
{
|
||||
FAR struct devif_callback_s *pr_cb; /* Reference to callback instance */
|
||||
sem_t pr_sem; /* Semaphore signals recv completion */
|
||||
size_t pr_buflen; /* Length of receive buffer */
|
||||
FAR uint8_t *pr_buffer; /* Pointer to receive buffer */
|
||||
ssize_t pr_recvlen; /* The received length */
|
||||
int pr_result; /* Success:OK, failure:negated errno */
|
||||
FAR struct pkt_conn_s *pr_conn; /* Connection associated with the socket */
|
||||
FAR struct devif_callback_s *pr_cb; /* Reference to callback instance */
|
||||
FAR struct msghdr *pr_msg; /* Receive info and buffer */
|
||||
sem_t pr_sem; /* Semaphore signals recv completion */
|
||||
ssize_t pr_recvlen; /* The received length */
|
||||
int pr_result; /* Success:OK, failure:negated errno */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_store_cmsg_timestamp
|
||||
*
|
||||
* Description:
|
||||
* Store the timestamp in the cmsg
|
||||
*
|
||||
* Input Parameters:
|
||||
* pstate Recicve state information
|
||||
* timestamp Timestamp information
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_TIMESTAMP
|
||||
static void pkt_store_cmsg_timestamp(FAR struct pkt_recvfrom_s *pstate,
|
||||
FAR struct timespec *timestamp)
|
||||
{
|
||||
FAR struct msghdr *msg = pstate->pr_msg;
|
||||
struct timeval tv;
|
||||
|
||||
if (_SO_GETOPT(pstate->pr_conn->sconn.s_options, SO_TIMESTAMPNS))
|
||||
{
|
||||
cmsg_append(msg, SOL_SOCKET, SO_TIMESTAMPNS, timestamp,
|
||||
sizeof(struct timespec));
|
||||
}
|
||||
else
|
||||
{
|
||||
TIMESPEC_TO_TIMEVAL(&tv, timestamp);
|
||||
cmsg_append(msg, SOL_SOCKET, SO_TIMESTAMP, &tv,
|
||||
sizeof(struct timeval));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_add_recvlen
|
||||
*
|
||||
@@ -92,8 +129,6 @@ static inline void pkt_add_recvlen(FAR struct pkt_recvfrom_s *pstate,
|
||||
}
|
||||
|
||||
pstate->pr_recvlen += recvlen;
|
||||
pstate->pr_buffer += recvlen;
|
||||
pstate->pr_buflen -= recvlen;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -120,20 +155,24 @@ static void pkt_recvfrom_newdata(FAR struct net_driver_s *dev,
|
||||
unsigned int offset;
|
||||
size_t recvlen;
|
||||
|
||||
if (dev->d_len > pstate->pr_buflen)
|
||||
#ifdef CONFIG_NET_TIMESTAMP
|
||||
/* Unpack stored timestamp if SO_TIMESTAMP socket option is enabled */
|
||||
|
||||
if (_SO_GETOPT(pstate->pr_conn->sconn.s_options, SO_TIMESTAMP) ||
|
||||
_SO_GETOPT(pstate->pr_conn->sconn.s_options, SO_TIMESTAMPNS))
|
||||
{
|
||||
recvlen = pstate->pr_buflen;
|
||||
}
|
||||
else
|
||||
{
|
||||
recvlen = dev->d_len;
|
||||
pkt_store_cmsg_timestamp(pstate, &dev->d_rxtime);
|
||||
}
|
||||
#endif
|
||||
|
||||
recvlen = MIN(pstate->pr_msg->msg_iov->iov_len, dev->d_len);
|
||||
|
||||
/* Copy the new packet data into the user buffer */
|
||||
|
||||
offset = (dev->d_appdata - dev->d_iob->io_data) - dev->d_iob->io_offset;
|
||||
|
||||
recvlen = iob_copyout(pstate->pr_buffer, dev->d_iob, recvlen, offset);
|
||||
recvlen = iob_copyout(pstate->pr_msg->msg_iov->iov_base,
|
||||
dev->d_iob, recvlen, offset);
|
||||
|
||||
ninfo("Received %d bytes (of %d)\n", (int)recvlen, (int)dev->d_len);
|
||||
|
||||
@@ -228,9 +267,8 @@ static uint16_t pkt_recvfrom_eventhandler(FAR struct net_driver_s *dev,
|
||||
* Initialize the state structure
|
||||
*
|
||||
* Input Parameters:
|
||||
* psock Pointer to the socket structure for the socket
|
||||
* buf Buffer to receive data
|
||||
* len Length of buffer
|
||||
* conn The PKT connection of interest
|
||||
* msg Receive info and buffer for receive data
|
||||
* pstate A pointer to the state structure to be initialized
|
||||
*
|
||||
* Returned Value:
|
||||
@@ -240,9 +278,8 @@ static uint16_t pkt_recvfrom_eventhandler(FAR struct net_driver_s *dev,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void pkt_recvfrom_initialize(FAR struct socket *psock, FAR void *buf,
|
||||
size_t len, FAR struct sockaddr *infrom,
|
||||
FAR socklen_t *fromlen,
|
||||
static void pkt_recvfrom_initialize(FAR struct pkt_conn_s *conn,
|
||||
FAR struct msghdr *msg,
|
||||
FAR struct pkt_recvfrom_s *pstate)
|
||||
{
|
||||
/* Initialize the state structure. */
|
||||
@@ -250,8 +287,8 @@ static void pkt_recvfrom_initialize(FAR struct socket *psock, FAR void *buf,
|
||||
memset(pstate, 0, sizeof(struct pkt_recvfrom_s));
|
||||
nxsem_init(&pstate->pr_sem, 0, 0); /* Doesn't really fail */
|
||||
|
||||
pstate->pr_buflen = len;
|
||||
pstate->pr_buffer = buf;
|
||||
pstate->pr_conn = conn;
|
||||
pstate->pr_msg = msg;
|
||||
}
|
||||
|
||||
/* The only un-initialization that has to be performed is destroying the
|
||||
@@ -313,35 +350,58 @@ static ssize_t pkt_recvfrom_result(int result,
|
||||
* Copy the buffered read-ahead data to the user buffer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - PKT socket connection structure containing the read-
|
||||
* ahead data.
|
||||
* buf target buffer.
|
||||
* pstate The state structure of the recv operation
|
||||
*
|
||||
* Returned Value:
|
||||
* Number of bytes copied to the user buffer
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline ssize_t pkt_readahead(FAR struct pkt_conn_s *conn,
|
||||
FAR void *buf, size_t buflen)
|
||||
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;
|
||||
ssize_t ret = -ENODATA;
|
||||
int recvlen;
|
||||
|
||||
/* Check there is any packets already buffered in a read-ahead buffer. */
|
||||
|
||||
pstate->pr_recvlen = -ENODATA;
|
||||
|
||||
if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
|
||||
{
|
||||
DEBUGASSERT(iob->io_pktlen > 0);
|
||||
|
||||
#ifdef CONFIG_NET_TIMESTAMP
|
||||
/* Unpack stored timestamp if SO_TIMESTAMP/SO_TIMESTAMPNS socket option
|
||||
* is enabled
|
||||
*/
|
||||
|
||||
if (_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMP) ||
|
||||
_SO_GETOPT(conn->sconn.s_options, SO_TIMESTAMPNS))
|
||||
{
|
||||
struct timespec ts;
|
||||
recvlen = iob_copyout((FAR uint8_t *)&ts, iob,
|
||||
sizeof(struct timespec),
|
||||
-sizeof(struct timespec));
|
||||
DEBUGASSERT(recvlen == sizeof(struct timespec));
|
||||
|
||||
pkt_store_cmsg_timestamp(pstate, &ts);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Copy to user */
|
||||
|
||||
ret = iob_copyout(buf, iob, buflen, 0);
|
||||
recvlen = iob_copyout(pstate->pr_msg->msg_iov->iov_base, iob,
|
||||
pstate->pr_msg->msg_iov->iov_len, 0);
|
||||
|
||||
ninfo("Received %zd bytes (of %u)\n", ret, iob->io_pktlen);
|
||||
/* Update the accumulated size of the data read */
|
||||
|
||||
pstate->pr_recvlen = recvlen;
|
||||
|
||||
ninfo("Received %d bytes (of %u)\n", recvlen, iob->io_pktlen);
|
||||
|
||||
/* Remove the I/O buffer chain from the head of the read-ahead
|
||||
* buffer queue.
|
||||
@@ -353,8 +413,6 @@ static inline ssize_t pkt_readahead(FAR struct pkt_conn_s *conn,
|
||||
|
||||
iob_free_chain(iob);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -392,14 +450,12 @@ static inline ssize_t pkt_readahead(FAR struct pkt_conn_s *conn,
|
||||
ssize_t pkt_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;
|
||||
FAR struct pkt_conn_s *conn = psock->s_conn;
|
||||
FAR struct net_driver_s *dev;
|
||||
struct pkt_recvfrom_s state;
|
||||
ssize_t ret;
|
||||
ssize_t ret = 0;
|
||||
|
||||
/* If a 'from' address has been provided, verify that it is large
|
||||
* enough to hold this address family.
|
||||
@@ -427,6 +483,8 @@ 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);
|
||||
|
||||
net_lock();
|
||||
|
||||
/* Check if there is buffered read-ahead data for this socket. We may have
|
||||
@@ -435,7 +493,8 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||
|
||||
if (!IOB_QEMPTY(&conn->readahead))
|
||||
{
|
||||
ret = pkt_readahead(conn, buf, len);
|
||||
pkt_readahead(&state);
|
||||
ret = pkt_recvfrom_result(ret, &state);
|
||||
}
|
||||
else if (_SS_ISNONBLOCK(conn->sconn.s_flags) ||
|
||||
(flags & MSG_DONTWAIT) != 0)
|
||||
@@ -446,8 +505,6 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||
}
|
||||
else
|
||||
{
|
||||
pkt_recvfrom_initialize(psock, buf, len, from, fromlen, &state);
|
||||
|
||||
/* Get the device driver that will service this transfer */
|
||||
|
||||
dev = pkt_find_device(conn);
|
||||
@@ -496,12 +553,13 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||
{
|
||||
ret = -EBUSY;
|
||||
}
|
||||
|
||||
errout_with_state:
|
||||
pkt_recvfrom_uninitialize(&state);
|
||||
}
|
||||
|
||||
net_unlock();
|
||||
|
||||
errout_with_state:
|
||||
pkt_recvfrom_uninitialize(&state);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -140,15 +140,16 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
|
||||
* is outside of the scope of getsockopt.
|
||||
*/
|
||||
|
||||
case SO_BROADCAST: /* Permits sending of broadcast messages */
|
||||
case SO_DEBUG: /* Enables recording of debugging information */
|
||||
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
|
||||
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
|
||||
* periodic transmission of probes */
|
||||
case SO_OOBINLINE: /* Leaves received out-of-band data inline */
|
||||
case SO_REUSEADDR: /* Allow reuse of local addresses */
|
||||
case SO_BROADCAST: /* Permits sending of broadcast messages */
|
||||
case SO_DEBUG: /* Enables recording of debugging information */
|
||||
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
|
||||
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
|
||||
* periodic transmission of probes */
|
||||
case SO_OOBINLINE: /* Leaves received out-of-band data inline */
|
||||
case SO_REUSEADDR: /* Allow reuse of local addresses */
|
||||
#ifdef CONFIG_NET_TIMESTAMP
|
||||
case SO_TIMESTAMP: /* Generates a timestamp for each incoming packet */
|
||||
case SO_TIMESTAMP: /* Generates a timestamp in us for each incoming packet */
|
||||
case SO_TIMESTAMPNS: /* Generates a timestamp in ns for each incoming packet */
|
||||
#endif
|
||||
{
|
||||
sockopt_t optionset;
|
||||
|
||||
@@ -130,15 +130,16 @@ static int psock_socketlevel_option(FAR struct socket *psock, int option,
|
||||
return OK;
|
||||
}
|
||||
|
||||
case SO_BROADCAST: /* Permits sending of broadcast messages */
|
||||
case SO_DEBUG: /* Enables recording of debugging information */
|
||||
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
|
||||
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
|
||||
* periodic transmission of probes */
|
||||
case SO_OOBINLINE: /* Leaves received out-of-band data inline */
|
||||
case SO_REUSEADDR: /* Allow reuse of local addresses */
|
||||
case SO_BROADCAST: /* Permits sending of broadcast messages */
|
||||
case SO_DEBUG: /* Enables recording of debugging information */
|
||||
case SO_DONTROUTE: /* Requests outgoing messages bypass standard routing */
|
||||
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
|
||||
* periodic transmission of probes */
|
||||
case SO_OOBINLINE: /* Leaves received out-of-band data inline */
|
||||
case SO_REUSEADDR: /* Allow reuse of local addresses */
|
||||
#ifdef CONFIG_NET_TIMESTAMP
|
||||
case SO_TIMESTAMP: /* Generates a timestamp for each incoming packet */
|
||||
case SO_TIMESTAMP: /* Generates a timestamp in us for each incoming packet */
|
||||
case SO_TIMESTAMPNS: /* Generates a timestamp in ns for each incoming packet */
|
||||
#endif
|
||||
{
|
||||
int setting;
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
#define _SO_SNDTIMEO _SO_BIT(SO_SNDTIMEO)
|
||||
#define _SO_TYPE _SO_BIT(SO_TYPE)
|
||||
#define _SO_TIMESTAMP _SO_BIT(SO_TIMESTAMP)
|
||||
#define _SO_TIMESTAMPNS _SO_BIT(SO_TIMESTAMPNS)
|
||||
#define _SO_BINDTODEVICE _SO_BIT(SO_BINDTODEVICE)
|
||||
|
||||
/* This is the largest option value. REVISIT: belongs in sys/socket.h */
|
||||
|
||||
Reference in New Issue
Block a user