diff options
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 74 |
1 files changed, 19 insertions, 55 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index d7b81e4fdd56..17923a508535 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -88,7 +88,6 @@ struct tap_filter { | |||
88 | }; | 88 | }; |
89 | 89 | ||
90 | struct tun_struct { | 90 | struct tun_struct { |
91 | struct list_head list; | ||
92 | unsigned int flags; | 91 | unsigned int flags; |
93 | int attached; | 92 | int attached; |
94 | uid_t owner; | 93 | uid_t owner; |
@@ -213,11 +212,6 @@ static int check_filter(struct tap_filter *filter, const struct sk_buff *skb) | |||
213 | 212 | ||
214 | /* Network device part of the driver */ | 213 | /* Network device part of the driver */ |
215 | 214 | ||
216 | static int tun_net_id; | ||
217 | struct tun_net { | ||
218 | struct list_head dev_list; | ||
219 | }; | ||
220 | |||
221 | static const struct ethtool_ops tun_ethtool_ops; | 215 | static const struct ethtool_ops tun_ethtool_ops; |
222 | 216 | ||
223 | /* Net device open. */ | 217 | /* Net device open. */ |
@@ -697,30 +691,22 @@ static void tun_setup(struct net_device *dev) | |||
697 | dev->features |= NETIF_F_NETNS_LOCAL; | 691 | dev->features |= NETIF_F_NETNS_LOCAL; |
698 | } | 692 | } |
699 | 693 | ||
700 | static struct tun_struct *tun_get_by_name(struct tun_net *tn, const char *name) | ||
701 | { | ||
702 | struct tun_struct *tun; | ||
703 | |||
704 | ASSERT_RTNL(); | ||
705 | list_for_each_entry(tun, &tn->dev_list, list) { | ||
706 | if (!strncmp(tun->dev->name, name, IFNAMSIZ)) | ||
707 | return tun; | ||
708 | } | ||
709 | |||
710 | return NULL; | ||
711 | } | ||
712 | |||
713 | static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | 694 | static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) |
714 | { | 695 | { |
715 | struct tun_net *tn; | ||
716 | struct tun_struct *tun; | 696 | struct tun_struct *tun; |
717 | struct net_device *dev; | 697 | struct net_device *dev; |
718 | const struct cred *cred = current_cred(); | 698 | const struct cred *cred = current_cred(); |
719 | int err; | 699 | int err; |
720 | 700 | ||
721 | tn = net_generic(net, tun_net_id); | 701 | dev = __dev_get_by_name(net, ifr->ifr_name); |
722 | tun = tun_get_by_name(tn, ifr->ifr_name); | 702 | if (dev) { |
723 | if (tun) { | 703 | if ((ifr->ifr_flags & IFF_TUN) && dev->netdev_ops == &tun_netdev_ops) |
704 | tun = netdev_priv(dev); | ||
705 | else if ((ifr->ifr_flags & IFF_TAP) && dev->netdev_ops == &tap_netdev_ops) | ||
706 | tun = netdev_priv(dev); | ||
707 | else | ||
708 | return -EINVAL; | ||
709 | |||
724 | if (tun->attached) | 710 | if (tun->attached) |
725 | return -EBUSY; | 711 | return -EBUSY; |
726 | 712 | ||
@@ -733,8 +719,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
733 | return -EPERM; | 719 | return -EPERM; |
734 | } | 720 | } |
735 | } | 721 | } |
736 | else if (__dev_get_by_name(net, ifr->ifr_name)) | ||
737 | return -EINVAL; | ||
738 | else { | 722 | else { |
739 | char *name; | 723 | char *name; |
740 | unsigned long flags = 0; | 724 | unsigned long flags = 0; |
@@ -782,8 +766,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
782 | err = register_netdevice(tun->dev); | 766 | err = register_netdevice(tun->dev); |
783 | if (err < 0) | 767 | if (err < 0) |
784 | goto err_free_dev; | 768 | goto err_free_dev; |
785 | |||
786 | list_add(&tun->list, &tn->dev_list); | ||
787 | } | 769 | } |
788 | 770 | ||
789 | DBG(KERN_INFO "%s: tun_set_iff\n", tun->dev->name); | 771 | DBG(KERN_INFO "%s: tun_set_iff\n", tun->dev->name); |
@@ -1095,10 +1077,8 @@ static int tun_chr_close(struct inode *inode, struct file *file) | |||
1095 | /* Drop read queue */ | 1077 | /* Drop read queue */ |
1096 | skb_queue_purge(&tun->readq); | 1078 | skb_queue_purge(&tun->readq); |
1097 | 1079 | ||
1098 | if (!(tun->flags & TUN_PERSIST)) { | 1080 | if (!(tun->flags & TUN_PERSIST)) |
1099 | list_del(&tun->list); | ||
1100 | unregister_netdevice(tun->dev); | 1081 | unregister_netdevice(tun->dev); |
1101 | } | ||
1102 | 1082 | ||
1103 | rtnl_unlock(); | 1083 | rtnl_unlock(); |
1104 | 1084 | ||
@@ -1212,37 +1192,21 @@ static const struct ethtool_ops tun_ethtool_ops = { | |||
1212 | 1192 | ||
1213 | static int tun_init_net(struct net *net) | 1193 | static int tun_init_net(struct net *net) |
1214 | { | 1194 | { |
1215 | struct tun_net *tn; | ||
1216 | |||
1217 | tn = kmalloc(sizeof(*tn), GFP_KERNEL); | ||
1218 | if (tn == NULL) | ||
1219 | return -ENOMEM; | ||
1220 | |||
1221 | INIT_LIST_HEAD(&tn->dev_list); | ||
1222 | |||
1223 | if (net_assign_generic(net, tun_net_id, tn)) { | ||
1224 | kfree(tn); | ||
1225 | return -ENOMEM; | ||
1226 | } | ||
1227 | |||
1228 | return 0; | 1195 | return 0; |
1229 | } | 1196 | } |
1230 | 1197 | ||
1231 | static void tun_exit_net(struct net *net) | 1198 | static void tun_exit_net(struct net *net) |
1232 | { | 1199 | { |
1233 | struct tun_net *tn; | 1200 | struct net_device *dev, *next; |
1234 | struct tun_struct *tun, *nxt; | ||
1235 | |||
1236 | tn = net_generic(net, tun_net_id); | ||
1237 | 1201 | ||
1238 | rtnl_lock(); | 1202 | rtnl_lock(); |
1239 | list_for_each_entry_safe(tun, nxt, &tn->dev_list, list) { | 1203 | for_each_netdev_safe(net, dev, next) { |
1240 | DBG(KERN_INFO "%s cleaned up\n", tun->dev->name); | 1204 | if (dev->ethtool_ops != &tun_ethtool_ops) |
1241 | unregister_netdevice(tun->dev); | 1205 | continue; |
1206 | DBG(KERN_INFO "%s cleaned up\n", dev->name); | ||
1207 | unregister_netdevice(dev); | ||
1242 | } | 1208 | } |
1243 | rtnl_unlock(); | 1209 | rtnl_unlock(); |
1244 | |||
1245 | kfree(tn); | ||
1246 | } | 1210 | } |
1247 | 1211 | ||
1248 | static struct pernet_operations tun_net_ops = { | 1212 | static struct pernet_operations tun_net_ops = { |
@@ -1257,7 +1221,7 @@ static int __init tun_init(void) | |||
1257 | printk(KERN_INFO "tun: %s, %s\n", DRV_DESCRIPTION, DRV_VERSION); | 1221 | printk(KERN_INFO "tun: %s, %s\n", DRV_DESCRIPTION, DRV_VERSION); |
1258 | printk(KERN_INFO "tun: %s\n", DRV_COPYRIGHT); | 1222 | printk(KERN_INFO "tun: %s\n", DRV_COPYRIGHT); |
1259 | 1223 | ||
1260 | ret = register_pernet_gen_device(&tun_net_id, &tun_net_ops); | 1224 | ret = register_pernet_device(&tun_net_ops); |
1261 | if (ret) { | 1225 | if (ret) { |
1262 | printk(KERN_ERR "tun: Can't register pernet ops\n"); | 1226 | printk(KERN_ERR "tun: Can't register pernet ops\n"); |
1263 | goto err_pernet; | 1227 | goto err_pernet; |
@@ -1271,7 +1235,7 @@ static int __init tun_init(void) | |||
1271 | return 0; | 1235 | return 0; |
1272 | 1236 | ||
1273 | err_misc: | 1237 | err_misc: |
1274 | unregister_pernet_gen_device(tun_net_id, &tun_net_ops); | 1238 | unregister_pernet_device(&tun_net_ops); |
1275 | err_pernet: | 1239 | err_pernet: |
1276 | return ret; | 1240 | return ret; |
1277 | } | 1241 | } |
@@ -1279,7 +1243,7 @@ err_pernet: | |||
1279 | static void tun_cleanup(void) | 1243 | static void tun_cleanup(void) |
1280 | { | 1244 | { |
1281 | misc_deregister(&tun_miscdev); | 1245 | misc_deregister(&tun_miscdev); |
1282 | unregister_pernet_gen_device(tun_net_id, &tun_net_ops); | 1246 | unregister_pernet_device(&tun_net_ops); |
1283 | } | 1247 | } |
1284 | 1248 | ||
1285 | module_init(tun_init); | 1249 | module_init(tun_init); |