summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/tun.c145
-rw-r--r--include/linux/if_tun.h2
2 files changed, 127 insertions, 20 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 87a4e0008d42..58b456fc048d 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -16,11 +16,25 @@
*/
/*
+ * Changes:
+ *
+ * Mark Smith <markzzzsmith@yahoo.com.au>
+ * Use random_ether_addr() for tap MAC address.
+ *
+ * Harald Roelle <harald.roelle@ifi.lmu.de> 2004/04/20
+ * Fixes in packet dropping, queue length setting and queue wakeup.
+ * Increased default tx queue length.
+ * Added ethtool API.
+ * Minor cleanups
+ *
* Daniel Podlejski <underley@underley.eu.org>
* Modifications for 2.3.99-pre5 kernel.
*/
-#define TUN_VER "1.5"
+#define DRV_NAME "tun"
+#define DRV_VERSION "1.6"
+#define DRV_DESCRIPTION "Universal TUN/TAP device driver"
+#define DRV_COPYRIGHT "(C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>"
#include <linux/config.h>
#include <linux/module.h>
@@ -31,11 +45,11 @@
#include <linux/poll.h>
#include <linux/fcntl.h>
#include <linux/init.h>
-#include <linux/random.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/miscdevice.h>
+#include <linux/ethtool.h>
#include <linux/rtnetlink.h>
#include <linux/if.h>
#include <linux/if_arp.h>
@@ -53,6 +67,7 @@ static int debug;
/* Network device part of the driver */
static LIST_HEAD(tun_dev_list);
+static struct ethtool_ops tun_ethtool_ops;
/* Net device open. */
static int tun_net_open(struct net_device *dev)
@@ -79,18 +94,24 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
if (!tun->attached)
goto drop;
- /* Queue packet */
- if (!(tun->flags & TUN_ONE_QUEUE)) {
- /* Normal queueing mode.
- * Packet scheduler handles dropping. */
- if (skb_queue_len(&tun->readq) >= TUN_READQ_SIZE)
+ /* Packet dropping */
+ if (skb_queue_len(&tun->readq) >= dev->tx_queue_len) {
+ if (!(tun->flags & TUN_ONE_QUEUE)) {
+ /* Normal queueing mode. */
+ /* Packet scheduler handles dropping of further packets. */
netif_stop_queue(dev);
- } else {
- /* Single queue mode.
- * Driver handles dropping itself. */
- if (skb_queue_len(&tun->readq) >= dev->tx_queue_len)
+
+ /* We won't see all dropped packets individually, so overrun
+ * error is more appropriate. */
+ tun->stats.tx_fifo_errors++;
+ } else {
+ /* Single queue mode.
+ * Driver handles dropping of all packets itself. */
goto drop;
+ }
}
+
+ /* Queue packet */
skb_queue_tail(&tun->readq, skb);
/* Notify and wake up reader process */
@@ -164,18 +185,16 @@ static void tun_net_init(struct net_device *dev)
/* Zero header length */
dev->type = ARPHRD_NONE;
dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
- dev->tx_queue_len = 10;
+ dev->tx_queue_len = TUN_READQ_SIZE; /* We prefer our own queue length */
break;
case TUN_TAP_DEV:
/* Ethernet TAP Device */
dev->set_multicast_list = tun_net_mclist;
- /* Generate random Ethernet address. */
- *(u16 *)dev->dev_addr = htons(0x00FF);
- get_random_bytes(dev->dev_addr + sizeof(u16), 4);
-
ether_setup(dev);
+ random_ether_addr(dev->dev_addr);
+ dev->tx_queue_len = TUN_READQ_SIZE; /* We prefer our own queue length */
break;
}
}
@@ -354,7 +373,7 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
schedule();
continue;
}
- netif_start_queue(tun->dev);
+ netif_wake_queue(tun->dev);
/** Decide whether to accept this packet. This code is designed to
* behave identically to an Ethernet interface. Accept the packet if
@@ -417,6 +436,7 @@ static void tun_setup(struct net_device *dev)
dev->hard_start_xmit = tun_net_xmit;
dev->stop = tun_net_close;
dev->get_stats = tun_net_stats;
+ dev->ethtool_ops = &tun_ethtool_ops;
dev->destructor = free_netdev;
}
@@ -735,12 +755,97 @@ static struct miscdevice tun_miscdev = {
.devfs_name = "net/tun",
};
+/* ethtool interface */
+
+static int tun_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ cmd->supported = 0;
+ cmd->advertising = 0;
+ cmd->speed = SPEED_10;
+ cmd->duplex = DUPLEX_FULL;
+ cmd->port = PORT_TP;
+ cmd->phy_address = 0;
+ cmd->transceiver = XCVR_INTERNAL;
+ cmd->autoneg = AUTONEG_DISABLE;
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+ return 0;
+}
+
+static void tun_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ struct tun_struct *tun = netdev_priv(dev);
+
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->fw_version, "N/A");
+
+ switch (tun->flags & TUN_TYPE_MASK) {
+ case TUN_TUN_DEV:
+ strcpy(info->bus_info, "tun");
+ break;
+ case TUN_TAP_DEV:
+ strcpy(info->bus_info, "tap");
+ break;
+ }
+}
+
+static u32 tun_get_msglevel(struct net_device *dev)
+{
+#ifdef TUN_DEBUG
+ struct tun_struct *tun = netdev_priv(dev);
+ return tun->debug;
+#else
+ return -EOPNOTSUPP;
+#endif
+}
+
+static void tun_set_msglevel(struct net_device *dev, u32 value)
+{
+#ifdef TUN_DEBUG
+ struct tun_struct *tun = netdev_priv(dev);
+ tun->debug = value;
+#endif
+}
+
+static u32 tun_get_link(struct net_device *dev)
+{
+ struct tun_struct *tun = netdev_priv(dev);
+ return tun->attached;
+}
+
+static u32 tun_get_rx_csum(struct net_device *dev)
+{
+ struct tun_struct *tun = netdev_priv(dev);
+ return (tun->flags & TUN_NOCHECKSUM) == 0;
+}
+
+static int tun_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct tun_struct *tun = netdev_priv(dev);
+ if (data)
+ tun->flags &= ~TUN_NOCHECKSUM;
+ else
+ tun->flags |= TUN_NOCHECKSUM;
+ return 0;
+}
+
+static struct ethtool_ops tun_ethtool_ops = {
+ .get_settings = tun_get_settings,
+ .get_drvinfo = tun_get_drvinfo,
+ .get_msglevel = tun_get_msglevel,
+ .set_msglevel = tun_set_msglevel,
+ .get_link = tun_get_link,
+ .get_rx_csum = tun_get_rx_csum,
+ .set_rx_csum = tun_set_rx_csum
+};
+
int __init tun_init(void)
{
int ret = 0;
- printk(KERN_INFO "Universal TUN/TAP device driver %s "
- "(C)1999-2002 Maxim Krasnyansky\n", TUN_VER);
+ printk(KERN_INFO "tun: %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
+ printk(KERN_INFO "tun: %s\n", DRV_COPYRIGHT);
ret = misc_register(&tun_miscdev);
if (ret)
@@ -765,5 +870,7 @@ void tun_cleanup(void)
module_init(tun_init);
module_exit(tun_cleanup);
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(TUN_MINOR);
diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h
index 386e1f91a1e1..096a85a58ae5 100644
--- a/include/linux/if_tun.h
+++ b/include/linux/if_tun.h
@@ -58,7 +58,7 @@ struct tun_struct {
#endif /* __KERNEL__ */
/* Read queue size */
-#define TUN_READQ_SIZE 10
+#define TUN_READQ_SIZE 500
/* TUN device flags */
#define TUN_TUN_DEV 0x0001