mirror of
https://github.com/apache/nuttx.git
synced 2026-06-02 01:21:26 +08:00
Improve tun (#198)
* Remove the code duplication in tun_net_receive_tap and remove the unused filep field * Shouldn't return -EBUSY in tun_write. Let the caller wait until the write buffer free * Handle that write buffer is ready first correctly in tun_read * Remove the unused tun_ipv6multicast
This commit is contained in:
+120
-152
@@ -134,12 +134,13 @@ struct tun_device_s
|
|||||||
{
|
{
|
||||||
bool bifup; /* true:ifup false:ifdown */
|
bool bifup; /* true:ifup false:ifdown */
|
||||||
bool read_wait;
|
bool read_wait;
|
||||||
|
bool write_wait;
|
||||||
WDOG_ID txpoll; /* TX poll timer */
|
WDOG_ID txpoll; /* TX poll timer */
|
||||||
struct work_s work; /* For deferring poll work to the work queue */
|
struct work_s work; /* For deferring poll work to the work queue */
|
||||||
FAR struct file *filep;
|
|
||||||
FAR struct pollfd *poll_fds;
|
FAR struct pollfd *poll_fds;
|
||||||
sem_t waitsem;
|
sem_t waitsem;
|
||||||
sem_t read_wait_sem;
|
sem_t read_wait_sem;
|
||||||
|
sem_t write_wait_sem;
|
||||||
size_t read_d_len;
|
size_t read_d_len;
|
||||||
size_t write_d_len;
|
size_t write_d_len;
|
||||||
|
|
||||||
@@ -170,7 +171,7 @@ static void tun_unlock(FAR struct tun_device_s *priv);
|
|||||||
|
|
||||||
/* Common TX logic */
|
/* Common TX logic */
|
||||||
|
|
||||||
static int tun_fd_transmit(FAR struct tun_device_s *priv);
|
static void tun_fd_transmit(FAR struct tun_device_s *priv);
|
||||||
static int tun_txpoll(FAR struct net_driver_s *dev);
|
static int tun_txpoll(FAR struct net_driver_s *dev);
|
||||||
#ifdef CONFIG_NET_ETHERNET
|
#ifdef CONFIG_NET_ETHERNET
|
||||||
static int tun_txpoll_tap(FAR struct net_driver_s *dev);
|
static int tun_txpoll_tap(FAR struct net_driver_s *dev);
|
||||||
@@ -201,13 +202,11 @@ static int tun_txavail(FAR struct net_driver_s *dev);
|
|||||||
static int tun_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
|
static int tun_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
|
||||||
static int tun_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
|
static int tun_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_NET_ICMPv6
|
|
||||||
static void tun_ipv6multicast(FAR struct tun_device_s *priv);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
|
static int tun_dev_init(FAR struct tun_device_s *priv,
|
||||||
|
FAR struct file *filep,
|
||||||
FAR const char *devfmt, bool tun);
|
FAR const char *devfmt, bool tun);
|
||||||
static int tun_dev_uninit(FAR struct tun_device_s *priv);
|
static void tun_dev_uninit(FAR struct tun_device_s *priv);
|
||||||
|
|
||||||
/* File interface */
|
/* File interface */
|
||||||
|
|
||||||
@@ -291,6 +290,18 @@ static void tun_pollnotify(FAR struct tun_device_s *priv,
|
|||||||
{
|
{
|
||||||
FAR struct pollfd *fds = priv->poll_fds;
|
FAR struct pollfd *fds = priv->poll_fds;
|
||||||
|
|
||||||
|
if (priv->read_wait && (eventset & POLLIN))
|
||||||
|
{
|
||||||
|
priv->read_wait = false;
|
||||||
|
nxsem_post(&priv->read_wait_sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->write_wait && (eventset & POLLOUT))
|
||||||
|
{
|
||||||
|
priv->write_wait = false;
|
||||||
|
nxsem_post(&priv->write_wait_sem);
|
||||||
|
}
|
||||||
|
|
||||||
if (fds == NULL)
|
if (fds == NULL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -316,7 +327,7 @@ static void tun_pollnotify(FAR struct tun_device_s *priv,
|
|||||||
* priv - Reference to the driver state structure
|
* priv - Reference to the driver state structure
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* OK on success; a negated errno on failure
|
* None
|
||||||
*
|
*
|
||||||
* Assumptions:
|
* Assumptions:
|
||||||
* May or may not be called from an interrupt handler. In either case,
|
* May or may not be called from an interrupt handler. In either case,
|
||||||
@@ -325,23 +336,10 @@ static void tun_pollnotify(FAR struct tun_device_s *priv,
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int tun_fd_transmit(FAR struct tun_device_s *priv)
|
static void tun_fd_transmit(FAR struct tun_device_s *priv)
|
||||||
{
|
{
|
||||||
NETDEV_TXPACKETS(&priv->dev);
|
NETDEV_TXPACKETS(&priv->dev);
|
||||||
|
|
||||||
/* Verify that the hardware is ready to send another packet. If we get
|
|
||||||
* here, then we are committed to sending a packet; Higher level logic
|
|
||||||
* must have assured that there is no transmission in progress.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (priv->read_wait)
|
|
||||||
{
|
|
||||||
priv->read_wait = false;
|
|
||||||
nxsem_post(&priv->read_wait_sem);
|
|
||||||
}
|
|
||||||
|
|
||||||
tun_pollnotify(priv, POLLIN);
|
tun_pollnotify(priv, POLLIN);
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -452,8 +450,8 @@ static int tun_txpoll_tap(FAR struct net_driver_s *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If zero is returned, the polling will continue until all connections have
|
/* If zero is returned, the polling will continue until all connections
|
||||||
* been examined.
|
* have been examined.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -589,6 +587,44 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
|
|||||||
|
|
||||||
arp_ipin(&priv->dev);
|
arp_ipin(&priv->dev);
|
||||||
ipv4_input(&priv->dev);
|
ipv4_input(&priv->dev);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_NET_IPv6
|
||||||
|
if (BUF->type == HTONS(ETHTYPE_IP6))
|
||||||
|
{
|
||||||
|
ninfo("Iv6 frame\n");
|
||||||
|
NETDEV_RXIPV6(&priv->dev);
|
||||||
|
|
||||||
|
/* Give the IPv6 packet to the network layer. */
|
||||||
|
|
||||||
|
ipv6_input(&priv->dev);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_NET_ARP
|
||||||
|
if (BUF->type == htons(ETHTYPE_ARP))
|
||||||
|
{
|
||||||
|
arp_arpin(&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
|
||||||
|
{
|
||||||
|
NETDEV_RXDROPPED(&priv->dev);
|
||||||
|
priv->dev.d_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* If the above function invocation resulted in data that should be
|
/* 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.
|
* sent out on the network, the field d_len will set to a value > 0.
|
||||||
@@ -617,67 +653,6 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
|
|||||||
tun_fd_transmit(priv);
|
tun_fd_transmit(priv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_NET_IPv6
|
|
||||||
if (BUF->type == HTONS(ETHTYPE_IP6))
|
|
||||||
{
|
|
||||||
ninfo("Iv6 frame\n");
|
|
||||||
NETDEV_RXIPV6(&priv->dev);
|
|
||||||
|
|
||||||
/* Give the IPv6 packet to the network layer. */
|
|
||||||
|
|
||||||
ipv6_input(&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)
|
|
||||||
{
|
|
||||||
/* Update the Ethernet header with the correct MAC address */
|
|
||||||
|
|
||||||
#ifdef CONFIG_NET_IPv4
|
|
||||||
if (IFF_IS_IPv4(priv->dev.d_flags))
|
|
||||||
{
|
|
||||||
arp_out(&priv->dev);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_NET_IPv6
|
|
||||||
{
|
|
||||||
neighbor_out(&priv->dev);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
priv->write_d_len = priv->dev.d_len;
|
|
||||||
tun_fd_transmit(priv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_NET_ARP
|
|
||||||
if (BUF->type == htons(ETHTYPE_ARP))
|
|
||||||
{
|
|
||||||
arp_arpin(&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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
NETDEV_RXDROPPED(&priv->dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -889,16 +864,6 @@ static int tun_ifup(FAR struct net_driver_s *dev)
|
|||||||
dev->d_ipv6addr[6], dev->d_ipv6addr[7]);
|
dev->d_ipv6addr[6], dev->d_ipv6addr[7]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Initialize PHYs, the Ethernet interface, and setup up Ethernet interrupts */
|
|
||||||
|
|
||||||
/* Instantiate the MAC address from priv->dev.d_mac.ether.ether_addr_octet */
|
|
||||||
|
|
||||||
#ifdef CONFIG_NET_ICMPv6
|
|
||||||
/* Set up IPv6 multicast address filtering */
|
|
||||||
|
|
||||||
tun_ipv6multicast(priv);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Set and activate a timer process */
|
/* Set and activate a timer process */
|
||||||
|
|
||||||
wd_start(priv->txpoll, TUN_WDDELAY, tun_poll_expiry,
|
wd_start(priv->txpoll, TUN_WDDELAY, tun_poll_expiry,
|
||||||
@@ -1113,7 +1078,8 @@ static void tun_ipv6multicast(FAR struct tun_device_s *priv)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
|
static int tun_dev_init(FAR struct tun_device_s *priv,
|
||||||
|
FAR struct file *filep,
|
||||||
FAR const char *devfmt, bool tun)
|
FAR const char *devfmt, bool tun)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@@ -1134,12 +1100,14 @@ static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
|
|||||||
|
|
||||||
nxsem_init(&priv->waitsem, 0, 1);
|
nxsem_init(&priv->waitsem, 0, 1);
|
||||||
nxsem_init(&priv->read_wait_sem, 0, 0);
|
nxsem_init(&priv->read_wait_sem, 0, 0);
|
||||||
|
nxsem_init(&priv->write_wait_sem, 0, 0);
|
||||||
|
|
||||||
/* The wait semaphore is used for signaling and, hence, should not have
|
/* The wait semaphore is used for signaling and, hence, should not have
|
||||||
* priority inheritance enabled.
|
* priority inheritance enabled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
nxsem_setprotocol(&priv->read_wait_sem, SEM_PRIO_NONE);
|
nxsem_setprotocol(&priv->read_wait_sem, SEM_PRIO_NONE);
|
||||||
|
nxsem_setprotocol(&priv->write_wait_sem, SEM_PRIO_NONE);
|
||||||
|
|
||||||
/* Create a watchdog for timing polling for and timing of transmissions */
|
/* Create a watchdog for timing polling for and timing of transmissions */
|
||||||
|
|
||||||
@@ -1159,12 +1127,11 @@ static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
|
|||||||
{
|
{
|
||||||
nxsem_destroy(&priv->waitsem);
|
nxsem_destroy(&priv->waitsem);
|
||||||
nxsem_destroy(&priv->read_wait_sem);
|
nxsem_destroy(&priv->read_wait_sem);
|
||||||
|
nxsem_destroy(&priv->write_wait_sem);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->filep = filep; /* Set link to file */
|
|
||||||
filep->f_priv = priv; /* Set link to TUN device */
|
filep->f_priv = priv; /* Set link to TUN device */
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1172,7 +1139,7 @@ static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
|
|||||||
* Name: tun_dev_uninit
|
* Name: tun_dev_uninit
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int tun_dev_uninit(FAR struct tun_device_s *priv)
|
static void tun_dev_uninit(FAR struct tun_device_s *priv)
|
||||||
{
|
{
|
||||||
/* Put the interface in the down state */
|
/* Put the interface in the down state */
|
||||||
|
|
||||||
@@ -1184,8 +1151,7 @@ static int tun_dev_uninit(FAR struct tun_device_s *priv)
|
|||||||
|
|
||||||
nxsem_destroy(&priv->waitsem);
|
nxsem_destroy(&priv->waitsem);
|
||||||
nxsem_destroy(&priv->read_wait_sem);
|
nxsem_destroy(&priv->read_wait_sem);
|
||||||
|
nxsem_destroy(&priv->write_wait_sem);
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -1195,7 +1161,6 @@ static int tun_dev_uninit(FAR struct tun_device_s *priv)
|
|||||||
static int tun_open(FAR struct file *filep)
|
static int tun_open(FAR struct file *filep)
|
||||||
{
|
{
|
||||||
filep->f_priv = 0;
|
filep->f_priv = 0;
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1222,7 +1187,6 @@ static int tun_close(FAR struct file *filep)
|
|||||||
tun_dev_uninit(priv);
|
tun_dev_uninit(priv);
|
||||||
|
|
||||||
tundev_unlock(tun);
|
tundev_unlock(tun);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1236,40 +1200,47 @@ static ssize_t tun_write(FAR struct file *filep, FAR const char *buffer,
|
|||||||
FAR struct tun_device_s *priv = filep->f_priv;
|
FAR struct tun_device_s *priv = filep->f_priv;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
if (priv == NULL)
|
if (priv == NULL || buflen > CONFIG_NET_TUN_PKTSIZE)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tun_lock(priv);
|
tun_lock(priv);
|
||||||
|
|
||||||
if (priv->write_d_len > 0)
|
for (; ; )
|
||||||
{
|
{
|
||||||
tun_unlock(priv);
|
/* Check if there are free space to write */
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
net_lock();
|
if (priv->write_d_len == 0)
|
||||||
|
|
||||||
if (buflen > CONFIG_NET_TUN_PKTSIZE)
|
|
||||||
{
|
|
||||||
ret = -EINVAL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
memcpy(priv->write_buf, buffer, buflen);
|
memcpy(priv->write_buf, buffer, buflen);
|
||||||
|
|
||||||
|
net_lock();
|
||||||
priv->dev.d_buf = priv->write_buf;
|
priv->dev.d_buf = priv->write_buf;
|
||||||
priv->dev.d_len = buflen;
|
priv->dev.d_len = buflen;
|
||||||
|
|
||||||
tun_net_receive(priv);
|
tun_net_receive(priv);
|
||||||
|
net_unlock();
|
||||||
|
|
||||||
ret = (ssize_t)buflen;
|
ret = buflen;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
net_unlock();
|
/* Wait if there are no free space to write */
|
||||||
tun_unlock(priv);
|
|
||||||
|
|
||||||
|
if ((filep->f_oflags & O_NONBLOCK) != 0)
|
||||||
|
{
|
||||||
|
ret = -EAGAIN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->write_wait = true;
|
||||||
|
tun_unlock(priv);
|
||||||
|
nxsem_wait(&priv->write_wait_sem);
|
||||||
|
tun_lock(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
tun_unlock(priv);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1282,8 +1253,6 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
|
|||||||
{
|
{
|
||||||
FAR struct tun_device_s *priv = filep->f_priv;
|
FAR struct tun_device_s *priv = filep->f_priv;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
size_t write_d_len;
|
|
||||||
size_t read_d_len;
|
|
||||||
|
|
||||||
if (priv == NULL)
|
if (priv == NULL)
|
||||||
{
|
{
|
||||||
@@ -1292,33 +1261,53 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
|
|||||||
|
|
||||||
tun_lock(priv);
|
tun_lock(priv);
|
||||||
|
|
||||||
|
for (; ; )
|
||||||
|
{
|
||||||
/* Check if there are data to read in write buffer */
|
/* Check if there are data to read in write buffer */
|
||||||
|
|
||||||
write_d_len = priv->write_d_len;
|
if (priv->write_d_len > 0)
|
||||||
if (write_d_len > 0)
|
|
||||||
{
|
{
|
||||||
if (buflen < write_d_len)
|
if (buflen < priv->write_d_len)
|
||||||
{
|
{
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buffer, priv->write_buf, write_d_len);
|
memcpy(buffer, priv->write_buf, priv->write_d_len);
|
||||||
ret = (ssize_t)write_d_len;
|
ret = priv->write_d_len;
|
||||||
|
|
||||||
priv->write_d_len = 0;
|
priv->write_d_len = 0;
|
||||||
|
|
||||||
NETDEV_TXDONE(&priv->dev);
|
NETDEV_TXDONE(&priv->dev);
|
||||||
tun_pollnotify(priv, POLLOUT);
|
tun_pollnotify(priv, POLLOUT);
|
||||||
|
break;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->read_d_len == 0)
|
/* Check if there are data to read in read buffer */
|
||||||
|
|
||||||
|
if (priv->read_d_len > 0)
|
||||||
{
|
{
|
||||||
|
if (buflen < priv->read_d_len)
|
||||||
|
{
|
||||||
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer, priv->read_buf, priv->read_d_len);
|
||||||
|
ret = priv->read_d_len;
|
||||||
|
priv->read_d_len = 0;
|
||||||
|
|
||||||
|
net_lock();
|
||||||
|
tun_txdone(priv);
|
||||||
|
net_unlock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait if there are no data to read */
|
||||||
|
|
||||||
if ((filep->f_oflags & O_NONBLOCK) != 0)
|
if ((filep->f_oflags & O_NONBLOCK) != 0)
|
||||||
{
|
{
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
goto out;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->read_wait = true;
|
priv->read_wait = true;
|
||||||
@@ -1327,27 +1316,7 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
|
|||||||
tun_lock(priv);
|
tun_lock(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
net_lock();
|
|
||||||
|
|
||||||
read_d_len = priv->read_d_len;
|
|
||||||
if (buflen < read_d_len)
|
|
||||||
{
|
|
||||||
ret = -EINVAL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(buffer, priv->read_buf, read_d_len);
|
|
||||||
ret = (ssize_t)read_d_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->read_d_len = 0;
|
|
||||||
tun_txdone(priv);
|
|
||||||
|
|
||||||
net_unlock();
|
|
||||||
|
|
||||||
out:
|
|
||||||
tun_unlock(priv);
|
tun_unlock(priv);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1410,7 +1379,6 @@ int tun_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
|
|||||||
|
|
||||||
errout:
|
errout:
|
||||||
tun_unlock(priv);
|
tun_unlock(priv);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user