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 * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
/* If processing is not done at the interrupt level, then high priority /* If processing is not done at the interrupt level, then high priority
* work queue support is required. * work queue support is required.
*/ */
@ -111,6 +112,11 @@
# define BUF ((struct eth_hdr_s *)priv->dev.d_buf) # define BUF ((struct eth_hdr_s *)priv->dev.d_buf)
#endif #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 * 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); static void tun_ipv6multicast(FAR struct tun_device_s *priv);
#endif #endif
static int tun_dev_init(FAR struct tun_device_s *priv, static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
FAR struct file *filep, FAR const char *devfmt); FAR const char *devfmt, bool tun);
static int tun_dev_uninit(FAR struct tun_device_s *priv); static int tun_dev_uninit(FAR struct tun_device_s *priv);
/* File interface */ /* File interface */
@ -329,7 +335,7 @@ static void tun_pollnotify(FAR struct tun_device_s *priv, pollevent_t eventset)
#endif #endif
/**************************************************************************** /****************************************************************************
* Name: tun_transmit * Name: tun_fd_transmit
* *
* Description: * Description:
* Start hardware transmission. Called either from the txdone interrupt * Start hardware transmission. Called either from the txdone interrupt
@ -451,23 +457,21 @@ static int tun_txpoll_tap(struct net_driver_s *dev)
*/ */
#ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (IFF_IS_IPv4(priv->dev.d_flags)) if (IFF_IS_IPv4(priv->dev.d_flags))
#endif
{ {
arp_out(&priv->dev); arp_out(&priv->dev);
} }
#endif /* CONFIG_NET_IPv4 */ #endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4 if (IFF_IS_IPv6(priv->dev.d_flags))
else
#endif
{ {
neighbor_out(&priv->dev); neighbor_out(&priv->dev);
} }
#endif /* CONFIG_NET_IPv6 */ #endif /* CONFIG_NET_IPv6 */
if (!devif_loopback(dev))
{
/* Send the packet */ /* Send the packet */
priv->read_d_len = priv->dev.d_len; priv->read_d_len = priv->dev.d_len;
@ -475,6 +479,7 @@ static int tun_txpoll_tap(struct net_driver_s *dev)
return 1; return 1;
} }
}
/* If zero is returned, the polling will continue until all connections have /* If zero is returned, the polling will continue until all connections have
* been examined. * been examined.
@ -518,6 +523,8 @@ static int tun_txpoll_tun(struct net_driver_s *dev)
*/ */
if (priv->dev.d_len > 0) if (priv->dev.d_len > 0)
{
if (!devif_loopback(dev))
{ {
/* Send the packet */ /* Send the packet */
@ -526,6 +533,7 @@ static int tun_txpoll_tun(struct net_driver_s *dev)
return 1; return 1;
} }
}
/* If zero is returned, the polling will continue until all connections have /* If zero is returned, the polling will continue until all connections have
* been examined. * been examined.
@ -585,8 +593,6 @@ static void tun_net_receive(FAR struct tun_device_s *priv)
#ifdef CONFIG_NET_ETHERNET #ifdef CONFIG_NET_ETHERNET
static void tun_net_receive_tap(FAR struct tun_device_s *priv) 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 /* Copy the data data from the hardware to priv->dev.d_buf. Set amount of
* data in priv->dev.d_len * data in priv->dev.d_len
*/ */
@ -607,32 +613,54 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
ninfo("IPv4 frame\n"); ninfo("IPv4 frame\n");
NETDEV_RXIPV4(&priv->dev); NETDEV_RXIPV4(&priv->dev);
/* Give the IPv4 packet to the network layer. ipv4_input will return /* Give the IPv4 packet to the network layer. */
* an error if it is unable to dispatch the packet at this time.
*/
arp_ipin(&priv->dev); arp_ipin(&priv->dev);
ret = ipv4_input(&priv->dev); ipv4_input(&priv->dev);
}
if (ret == OK) 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);
}
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.
*/ */
if (priv->dev.d_len > 0) if (priv->dev.d_len > 0)
{ {
/* Update the Ethernet header with the correct MAC address */ /* Update the Ethernet header with the correct MAC address */
#ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv4
if (IFF_IS_IPv4(priv->dev.d_flags)) if (IFF_IS_IPv4(priv->dev.d_flags))
#endif
{ {
arp_out(&priv->dev); arp_out(&priv->dev);
} }
#endif
#ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv6
else if (IFF_IS_IPv6(priv->dev.d_flags))
{ {
neighbor_out(&priv->dev); neighbor_out(&priv->dev);
} }
@ -643,89 +671,6 @@ static void tun_net_receive_tap(FAR struct tun_device_s *priv)
priv->write_d_len = priv->dev.d_len; priv->write_d_len = priv->dev.d_len;
tun_fd_transmit(priv); tun_fd_transmit(priv);
} }
else
{
tun_pollnotify(priv, POLLOUT);
}
}
else
{
priv->dev.d_len = 0;
tun_pollnotify(priv, POLLOUT);
}
}
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 will return
* an error if it is unable to dispatch the packet at this time.
*/
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);
}
}
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
@ -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) 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 /* Copy the data data from the hardware to priv->dev.d_buf. Set amount of
* data in priv->dev.d_len * data in priv->dev.d_len
*/ */
@ -762,50 +705,37 @@ static void tun_net_receive_tun(FAR struct tun_device_s *priv)
pkt_input(&priv->dev); pkt_input(&priv->dev);
#endif #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) #if defined(CONFIG_NET_IPv4)
if ((IPv4BUF->vhl & IP_VERSION_MASK) == IPv4_VERSION)
{
ninfo("IPv4 frame\n"); ninfo("IPv4 frame\n");
NETDEV_RXIPV4(&priv->dev); NETDEV_RXIPV4(&priv->dev);
/* Give the IPv4 packet to the network layer. ipv4_input will return /* Give the IPv4 packet to the network layer. */
* an error if it is unable to dispatch the packet at this time.
*/
ret = ipv4_input(&priv->dev); 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)
{
priv->write_d_len = priv->dev.d_len;
tun_fd_transmit(priv);
} }
else else
#endif
#if defined(CONFIG_NET_IPv6)
if ((IPv6BUF->vtc & IP_VERSION_MASK) == IPv6_VERSION)
{ {
tun_pollnotify(priv, POLLOUT);
}
}
else
{
priv->dev.d_len = 0;
tun_pollnotify(priv, POLLOUT);
}
#elif defined(CONFIG_NET_IPv6)
ninfo("Iv6 frame\n"); ninfo("Iv6 frame\n");
NETDEV_RXIPV6(&priv->dev); NETDEV_RXIPV6(&priv->dev);
/* Give the IPv6 packet to the network layer. ipv6_input will return /* Give the IPv6 packet to the network layer. */
* an error if it is unable to dispatch the packet at this time.
*/
ret = ipv6_input(&priv->dev); ipv6_input(&priv->dev);
if (ret == OK) }
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.
*/ */
@ -815,20 +745,6 @@ static void tun_net_receive_tun(FAR struct tun_device_s *priv)
priv->write_d_len = priv->dev.d_len; priv->write_d_len = priv->dev.d_len;
tun_fd_transmit(priv); 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
} }
/**************************************************************************** /****************************************************************************
@ -1047,7 +963,7 @@ static void tun_txavail_work(FAR void *arg)
/* Check if there is room to hold another network packet. */ /* 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); tun_unlock(priv);
return; 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, 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; 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 */ 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. */ /* Assign d_ifname if specified. */
if (devfmt) 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 */ /* 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) if (ret != OK)
{ {
nxsem_destroy(&priv->waitsem); 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; FAR struct tun_device_s *priv = filep->f_priv;
int intf; int intf;
if (!priv) if (priv == NULL)
{ {
return OK; 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; FAR struct tun_device_s *priv = filep->f_priv;
ssize_t ret; ssize_t ret;
if (!priv) if (priv == NULL)
{ {
return -EINVAL; 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 write_d_len;
size_t read_d_len; size_t read_d_len;
if (!priv) if (priv == NULL)
{ {
return -EINVAL; return -EINVAL;
} }
@ -1394,15 +1300,9 @@ static ssize_t tun_read(FAR struct file *filep, FAR char *buffer,
ret = (ssize_t)write_d_len; ret = (ssize_t)write_d_len;
priv->write_d_len = 0; priv->write_d_len = 0;
NETDEV_TXDONE(&priv->dev);
tun_pollnotify(priv, POLLOUT); tun_pollnotify(priv, POLLOUT);
if (priv->read_d_len == 0)
{
net_lock();
tun_txdone(priv);
net_unlock();
}
goto out; goto out;
} }
@ -1455,16 +1355,11 @@ int tun_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
pollevent_t eventset; pollevent_t eventset;
int ret = OK; int ret = OK;
if (!priv)
{
return -EINVAL;
}
/* Some sanity checking */ /* Some sanity checking */
if (!priv || !fds) if (priv == NULL || fds == NULL)
{ {
return -ENODEV; return -EINVAL;
} }
tun_lock(priv); tun_lock(priv);
@ -1531,7 +1426,8 @@ static int tun_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
int intf; int intf;
FAR struct ifreq *ifr = (FAR struct ifreq *)arg; FAR struct ifreq *ifr = (FAR struct ifreq *)arg;
if (!ifr || ((ifr->ifr_flags & IFF_MASK) != IFF_TUN && if (ifr == NULL ||
((ifr->ifr_flags & IFF_MASK) != IFF_TUN &&
(ifr->ifr_flags & IFF_MASK) != IFF_TAP)) (ifr->ifr_flags & IFF_MASK) != IFF_TAP))
{ {
return -EINVAL; return -EINVAL;
@ -1552,7 +1448,8 @@ static int tun_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
intf++, free_tuns >>= 1); intf++, free_tuns >>= 1);
ret = tun_dev_init(&g_tun_devices[intf], filep, 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) if (ret != OK)
{ {
tundev_unlock(tun); tundev_unlock(tun);
@ -1563,30 +1460,6 @@ static int tun_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
priv = filep->f_priv; priv = filep->f_priv;
strncpy(ifr->ifr_name, priv->dev.d_ifname, IFNAMSIZ); 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); tundev_unlock(tun);
return OK; return OK;
@ -1603,7 +1476,7 @@ static int tun_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
* Name: tun_initialize * Name: tun_initialize
* *
* Description: * Description:
* Instantiate a SLIP network interface. * Instantiate a TUN network interface.
* *
* Input Parameters: * Input Parameters:
* *
@ -1625,3 +1498,4 @@ int tun_initialize(void)
} }
#endif /* CONFIG_NET && CONFIG_NET_TUN */ #endif /* CONFIG_NET && CONFIG_NET_TUN */