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:
parent
5c80b94820
commit
e9bc32cdbc
@ -134,12 +134,13 @@ struct tun_device_s
|
||||
{
|
||||
bool bifup; /* true:ifup false:ifdown */
|
||||
bool read_wait;
|
||||
bool write_wait;
|
||||
WDOG_ID txpoll; /* TX poll timer */
|
||||
struct work_s work; /* For deferring poll work to the work queue */
|
||||
FAR struct file *filep;
|
||||
FAR struct pollfd *poll_fds;
|
||||
sem_t waitsem;
|
||||
sem_t read_wait_sem;
|
||||
sem_t write_wait_sem;
|
||||
size_t read_d_len;
|
||||
size_t write_d_len;
|
||||
|
||||
@ -170,7 +171,7 @@ static void tun_unlock(FAR struct tun_device_s *priv);
|
||||
|
||||
/* 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);
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
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_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
|
||||
#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);
|
||||
static int tun_dev_uninit(FAR struct tun_device_s *priv);
|
||||
static void tun_dev_uninit(FAR struct tun_device_s *priv);
|
||||
|
||||
/* File interface */
|
||||
|
||||
@ -291,6 +290,18 @@ static void tun_pollnotify(FAR struct tun_device_s *priv,
|
||||
{
|
||||
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)
|
||||
{
|
||||
return;
|
||||
@ -316,7 +327,7 @@ static void tun_pollnotify(FAR struct tun_device_s *priv,
|
||||
* priv - Reference to the driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success; a negated errno on failure
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* 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);
|
||||
|
||||
/* 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);
|
||||
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
|
||||
* been examined.
|
||||
/* If zero is returned, the polling will continue until all connections
|
||||
* have been examined.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
@ -589,33 +587,6 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
|
||||
|
||||
arp_ipin(&priv->dev);
|
||||
ipv4_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_IPv6
|
||||
if (IFF_IS_IPv4(priv->dev.d_flags))
|
||||
#endif
|
||||
{
|
||||
arp_out(&priv->dev);
|
||||
}
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
else
|
||||
{
|
||||
neighbor_out(&priv->dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* And send the packet */
|
||||
|
||||
priv->write_d_len = priv->dev.d_len;
|
||||
tun_fd_transmit(priv);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -628,31 +599,6 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
|
||||
/* 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
|
||||
@ -670,12 +616,41 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
|
||||
{
|
||||
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
|
||||
* 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_IPv6
|
||||
if (IFF_IS_IPv4(priv->dev.d_flags))
|
||||
#endif
|
||||
{
|
||||
arp_out(&priv->dev);
|
||||
}
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
else
|
||||
{
|
||||
neighbor_out(&priv->dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* And send the packet */
|
||||
|
||||
priv->write_d_len = priv->dev.d_len;
|
||||
tun_fd_transmit(priv);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -889,16 +864,6 @@ static int tun_ifup(FAR struct net_driver_s *dev)
|
||||
dev->d_ipv6addr[6], dev->d_ipv6addr[7]);
|
||||
#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 */
|
||||
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
@ -1134,16 +1100,18 @@ static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
|
||||
|
||||
nxsem_init(&priv->waitsem, 0, 1);
|
||||
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
|
||||
* priority inheritance enabled.
|
||||
*/
|
||||
|
||||
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 */
|
||||
|
||||
priv->txpoll = wd_create(); /* Create periodic poll timer */
|
||||
priv->txpoll = wd_create(); /* Create periodic poll timer */
|
||||
|
||||
/* Assign d_ifname if specified. */
|
||||
|
||||
@ -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->read_wait_sem);
|
||||
nxsem_destroy(&priv->write_wait_sem);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1172,7 +1139,7 @@ static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
|
||||
* 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 */
|
||||
|
||||
@ -1184,8 +1151,7 @@ static int tun_dev_uninit(FAR struct tun_device_s *priv)
|
||||
|
||||
nxsem_destroy(&priv->waitsem);
|
||||
nxsem_destroy(&priv->read_wait_sem);
|
||||
|
||||
return OK;
|
||||
nxsem_destroy(&priv->write_wait_sem);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -1195,7 +1161,6 @@ static int tun_dev_uninit(FAR struct tun_device_s *priv)
|
||||
static int tun_open(FAR struct file *filep)
|
||||
{
|
||||
filep->f_priv = 0;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -1222,7 +1187,6 @@ static int tun_close(FAR struct file *filep)
|
||||
tun_dev_uninit(priv);
|
||||
|
||||
tundev_unlock(tun);
|
||||
|
||||
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;
|
||||
ssize_t ret;
|
||||
|
||||
if (priv == NULL)
|
||||
if (priv == NULL || buflen > CONFIG_NET_TUN_PKTSIZE)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tun_lock(priv);
|
||||
|
||||
if (priv->write_d_len > 0)
|
||||
for (; ; )
|
||||
{
|
||||
/* Check if there are free space to write */
|
||||
|
||||
if (priv->write_d_len == 0)
|
||||
{
|
||||
memcpy(priv->write_buf, buffer, buflen);
|
||||
|
||||
net_lock();
|
||||
priv->dev.d_buf = priv->write_buf;
|
||||
priv->dev.d_len = buflen;
|
||||
|
||||
tun_net_receive(priv);
|
||||
net_unlock();
|
||||
|
||||
ret = buflen;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wait if there are no free space to write */
|
||||
|
||||
if ((filep->f_oflags & O_NONBLOCK) != 0)
|
||||
{
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
priv->write_wait = true;
|
||||
tun_unlock(priv);
|
||||
return -EBUSY;
|
||||
nxsem_wait(&priv->write_wait_sem);
|
||||
tun_lock(priv);
|
||||
}
|
||||
|
||||
net_lock();
|
||||
|
||||
if (buflen > CONFIG_NET_TUN_PKTSIZE)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(priv->write_buf, buffer, buflen);
|
||||
|
||||
priv->dev.d_buf = priv->write_buf;
|
||||
priv->dev.d_len = buflen;
|
||||
|
||||
tun_net_receive(priv);
|
||||
|
||||
ret = (ssize_t)buflen;
|
||||
}
|
||||
|
||||
net_unlock();
|
||||
tun_unlock(priv);
|
||||
|
||||
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;
|
||||
ssize_t ret;
|
||||
size_t write_d_len;
|
||||
size_t read_d_len;
|
||||
|
||||
if (priv == NULL)
|
||||
{
|
||||
@ -1292,33 +1261,53 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
|
||||
|
||||
tun_lock(priv);
|
||||
|
||||
/* Check if there are data to read in write buffer */
|
||||
|
||||
write_d_len = priv->write_d_len;
|
||||
if (write_d_len > 0)
|
||||
for (; ; )
|
||||
{
|
||||
if (buflen < write_d_len)
|
||||
/* Check if there are data to read in write buffer */
|
||||
|
||||
if (priv->write_d_len > 0)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
if (buflen < priv->write_d_len)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(buffer, priv->write_buf, priv->write_d_len);
|
||||
ret = priv->write_d_len;
|
||||
priv->write_d_len = 0;
|
||||
|
||||
NETDEV_TXDONE(&priv->dev);
|
||||
tun_pollnotify(priv, POLLOUT);
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(buffer, priv->write_buf, write_d_len);
|
||||
ret = (ssize_t)write_d_len;
|
||||
/* Check if there are data to read in read buffer */
|
||||
|
||||
priv->write_d_len = 0;
|
||||
NETDEV_TXDONE(&priv->dev);
|
||||
tun_pollnotify(priv, POLLOUT);
|
||||
if (priv->read_d_len > 0)
|
||||
{
|
||||
if (buflen < priv->read_d_len)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
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 (priv->read_d_len == 0)
|
||||
{
|
||||
if ((filep->f_oflags & O_NONBLOCK) != 0)
|
||||
{
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
|
||||
priv->read_wait = true;
|
||||
@ -1327,27 +1316,7 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
|
||||
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);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1410,7 +1379,6 @@ int tun_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
|
||||
|
||||
errout:
|
||||
tun_unlock(priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user