From 0304e5f1d5c22089ea47de39d48958f5dd747fbe Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 15 Apr 2011 18:45:10 +0200 Subject: Save a list of interfaces managed by quicktun --- quicktun.c | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/quicktun.c b/quicktun.c index 4c5c585..50429a4 100644 --- a/quicktun.c +++ b/quicktun.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,9 @@ #define MAX_MTU 65535 +static LIST_HEAD(quicktun_list); + + struct quicktun_struct { struct net_device *dev; unsigned long flags; @@ -34,6 +38,12 @@ struct quicktun_struct { }; +struct quicktun_list_entry { + struct list_head list; + struct quicktun_struct *quicktun; +}; + + static netdev_tx_t quicktun_net_xmit(struct sk_buff *skb, struct net_device *dev) { struct quicktun_struct *tun = netdev_priv(dev); @@ -265,6 +275,7 @@ static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *inf struct quicktun_struct *tun; struct net *net = genl_info_net(info); struct net_device *dev; + struct quicktun_list_entry *entry; char *name = "qt%d"; int err; @@ -286,16 +297,20 @@ static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *inf if (info->attrs[QUICKTUN_A_IFNAME]) name = nla_data(info->attrs[QUICKTUN_A_IFNAME]); + entry = kmalloc(sizeof(struct quicktun_struct), GFP_KERNEL); dev = alloc_netdev(sizeof(struct quicktun_struct), name, quicktun_setup); - if (!dev) - return -ENOMEM; + if (!entry || !dev) { + err = -ENOMEM; + goto err_free; + } dev_net_set(dev, net); tun = netdev_priv(dev); tun->dev = dev; tun->flags = flags; + entry->quicktun = tun; quicktun_net_init(dev); @@ -321,7 +336,7 @@ static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *inf err = quicktun_socket_init(dev); if (err < 0) - goto err_free_dev; + goto err_free; rtnl_lock(); @@ -335,6 +350,8 @@ static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *inf if (err < 0) goto err_free_sk; + list_add_tail_rcu(&entry->list, &quicktun_list); + rtnl_unlock(); return 0; @@ -343,8 +360,9 @@ static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *inf rtnl_unlock(); sock_release(tun->sock); - err_free_dev: - free_netdev(dev); + err_free: + if (dev) free_netdev(dev); + if (entry) kfree(entry); return err; } @@ -354,6 +372,7 @@ static int quicktun_cmd_delete_device(struct sk_buff *skb, struct genl_info *inf struct net *net = genl_info_net(info); struct net_device *dev; struct quicktun_struct *tun; + struct quicktun_list_entry *entry = NULL; struct socket *sock; char *name; @@ -381,12 +400,27 @@ static int quicktun_cmd_delete_device(struct sk_buff *skb, struct genl_info *inf tun = netdev_priv(dev); sock = tun->sock; + rcu_read_lock(); + + list_for_each_entry_rcu(entry, &quicktun_list, list) { + if (entry->quicktun->dev == dev) { + break; + } + } + + list_del_rcu(&entry->list); + + rcu_read_unlock(); + unregister_netdevice(dev); rtnl_unlock(); sock_release(sock); + synchronize_rcu(); + kfree(entry); + return 0; err_unlock: -- cgit v1.2.3