Merged in masayuki2009/nuttx.nuttx/network_bridge (pull request #630)
drivers/net: Add TAP (network bridge) mode to tun.c In previous implementation, TAP mode did not handle a packet correctly. Also, the driver did not set the link layer type and could not assign the interface name. This PR changes fix such issues and supports TAP mode correctly. Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com> Approved-by: Gregory Nutt <gnutt@nuttx.org>
This commit is contained in:
parent
83ccdd0105
commit
b29e7a37b2
1 changed files with 343 additions and 7 deletions
|
@ -96,7 +96,7 @@
|
|||
*/
|
||||
|
||||
#ifndef CONFIG_TUN_NINTERFACES
|
||||
# define CONFIG_TUN_NINTERFACES 1
|
||||
# define CONFIG_TUN_NINTERFACES 1
|
||||
#endif
|
||||
|
||||
/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per
|
||||
|
@ -105,6 +105,12 @@
|
|||
|
||||
#define TUN_WDDELAY (1*CLK_TCK)
|
||||
|
||||
/* This is a helper pointer for accessing the contents of the Ethernet header */
|
||||
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
# define BUF ((struct eth_hdr_s *)priv->dev.d_buf)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
@ -157,10 +163,19 @@ static void tun_unlock(FAR struct tun_device_s *priv);
|
|||
|
||||
static int tun_fd_transmit(FAR struct tun_device_s *priv);
|
||||
static int tun_txpoll(struct net_driver_s *dev);
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
static int tun_txpoll_tap(struct net_driver_s *dev);
|
||||
#endif
|
||||
static int tun_txpoll_tun(struct net_driver_s *dev);
|
||||
|
||||
/* Interrupt handling */
|
||||
|
||||
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);
|
||||
#endif
|
||||
static void tun_net_receive_tun(FAR struct tun_device_s *priv);
|
||||
|
||||
static void tun_txdone(FAR struct tun_device_s *priv);
|
||||
|
||||
/* Watchdog timer expirations */
|
||||
|
@ -378,6 +393,123 @@ static int tun_fd_transmit(FAR struct tun_device_s *priv)
|
|||
****************************************************************************/
|
||||
|
||||
static int tun_txpoll(struct net_driver_s *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
if (dev->d_lltype == NET_LL_ETHERNET)
|
||||
{
|
||||
ret = tun_txpoll_tap(dev);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ret = tun_txpoll_tun(dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tun_txpoll_tap : for tap (ethernet bridge) mode
|
||||
*
|
||||
* Description:
|
||||
* The transmitter is available, check if the network has any outgoing packets
|
||||
* ready to send. This is a callback from devif_poll(). devif_poll() may
|
||||
* be called:
|
||||
*
|
||||
* 1. When the preceding TX packet send is complete,
|
||||
* 2. When the preceding TX packet send timesout and the interface is reset
|
||||
* 3. During normal TX polling
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Reference to the NuttX driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success; a negated errno on failure
|
||||
*
|
||||
* Assumptions:
|
||||
* May or may not be called from an interrupt handler. In either case,
|
||||
* global interrupts are disabled, either explicitly or indirectly through
|
||||
* interrupt handling logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
static int tun_txpoll_tap(struct net_driver_s *dev)
|
||||
{
|
||||
FAR struct tun_device_s *priv = (FAR struct tun_device_s *)dev->d_private;
|
||||
|
||||
/* If the polling resulted in data that should be sent out on the network,
|
||||
* the field d_len is set to a value > 0.
|
||||
*/
|
||||
|
||||
if (priv->dev.d_len > 0)
|
||||
{
|
||||
/* Look up the destination MAC address and add it to the Ethernet
|
||||
* header.
|
||||
*/
|
||||
|
||||
#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
|
||||
{
|
||||
neighbor_out(&priv->dev);
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv6 */
|
||||
|
||||
/* Send the packet */
|
||||
|
||||
priv->read_d_len = priv->dev.d_len;
|
||||
tun_fd_transmit(priv);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If zero is returned, the polling will continue until all connections have
|
||||
* been examined.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tun_txpoll_tun : for tun (IP tunneling) mode
|
||||
*
|
||||
* Description:
|
||||
* The transmitter is available, check if the network has any outgoing packets
|
||||
* ready to send. This is a callback from devif_poll(). devif_poll() may
|
||||
* be called:
|
||||
*
|
||||
* 1. When the preceding TX packet send is complete,
|
||||
* 2. When the preceding TX packet send timesout and the interface is reset
|
||||
* 3. During normal TX polling
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Reference to the NuttX driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success; a negated errno on failure
|
||||
*
|
||||
* Assumptions:
|
||||
* May or may not be called from an interrupt handler. In either case,
|
||||
* global interrupts are disabled, either explicitly or indirectly through
|
||||
* interrupt handling logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int tun_txpoll_tun(struct net_driver_s *dev)
|
||||
{
|
||||
FAR struct tun_device_s *priv = (FAR struct tun_device_s *)dev->d_private;
|
||||
|
||||
|
@ -403,7 +535,7 @@ static int tun_txpoll(struct net_driver_s *dev)
|
|||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tun_receive
|
||||
* Name: tun_net_receive
|
||||
*
|
||||
* Description:
|
||||
* An interrupt was received indicating the availability of a new RX packet
|
||||
|
@ -420,6 +552,203 @@ static int tun_txpoll(struct net_driver_s *dev)
|
|||
****************************************************************************/
|
||||
|
||||
static void tun_net_receive(FAR struct tun_device_s *priv)
|
||||
{
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
if (priv->dev.d_lltype == NET_LL_ETHERNET)
|
||||
{
|
||||
tun_net_receive_tap(priv);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
tun_net_receive_tun(priv);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tun_net_receive_tap : for tap (ethernet bridge) mode
|
||||
*
|
||||
* Description:
|
||||
* An interrupt was received indicating the availability of a new RX packet
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - Reference to the driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Global interrupts are disabled by interrupt handling logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#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
|
||||
*/
|
||||
|
||||
NETDEV_RXPACKETS(&priv->dev);
|
||||
|
||||
#ifdef CONFIG_NET_PKT
|
||||
/* When packet sockets are enabled, feed the frame into the packet tap */
|
||||
|
||||
pkt_input(&priv->dev);
|
||||
#endif
|
||||
|
||||
/* We only accept IP packets of the configured type and ARP packets */
|
||||
|
||||
#if defined(CONFIG_NET_IPv4)
|
||||
if (BUF->type == HTONS(ETHTYPE_IP))
|
||||
{
|
||||
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.
|
||||
*/
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
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
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tun_net_receive_tun : for tun (IP tunneling) mode
|
||||
*
|
||||
* Description:
|
||||
* An interrupt was received indicating the availability of a new RX packet
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - Reference to the driver state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Global interrupts are disabled by interrupt handling logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void tun_net_receive_tun(FAR struct tun_device_s *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -904,14 +1233,10 @@ static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
|
|||
|
||||
tun_ifdown(&priv->dev);
|
||||
|
||||
if (devfmt)
|
||||
{
|
||||
strncpy(priv->dev.d_ifname, devfmt, IFNAMSIZ);
|
||||
}
|
||||
|
||||
/* Register the device with the OS so that socket IOCTLs can be performed */
|
||||
|
||||
ret = netdev_register(&priv->dev, NET_LL_TUN);
|
||||
|
||||
if (ret != OK)
|
||||
{
|
||||
nxsem_destroy(&priv->waitsem);
|
||||
|
@ -919,6 +1244,13 @@ static int tun_dev_init(FAR struct tun_device_s *priv, FAR struct file *filep,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Assign d_ifname if specified. This must be done after registration */
|
||||
|
||||
if (devfmt)
|
||||
{
|
||||
strncpy(priv->dev.d_ifname, devfmt, IFNAMSIZ);
|
||||
}
|
||||
|
||||
priv->filep = filep; /* Set link to file */
|
||||
filep->f_priv = priv; /* Set link to TUN device */
|
||||
|
||||
|
@ -1242,6 +1574,10 @@ static int tun_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
*/
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue