drivers/net/tun.c: Call ipv[4|6]_input dynamically by checking packet header and remove the code duplication

This commit is contained in:
Xiang Xiao 2018-11-09 09:50:10 -06:00 committed by Gregory Nutt
parent 3f1b6543db
commit 8193c28e91

View File

@ -74,6 +74,7 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* If processing is not done at the interrupt level, then high priority
* work queue support is required.
*/
@ -111,6 +112,11 @@
# define BUF ((struct eth_hdr_s *)priv->dev.d_buf)
#endif
/* This is a helper pointer for accessing the contents of the ip header */
#define IPv4BUF ((struct ipv4_hdr_s *)(priv->dev.d_buf + priv->dev.d_llhdrlen))
#define IPv6BUF ((struct ipv6_hdr_s *)(priv->dev.d_buf + priv->dev.d_llhdrlen))
/****************************************************************************
* Private Types
****************************************************************************/
@ -196,8 +202,8 @@ static int tun_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
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, FAR const char *devfmt);
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);
/* File interface */
@ -329,7 +335,7 @@ static void tun_pollnotify(FAR struct tun_device_s *priv, pollevent_t eventset)
#endif
/****************************************************************************
* Name: tun_transmit
* Name: tun_fd_transmit
*
* Description:
* Start hardware transmission. Called either from the txdone interrupt
@ -451,29 +457,28 @@ static int tun_txpoll_tap(struct net_driver_s *dev)
*/
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (IFF_IS_IPv4(priv->dev.d_flags))
#endif
{
arp_out(&priv->dev);
}
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
if (IFF_IS_IPv6(priv->dev.d_flags))
{
neighbor_out(&priv->dev);
}
#endif /* CONFIG_NET_IPv6 */
/* Send the packet */
if (!devif_loopback(dev))
{
/* Send the packet */
priv->read_d_len = priv->dev.d_len;
tun_fd_transmit(priv);
priv->read_d_len = priv->dev.d_len;
tun_fd_transmit(priv);
return 1;
return 1;
}
}
/* If zero is returned, the polling will continue until all connections have
@ -519,12 +524,15 @@ static int tun_txpoll_tun(struct net_driver_s *dev)
if (priv->dev.d_len > 0)
{
/* Send the packet */
if (!devif_loopback(dev))
{
/* Send the packet */
priv->read_d_len = priv->dev.d_len;
tun_fd_transmit(priv);
priv->read_d_len = priv->dev.d_len;
tun_fd_transmit(priv);
return 1;
return 1;
}
}
/* If zero is returned, the polling will continue until all connections have
@ -585,8 +593,6 @@ static void tun_net_receive(FAR struct tun_device_s *priv)
#ifdef CONFIG_NET_ETHERNET
static void tun_net_receive_tap(FAR struct tun_device_s *priv)
{
int ret;
/* Copy the data data from the hardware to priv->dev.d_buf. Set amount of
* data in priv->dev.d_len
*/
@ -607,53 +613,10 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
ninfo("IPv4 frame\n");
NETDEV_RXIPV4(&priv->dev);
/* Give the IPv4 packet to the network layer. ipv4_input will return
* an error if it is unable to dispatch the packet at this time.
*/
/* Give the IPv4 packet to the network layer. */
arp_ipin(&priv->dev);
ret = ipv4_input(&priv->dev);
if (ret == OK)
{
/* 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
{
tun_pollnotify(priv, POLLOUT);
}
}
else
{
priv->dev.d_len = 0;
tun_pollnotify(priv, POLLOUT);
}
ipv4_input(&priv->dev);
}
else
#endif
@ -663,44 +626,9 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
ninfo("Iv6 frame\n");
NETDEV_RXIPV6(&priv->dev);
/* Give the IPv6 packet to the network layer. ipv6_input will return
* an error if it is unable to dispatch the packet at this time.
*/
/* Give the IPv6 packet to the network layer. */
ret = ipv6_input(&priv->dev);
if (ret == OK)
{
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
{
tun_pollnotify(priv, POLLOUT);
}
}
else
{
priv->write_d_len = 0;
tun_pollnotify(priv, POLLOUT);
}
ipv6_input(&priv->dev);
}
else
#endif
@ -709,23 +637,40 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
{
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);
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_IPv4
if (IFF_IS_IPv4(priv->dev.d_flags))
{
arp_out(&priv->dev);
}
#endif
#ifdef CONFIG_NET_IPv6
if (IFF_IS_IPv6(priv->dev.d_flags))
{
neighbor_out(&priv->dev);
}
#endif
/* And send the packet */
priv->write_d_len = priv->dev.d_len;
tun_fd_transmit(priv);
}
}
#endif
@ -748,8 +693,6 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
static void tun_net_receive_tun(FAR struct tun_device_s *priv)
{
int ret;
/* Copy the data data from the hardware to priv->dev.d_buf. Set amount of
* data in priv->dev.d_len
*/
@ -762,73 +705,46 @@ static void tun_net_receive_tun(FAR struct tun_device_s *priv)
pkt_input(&priv->dev);
#endif
/* We only accept IP packets of the configured type and ARP packets */
/* We only accept IP packets of the configured type */
#if defined(CONFIG_NET_IPv4)
ninfo("IPv4 frame\n");
NETDEV_RXIPV4(&priv->dev);
/* Give the IPv4 packet to the network layer. ipv4_input will return
* an error if it is unable to dispatch the packet at this time.
*/
ret = ipv4_input(&priv->dev);
if (ret == OK)
if ((IPv4BUF->vhl & IP_VERSION_MASK) == IPv4_VERSION)
{
/* 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.
*/
ninfo("IPv4 frame\n");
NETDEV_RXIPV4(&priv->dev);
if (priv->dev.d_len > 0)
{
priv->write_d_len = priv->dev.d_len;
tun_fd_transmit(priv);
}
else
{
tun_pollnotify(priv, POLLOUT);
}
/* Give the IPv4 packet to the network layer. */
ipv4_input(&priv->dev);
}
else
{
priv->dev.d_len = 0;
tun_pollnotify(priv, POLLOUT);
}
#elif defined(CONFIG_NET_IPv6)
ninfo("Iv6 frame\n");
NETDEV_RXIPV6(&priv->dev);
/* Give the IPv6 packet to the network layer. ipv6_input will return
* an error if it is unable to dispatch the packet at this time.
*/
ret = ipv6_input(&priv->dev);
if (ret == OK)
{
/* 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
{
tun_pollnotify(priv, POLLOUT);
}
}
else
{
priv->write_d_len = 0;
tun_pollnotify(priv, POLLOUT);
}
#else
NETDEV_RXDROPPED(&priv->dev);
#endif
#if defined(CONFIG_NET_IPv6)
if ((IPv6BUF->vtc & IP_VERSION_MASK) == IPv6_VERSION)
{
ninfo("Iv6 frame\n");
NETDEV_RXIPV6(&priv->dev);
/* Give the IPv6 packet to the network layer. */
ipv6_input(&priv->dev);
}
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)
{
priv->write_d_len = priv->dev.d_len;
tun_fd_transmit(priv);
}
}
/****************************************************************************
@ -1047,7 +963,7 @@ static void tun_txavail_work(FAR void *arg)
/* Check if there is room to hold another network packet. */
if (priv->read_d_len != 0 || priv->write_d_len != 0)
if (priv->read_d_len != 0)
{
tun_unlock(priv);
return;
@ -1191,7 +1107,7 @@ 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,
FAR const char *devfmt)
FAR const char *devfmt, bool tun)
{
int ret;
@ -1222,15 +1138,6 @@ static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
priv->txpoll = wd_create(); /* Create periodic poll timer */
/* Initialize other variables */
priv->write_d_len = 0;
priv->read_wait = false;
/* Put the interface in the down state */
tun_ifdown(&priv->dev);
/* Assign d_ifname if specified. */
if (devfmt)
@ -1240,8 +1147,7 @@ static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
/* Register the device with the OS so that socket IOCTLs can be performed */
ret = netdev_register(&priv->dev, NET_LL_TUN);
ret = netdev_register(&priv->dev, tun ? NET_LL_TUN : NET_LL_ETHERNET);
if (ret != OK)
{
nxsem_destroy(&priv->waitsem);
@ -1297,7 +1203,7 @@ static int tun_close(FAR struct file *filep)
FAR struct tun_device_s *priv = filep->f_priv;
int intf;
if (!priv)
if (priv == NULL)
{
return OK;
}
@ -1323,7 +1229,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 ret;
if (!priv)
if (priv == NULL)
{
return -EINVAL;
}
@ -1372,7 +1278,7 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
size_t write_d_len;
size_t read_d_len;
if (!priv)
if (priv == NULL)
{
return -EINVAL;
}
@ -1394,15 +1300,9 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
ret = (ssize_t)write_d_len;
priv->write_d_len = 0;
NETDEV_TXDONE(&priv->dev);
tun_pollnotify(priv, POLLOUT);
if (priv->read_d_len == 0)
{
net_lock();
tun_txdone(priv);
net_unlock();
}
goto out;
}
@ -1455,16 +1355,11 @@ int tun_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
pollevent_t eventset;
int ret = OK;
if (!priv)
{
return -EINVAL;
}
/* Some sanity checking */
if (!priv || !fds)
if (priv == NULL || fds == NULL)
{
return -ENODEV;
return -EINVAL;
}
tun_lock(priv);
@ -1531,8 +1426,9 @@ static int tun_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
int intf;
FAR struct ifreq *ifr = (FAR struct ifreq *)arg;
if (!ifr || ((ifr->ifr_flags & IFF_MASK) != IFF_TUN &&
(ifr->ifr_flags & IFF_MASK) != IFF_TAP))
if (ifr == NULL ||
((ifr->ifr_flags & IFF_MASK) != IFF_TUN &&
(ifr->ifr_flags & IFF_MASK) != IFF_TAP))
{
return -EINVAL;
}
@ -1552,7 +1448,8 @@ static int tun_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
intf++, free_tuns >>= 1);
ret = tun_dev_init(&g_tun_devices[intf], filep,
*ifr->ifr_name ? ifr->ifr_name : 0);
*ifr->ifr_name ? ifr->ifr_name : 0,
(ifr->ifr_flags & IFF_MASK) == IFF_TUN);
if (ret != OK)
{
tundev_unlock(tun);
@ -1563,30 +1460,6 @@ static int tun_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
priv = filep->f_priv;
strncpy(ifr->ifr_name, priv->dev.d_ifname, IFNAMSIZ);
#ifdef CONFIG_NET_ETHERNET
if ((ifr->ifr_flags & IFF_MASK) == IFF_TAP)
{
/* TAP device -> handling raw Ethernet packets
* -> set appropriate Ethernet header length
*/
priv->dev.d_llhdrlen = ETH_HDRLEN;
/* Also, set the link type to NET_LL_ETHERNET */
priv->dev.d_lltype = NET_LL_ETHERNET;
}
else if ((ifr->ifr_flags & IFF_MASK) == IFF_TUN)
#endif
{
/* TUN device -> handling an application data stream
* -> no header
*/
priv->dev.d_llhdrlen = 0;
}
tundev_unlock(tun);
return OK;
@ -1603,7 +1476,7 @@ static int tun_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
* Name: tun_initialize
*
* Description:
* Instantiate a SLIP network interface.
* Instantiate a TUN network interface.
*
* Input Parameters:
*
@ -1625,3 +1498,4 @@ int tun_initialize(void)
}
#endif /* CONFIG_NET && CONFIG_NET_TUN */