aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/ip_gre.c63
1 files changed, 32 insertions, 31 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 1a17c5beffd..a8ec0904e5a 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -126,10 +126,9 @@ static int ipgre_fb_tunnel_init(struct net_device *dev);
126 126
127static int ipgre_net_id; 127static int ipgre_net_id;
128struct ipgre_net { 128struct ipgre_net {
129 struct net_device *fb_tunnel_dev;
129}; 130};
130 131
131static struct net_device *ipgre_fb_tunnel_dev;
132
133/* Tunnel hash table */ 132/* Tunnel hash table */
134 133
135/* 134/*
@@ -168,6 +167,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net,
168 unsigned h0 = HASH(remote); 167 unsigned h0 = HASH(remote);
169 unsigned h1 = HASH(key); 168 unsigned h1 = HASH(key);
170 struct ip_tunnel *t; 169 struct ip_tunnel *t;
170 struct ipgre_net *ign = net_generic(net, ipgre_net_id);
171 171
172 for (t = tunnels_r_l[h0^h1]; t; t = t->next) { 172 for (t = tunnels_r_l[h0^h1]; t; t = t->next) {
173 if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) { 173 if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) {
@@ -194,8 +194,8 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net,
194 return t; 194 return t;
195 } 195 }
196 196
197 if (ipgre_fb_tunnel_dev->flags&IFF_UP) 197 if (ign->fb_tunnel_dev->flags&IFF_UP)
198 return netdev_priv(ipgre_fb_tunnel_dev); 198 return netdev_priv(ign->fb_tunnel_dev);
199 return NULL; 199 return NULL;
200} 200}
201 201
@@ -977,7 +977,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
977 switch (cmd) { 977 switch (cmd) {
978 case SIOCGETTUNNEL: 978 case SIOCGETTUNNEL:
979 t = NULL; 979 t = NULL;
980 if (dev == ipgre_fb_tunnel_dev) { 980 if (dev == ign->fb_tunnel_dev) {
981 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { 981 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
982 err = -EFAULT; 982 err = -EFAULT;
983 break; 983 break;
@@ -1016,7 +1016,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
1016 1016
1017 t = ipgre_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL); 1017 t = ipgre_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL);
1018 1018
1019 if (dev != ipgre_fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { 1019 if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
1020 if (t != NULL) { 1020 if (t != NULL) {
1021 if (t->dev != dev) { 1021 if (t->dev != dev) {
1022 err = -EEXIST; 1022 err = -EEXIST;
@@ -1071,7 +1071,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
1071 if (!capable(CAP_NET_ADMIN)) 1071 if (!capable(CAP_NET_ADMIN))
1072 goto done; 1072 goto done;
1073 1073
1074 if (dev == ipgre_fb_tunnel_dev) { 1074 if (dev == ign->fb_tunnel_dev) {
1075 err = -EFAULT; 1075 err = -EFAULT;
1076 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) 1076 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
1077 goto done; 1077 goto done;
@@ -1079,7 +1079,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
1079 if ((t = ipgre_tunnel_locate(net, &p, 0)) == NULL) 1079 if ((t = ipgre_tunnel_locate(net, &p, 0)) == NULL)
1080 goto done; 1080 goto done;
1081 err = -EPERM; 1081 err = -EPERM;
1082 if (t == netdev_priv(ipgre_fb_tunnel_dev)) 1082 if (t == netdev_priv(ign->fb_tunnel_dev))
1083 goto done; 1083 goto done;
1084 dev = t->dev; 1084 dev = t->dev;
1085 } 1085 }
@@ -1270,7 +1270,7 @@ static int ipgre_tunnel_init(struct net_device *dev)
1270 return 0; 1270 return 0;
1271} 1271}
1272 1272
1273static int __init ipgre_fb_tunnel_init(struct net_device *dev) 1273static int ipgre_fb_tunnel_init(struct net_device *dev)
1274{ 1274{
1275 struct ip_tunnel *tunnel = netdev_priv(dev); 1275 struct ip_tunnel *tunnel = netdev_priv(dev);
1276 struct iphdr *iph = &tunnel->parms.iph; 1276 struct iphdr *iph = &tunnel->parms.iph;
@@ -1308,8 +1308,25 @@ static int ipgre_init_net(struct net *net)
1308 if (err < 0) 1308 if (err < 0)
1309 goto err_assign; 1309 goto err_assign;
1310 1310
1311 ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0",
1312 ipgre_tunnel_setup);
1313 if (!ign->fb_tunnel_dev) {
1314 err = -ENOMEM;
1315 goto err_alloc_dev;
1316 }
1317
1318 ign->fb_tunnel_dev->init = ipgre_fb_tunnel_init;
1319 dev_net_set(ign->fb_tunnel_dev, net);
1320
1321 if ((err = register_netdev(ign->fb_tunnel_dev)))
1322 goto err_reg_dev;
1323
1311 return 0; 1324 return 0;
1312 1325
1326err_reg_dev:
1327 free_netdev(ign->fb_tunnel_dev);
1328err_alloc_dev:
1329 /* nothing */
1313err_assign: 1330err_assign:
1314 kfree(ign); 1331 kfree(ign);
1315err_alloc: 1332err_alloc:
@@ -1321,6 +1338,10 @@ static void ipgre_exit_net(struct net *net)
1321 struct ipgre_net *ign; 1338 struct ipgre_net *ign;
1322 1339
1323 ign = net_generic(net, ipgre_net_id); 1340 ign = net_generic(net, ipgre_net_id);
1341 rtnl_lock();
1342 if (net != &init_net)
1343 unregister_netdevice(ign->fb_tunnel_dev);
1344 rtnl_unlock();
1324 kfree(ign); 1345 kfree(ign);
1325} 1346}
1326 1347
@@ -1344,31 +1365,11 @@ static int __init ipgre_init(void)
1344 return -EAGAIN; 1365 return -EAGAIN;
1345 } 1366 }
1346 1367
1347 ipgre_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0",
1348 ipgre_tunnel_setup);
1349 if (!ipgre_fb_tunnel_dev) {
1350 err = -ENOMEM;
1351 goto err1;
1352 }
1353
1354 ipgre_fb_tunnel_dev->init = ipgre_fb_tunnel_init;
1355
1356 if ((err = register_netdev(ipgre_fb_tunnel_dev)))
1357 goto err2;
1358
1359 err = register_pernet_gen_device(&ipgre_net_id, &ipgre_net_ops); 1368 err = register_pernet_gen_device(&ipgre_net_id, &ipgre_net_ops);
1360 if (err < 0) 1369 if (err < 0)
1361 goto err3; 1370 inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
1362out: 1371
1363 return err; 1372 return err;
1364err2:
1365 free_netdev(ipgre_fb_tunnel_dev);
1366err1:
1367 inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
1368 goto out;
1369err3:
1370 unregister_netdevice(ipgre_fb_tunnel_dev);
1371 goto err1;
1372} 1373}
1373 1374
1374static void __exit ipgre_destroy_tunnels(void) 1375static void __exit ipgre_destroy_tunnels(void)