net/pkt: Add readahead queue for pkt, call input for tx on sim
Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
parent
cd1decf4a5
commit
0e018308a3
@ -110,6 +110,12 @@ static void netdriver_send(struct net_driver_s *dev)
|
||||
|
||||
UNUSED(devidx);
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
/* When packet sockets are enabled, feed the tx frame into it */
|
||||
|
||||
pkt_input(dev);
|
||||
#endif
|
||||
|
||||
sim_netdev_send(devidx, buf, dev->d_len);
|
||||
}
|
||||
|
||||
|
@ -208,17 +208,25 @@ static int devif_poll_pkt_connections(FAR struct net_driver_s *dev,
|
||||
|
||||
while (!bstop && (pkt_conn = pkt_nextconn(pkt_conn)))
|
||||
{
|
||||
/* Perform the packet TX poll */
|
||||
/* Skip packet connections that are bound to other polling devices */
|
||||
|
||||
pkt_poll(dev, pkt_conn);
|
||||
if (dev->d_ifindex == pkt_conn->ifindex)
|
||||
{
|
||||
/* Perform the packet TX poll */
|
||||
|
||||
/* Perform any necessary conversions on outgoing packets */
|
||||
pkt_poll(dev, pkt_conn);
|
||||
|
||||
devif_packet_conversion(dev, DEVIF_PKT);
|
||||
/* Perform any necessary conversions on outgoing packets */
|
||||
|
||||
/* Call back into the driver */
|
||||
devif_packet_conversion(dev, DEVIF_PKT);
|
||||
|
||||
bstop = callback(dev);
|
||||
/* Call back into the driver */
|
||||
|
||||
if (dev->d_len > 0)
|
||||
{
|
||||
bstop = callback(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bstop;
|
||||
|
@ -64,6 +64,16 @@ struct pkt_conn_s
|
||||
uint8_t ifindex;
|
||||
uint16_t proto;
|
||||
uint8_t crefs; /* Reference counts on this instance */
|
||||
|
||||
/* Read-ahead buffering.
|
||||
*
|
||||
* readahead - A singly linked list of type struct iob_qentry_s
|
||||
* where the PKT read-ahead data is retained.
|
||||
*
|
||||
* TODO: Maybe support PACKET_MMAP for further optimize.
|
||||
*/
|
||||
|
||||
struct iob_queue_s readahead; /* Read-ahead buffering */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
@ -231,7 +241,7 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||
* Select the network driver to use with the PKT transaction.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - PKT connection structure (not currently used).
|
||||
* conn - PKT connection structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* A pointer to the network driver to use.
|
||||
|
@ -210,7 +210,8 @@ FAR struct pkt_conn_s *pkt_active(FAR struct eth_hdr_s *buf)
|
||||
{
|
||||
/* FIXME lmac in conn should have been set by pkt_bind() */
|
||||
|
||||
if (eth_addr_cmp(buf->dest, conn->lmac))
|
||||
if (eth_addr_cmp(buf->dest, conn->lmac) ||
|
||||
eth_addr_cmp(buf->src, conn->lmac))
|
||||
{
|
||||
/* Matching connection found.. return a reference to it */
|
||||
|
||||
|
@ -41,7 +41,7 @@
|
||||
* Select the network driver to use with the PKT transaction.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - PKT connection structure (not currently used).
|
||||
* conn - PKT connection structure.
|
||||
*
|
||||
* Returned Value:
|
||||
* A pointer to the network driver to use.
|
||||
@ -50,9 +50,7 @@
|
||||
|
||||
FAR struct net_driver_s *pkt_find_device(FAR struct pkt_conn_s *conn)
|
||||
{
|
||||
/* REVISIT: This is bogus. A better network device lookup is needed. */
|
||||
|
||||
return netdev_findbyname("eth0");
|
||||
return netdev_findbyindex(conn->ifindex);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET && CONFIG_NET_PKT */
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/mm/iob.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
#include <nuttx/net/pkt.h>
|
||||
|
||||
@ -39,6 +40,66 @@
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_datahandler
|
||||
*
|
||||
* Description:
|
||||
* Handle packet that are not accepted by the application.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device instance only the input packet in d_buf, length = d_len;
|
||||
* conn - A pointer to the PKT connection structure
|
||||
*
|
||||
* Returned Value:
|
||||
* The number of bytes actually buffered is returned. This will be either
|
||||
* zero or equal to buflen; partial packets are not buffered.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint16_t pkt_datahandler(FAR struct net_driver_s *dev,
|
||||
FAR struct pkt_conn_s *conn)
|
||||
{
|
||||
FAR struct iob_s *iob = iob_tryalloc(true);
|
||||
int ret;
|
||||
|
||||
if (iob == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
ret = iob_clone_partial(dev->d_iob, dev->d_len, -NET_LL_HDRLEN(dev),
|
||||
iob, 0, true, false);
|
||||
if (ret < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to clone the I/O buffer chain: %d\n", ret);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Add the new I/O buffer chain to the tail of the read-ahead queue (again
|
||||
* without waiting).
|
||||
*/
|
||||
|
||||
if ((ret = iob_tryadd_queue(iob, &conn->readahead)) < 0)
|
||||
{
|
||||
nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
|
||||
goto errout;
|
||||
}
|
||||
else
|
||||
{
|
||||
ninfo("Buffered %d bytes\n", dev->d_len);
|
||||
return dev->d_len;
|
||||
}
|
||||
|
||||
errout:
|
||||
iob_free_chain(iob);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_in
|
||||
*
|
||||
@ -93,14 +154,17 @@ static int pkt_in(FAR struct net_driver_s *dev)
|
||||
|
||||
if ((flags & PKT_NEWDATA) != 0)
|
||||
{
|
||||
/* No.. the packet was not processed now. Return -EAGAIN so
|
||||
* that the driver may retry again later. We still need to
|
||||
* set d_len to zero so that the driver is aware that there
|
||||
* is nothing to be sent.
|
||||
*/
|
||||
/* Add the PKT to the socket read-ahead buffer. */
|
||||
|
||||
nwarn("WARNING: Packet not processed\n");
|
||||
ret = -EAGAIN;
|
||||
if (pkt_datahandler(dev, conn) == 0)
|
||||
{
|
||||
/* No.. the packet was not processed now. Return -EAGAIN so
|
||||
* that the driver may retry again later.
|
||||
*/
|
||||
|
||||
nwarn("WARNING: Packet not processed\n");
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -304,6 +304,57 @@ static ssize_t pkt_recvfrom_result(int result,
|
||||
return pstate->pr_recvlen;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pkt_readahead
|
||||
*
|
||||
* Description:
|
||||
* 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.
|
||||
*
|
||||
* Returned Value:
|
||||
* Number of bytes copied to the user buffer
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline ssize_t pkt_readahead(FAR struct pkt_conn_s *conn,
|
||||
FAR void *buf, size_t buflen)
|
||||
{
|
||||
FAR struct iob_s *iob;
|
||||
ssize_t ret = -ENODATA;
|
||||
|
||||
/* Check there is any packets already buffered in a read-ahead buffer. */
|
||||
|
||||
if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
|
||||
{
|
||||
DEBUGASSERT(iob->io_pktlen > 0);
|
||||
|
||||
/* Copy to user */
|
||||
|
||||
ret = iob_copyout(buf, iob, buflen, 0);
|
||||
|
||||
ninfo("Received %zd bytes (of %u)\n", ret, iob->io_pktlen);
|
||||
|
||||
/* Remove the I/O buffer chain from the head of the read-ahead
|
||||
* buffer queue.
|
||||
*/
|
||||
|
||||
iob_remove_queue(&conn->readahead);
|
||||
|
||||
/* And free the I/O buffer chain */
|
||||
|
||||
iob_free_chain(iob);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -370,59 +421,80 @@ ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
|
||||
*/
|
||||
|
||||
net_lock();
|
||||
pkt_recvfrom_initialize(psock, buf, len, from, fromlen, &state);
|
||||
|
||||
/* Get the device driver that will service this transfer */
|
||||
|
||||
dev = pkt_find_device(conn);
|
||||
if (dev == NULL)
|
||||
{
|
||||
ret = -ENODEV;
|
||||
goto errout_with_state;
|
||||
}
|
||||
|
||||
/* TODO pkt_recvfrom_initialize() expects from to be of type sockaddr_in,
|
||||
* but in our case is sockaddr_ll
|
||||
/* Check if there is buffered read-ahead data for this socket. We may have
|
||||
* already received the response to previous command.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
ret = pkt_connect(conn, NULL);
|
||||
if (ret < 0)
|
||||
if (!IOB_QEMPTY(&conn->readahead))
|
||||
{
|
||||
goto errout_with_state;
|
||||
ret = pkt_readahead(conn, buf, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set up the callback in the connection */
|
||||
|
||||
state.pr_cb = pkt_callback_alloc(dev, conn);
|
||||
if (state.pr_cb)
|
||||
else if (_SS_ISNONBLOCK(conn->sconn.s_flags) ||
|
||||
(flags & MSG_DONTWAIT) != 0)
|
||||
{
|
||||
state.pr_cb->flags = (PKT_NEWDATA | PKT_POLL);
|
||||
state.pr_cb->priv = (FAR void *)&state;
|
||||
state.pr_cb->event = pkt_recvfrom_eventhandler;
|
||||
/* Handle non-blocking PKT sockets */
|
||||
|
||||
/* Wait for either the receive to complete or for an error/timeout to
|
||||
* occur. NOTES: (1) net_sem_wait will also terminate if a signal
|
||||
* is received, (2) the network is locked! It will be un-locked while
|
||||
* the task sleeps and automatically re-locked when the task restarts.
|
||||
*/
|
||||
|
||||
ret = net_sem_wait(&state.pr_sem);
|
||||
|
||||
/* Make sure that no further events are processed */
|
||||
|
||||
pkt_callback_free(dev, conn, state.pr_cb);
|
||||
ret = pkt_recvfrom_result(ret, &state);
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EBUSY;
|
||||
}
|
||||
pkt_recvfrom_initialize(psock, buf, len, from, fromlen, &state);
|
||||
|
||||
/* Get the device driver that will service this transfer */
|
||||
|
||||
dev = pkt_find_device(conn);
|
||||
if (dev == NULL)
|
||||
{
|
||||
ret = -ENODEV;
|
||||
goto errout_with_state;
|
||||
}
|
||||
|
||||
/* TODO pkt_recvfrom_initialize() expects from to be of type
|
||||
* sockaddr_in, but in our case is sockaddr_ll
|
||||
*/
|
||||
|
||||
#if 0
|
||||
ret = pkt_connect(conn, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto errout_with_state;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set up the callback in the connection */
|
||||
|
||||
state.pr_cb = pkt_callback_alloc(dev, conn);
|
||||
if (state.pr_cb)
|
||||
{
|
||||
state.pr_cb->flags = (PKT_NEWDATA | PKT_POLL);
|
||||
state.pr_cb->priv = (FAR void *)&state;
|
||||
state.pr_cb->event = pkt_recvfrom_eventhandler;
|
||||
|
||||
/* Wait for either the receive to complete or for an error/timeout
|
||||
* to occur. NOTES: (1) net_sem_wait will also terminate if a
|
||||
* signal is received, (2) the network is locked! It will be
|
||||
* un-locked while the task sleeps and automatically re-locked when
|
||||
* the task restarts.
|
||||
*/
|
||||
|
||||
ret = net_sem_wait(&state.pr_sem);
|
||||
|
||||
/* Make sure that no further events are processed */
|
||||
|
||||
pkt_callback_free(dev, conn, state.pr_cb);
|
||||
ret = pkt_recvfrom_result(ret, &state);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EBUSY;
|
||||
}
|
||||
|
||||
errout_with_state:
|
||||
pkt_recvfrom_uninitialize(&state);
|
||||
}
|
||||
|
||||
net_unlock();
|
||||
pkt_recvfrom_uninitialize(&state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -305,7 +305,11 @@ static int pkt_close(FAR struct socket *psock)
|
||||
|
||||
if (conn->crefs <= 1)
|
||||
{
|
||||
/* Yes... free the connection structure */
|
||||
/* Yes... free any read-ahead data */
|
||||
|
||||
iob_free_queue(&conn->readahead);
|
||||
|
||||
/* Then free the connection structure */
|
||||
|
||||
conn->crefs = 0; /* No more references on the connection */
|
||||
pkt_free(psock->s_conn); /* Free network resources */
|
||||
|
Loading…
Reference in New Issue
Block a user