diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 100288bd430..5c977a2395c 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -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 */ +