diff options
Diffstat (limited to 'net/ipv4/ip_gre.c')
-rw-r--r-- | net/ipv4/ip_gre.c | 63 |
1 files changed, 32 insertions, 31 deletions
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 1a17c5beffdc..a8ec0904e5a6 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 | ||
127 | static int ipgre_net_id; | 127 | static int ipgre_net_id; |
128 | struct ipgre_net { | 128 | struct ipgre_net { |
129 | struct net_device *fb_tunnel_dev; | ||
129 | }; | 130 | }; |
130 | 131 | ||
131 | static 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 | ||
1273 | static int __init ipgre_fb_tunnel_init(struct net_device *dev) | 1273 | static 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 | ||
1326 | err_reg_dev: | ||
1327 | free_netdev(ign->fb_tunnel_dev); | ||
1328 | err_alloc_dev: | ||
1329 | /* nothing */ | ||
1313 | err_assign: | 1330 | err_assign: |
1314 | kfree(ign); | 1331 | kfree(ign); |
1315 | err_alloc: | 1332 | err_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); |
1362 | out: | 1371 | |
1363 | return err; | 1372 | return err; |
1364 | err2: | ||
1365 | free_netdev(ipgre_fb_tunnel_dev); | ||
1366 | err1: | ||
1367 | inet_del_protocol(&ipgre_protocol, IPPROTO_GRE); | ||
1368 | goto out; | ||
1369 | err3: | ||
1370 | unregister_netdevice(ipgre_fb_tunnel_dev); | ||
1371 | goto err1; | ||
1372 | } | 1373 | } |
1373 | 1374 | ||
1374 | static void __exit ipgre_destroy_tunnels(void) | 1375 | static void __exit ipgre_destroy_tunnels(void) |