net/tun: Change TUN/TAP to use IOB

TUN/TAP is not working after IOB offload, try to fix.

Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
Zhe Weng 2023-01-10 20:03:02 +08:00 committed by Xiang Xiao
parent be89bcc044
commit ff68d9ac04
1 changed files with 49 additions and 28 deletions

View File

@ -61,6 +61,8 @@
#include <nuttx/irq.h>
#include <nuttx/mutex.h>
#include <nuttx/wqueue.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/net.h>
#include <nuttx/net/netdev.h>
#include <nuttx/net/ethernet.h>
#include <nuttx/net/tun.h>
@ -98,12 +100,6 @@
# define CONFIG_TUN_NINTERFACES 1
#endif
/* Make sure that packet buffers include in configured guard size and are an
* even multiple of 16-bits in length.
*/
#define NET_TUN_PKTSIZE ((CONFIG_NET_TUN_PKTSIZE + CONFIG_NET_GUARDSIZE + 1) & ~1)
/* This is a helper pointer for accessing the contents of the Ethernet
* header.
*/
@ -137,8 +133,8 @@ struct tun_device_s
* is assured only by the preceding wide data types.
*/
uint8_t read_buf[NET_TUN_PKTSIZE];
uint8_t write_buf[NET_TUN_PKTSIZE];
FAR struct iob_s *read_buf;
FAR struct iob_s *write_buf;
/* This holds the information visible to the NuttX network */
@ -310,8 +306,14 @@ static void tun_fd_transmit(FAR struct tun_device_s *priv)
static int tun_txpoll(FAR struct net_driver_s *dev)
{
FAR struct tun_device_s *priv = (FAR struct tun_device_s *)dev->d_private;
int ret;
DEBUGASSERT(priv->read_buf == NULL);
priv->read_d_len = dev->d_len;
priv->read_buf = dev->d_iob;
netdev_iob_clear(dev);
#ifdef CONFIG_NET_ETHERNET
if (dev->d_lltype == NET_LL_ETHERNET)
{
@ -358,7 +360,6 @@ static int tun_txpoll_tap(FAR struct net_driver_s *dev)
/* Send the packet */
priv->read_d_len = priv->dev.d_len;
tun_fd_transmit(priv);
return 1;
@ -394,7 +395,6 @@ static int tun_txpoll_tun(FAR struct net_driver_s *dev)
{
FAR struct tun_device_s *priv = (FAR struct tun_device_s *)dev->d_private;
priv->read_d_len = priv->dev.d_len;
tun_fd_transmit(priv);
return 1;
@ -495,17 +495,6 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
{
arp_input(&priv->dev);
NETDEV_RXARP(&priv->dev);
/* If the above function invocation resulted in data that should be
* sent out on the network, the field d_len will set to a value > 0.
*/
if (priv->dev.d_len > 0)
{
priv->write_d_len = priv->dev.d_len;
tun_fd_transmit(priv);
priv->dev.d_len = 0;
}
}
else
#endif
@ -522,7 +511,10 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
{
/* And send the packet */
DEBUGASSERT(priv->write_buf == NULL);
priv->write_d_len = priv->dev.d_len;
priv->write_buf = priv->dev.d_iob;
netdev_iob_clear(&priv->dev);
tun_fd_transmit(priv);
}
}
@ -599,7 +591,10 @@ static void tun_net_receive_tun(FAR struct tun_device_s *priv)
if (dev->d_len > 0)
{
DEBUGASSERT(priv->write_buf == NULL);
priv->write_d_len = dev->d_len;
priv->write_buf = dev->d_iob;
netdev_iob_clear(dev);
tun_fd_transmit(priv);
}
}
@ -629,7 +624,6 @@ static void tun_txdone(FAR struct tun_device_s *priv)
/* Then poll the network for new XMIT data */
priv->dev.d_buf = priv->read_buf;
devif_poll(&priv->dev, tun_txpoll);
}
@ -751,7 +745,6 @@ static void tun_txavail_work(FAR void *arg)
{
/* Poll the network for new XMIT data */
priv->dev.d_buf = priv->read_buf;
devif_poll(&priv->dev, tun_txpoll);
}
@ -965,6 +958,7 @@ static ssize_t tun_write(FAR struct file *filep, FAR const char *buffer,
{
FAR struct tun_device_s *priv = filep->f_priv;
ssize_t nwritten = 0;
uint8_t llhdrlen;
int ret;
if (priv == NULL || buflen > CONFIG_NET_TUN_PKTSIZE)
@ -972,6 +966,8 @@ static ssize_t tun_write(FAR struct file *filep, FAR const char *buffer,
return -EINVAL;
}
llhdrlen = NET_LL_HDRLEN(&priv->dev);
for (; ; )
{
/* Write must return immediately if interrupted by a signal (or if the
@ -988,10 +984,24 @@ static ssize_t tun_write(FAR struct file *filep, FAR const char *buffer,
if (priv->write_d_len == 0)
{
memcpy(priv->write_buf, buffer, buflen);
net_lock();
priv->dev.d_buf = priv->write_buf;
ret = netdev_iob_prepare(&priv->dev, false, 0);
if (ret < 0)
{
nwritten = (nwritten == 0) ? ret : nwritten;
net_unlock();
break;
}
ret = iob_trycopyin(priv->dev.d_iob, (FAR const uint8_t *)buffer,
buflen, -llhdrlen, false);
if (ret < 0)
{
nwritten = (nwritten == 0) ? ret : nwritten;
net_unlock();
break;
}
priv->dev.d_len = buflen;
tun_net_receive(priv);
@ -1027,6 +1037,7 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
{
FAR struct tun_device_s *priv = filep->f_priv;
ssize_t nread = 0;
uint8_t llhdrlen;
int ret;
if (priv == NULL)
@ -1034,6 +1045,8 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
return -EINVAL;
}
llhdrlen = NET_LL_HDRLEN(&priv->dev);
for (; ; )
{
/* Read must return immediately if interrupted by a signal (or if the
@ -1056,8 +1069,12 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
break;
}
memcpy(buffer, priv->write_buf, priv->write_d_len);
iob_copyout((FAR uint8_t *)buffer, priv->write_buf,
priv->write_d_len, -llhdrlen);
nread = priv->write_d_len;
iob_free_chain(priv->write_buf);
priv->write_buf = NULL;
priv->write_d_len = 0;
NETDEV_TXDONE(&priv->dev);
@ -1075,8 +1092,12 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
break;
}
memcpy(buffer, priv->read_buf, priv->read_d_len);
iob_copyout((FAR uint8_t *)buffer, priv->read_buf,
priv->read_d_len, -llhdrlen);
nread = priv->read_d_len;
iob_free_chain(priv->read_buf);
priv->read_buf = NULL;
priv->read_d_len = 0;
net_lock();