aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6mr.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6mr.c')
-rw-r--r--net/ipv6/ip6mr.c32
1 files changed, 22 insertions, 10 deletions
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 716153941fc4..3e333268db89 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -33,6 +33,7 @@
33#include <linux/proc_fs.h> 33#include <linux/proc_fs.h>
34#include <linux/seq_file.h> 34#include <linux/seq_file.h>
35#include <linux/init.h> 35#include <linux/init.h>
36#include <linux/slab.h>
36#include <net/protocol.h> 37#include <net/protocol.h>
37#include <linux/skbuff.h> 38#include <linux/skbuff.h>
38#include <net/sock.h> 39#include <net/sock.h>
@@ -477,7 +478,7 @@ failure:
477 * Delete a VIF entry 478 * Delete a VIF entry
478 */ 479 */
479 480
480static int mif6_delete(struct net *net, int vifi) 481static int mif6_delete(struct net *net, int vifi, struct list_head *head)
481{ 482{
482 struct mif_device *v; 483 struct mif_device *v;
483 struct net_device *dev; 484 struct net_device *dev;
@@ -519,7 +520,7 @@ static int mif6_delete(struct net *net, int vifi)
519 in6_dev->cnf.mc_forwarding--; 520 in6_dev->cnf.mc_forwarding--;
520 521
521 if (v->flags & MIFF_REGISTER) 522 if (v->flags & MIFF_REGISTER)
522 unregister_netdevice(dev); 523 unregister_netdevice_queue(dev, head);
523 524
524 dev_put(dev); 525 dev_put(dev);
525 return 0; 526 return 0;
@@ -976,6 +977,7 @@ static int ip6mr_device_event(struct notifier_block *this,
976 struct net *net = dev_net(dev); 977 struct net *net = dev_net(dev);
977 struct mif_device *v; 978 struct mif_device *v;
978 int ct; 979 int ct;
980 LIST_HEAD(list);
979 981
980 if (event != NETDEV_UNREGISTER) 982 if (event != NETDEV_UNREGISTER)
981 return NOTIFY_DONE; 983 return NOTIFY_DONE;
@@ -983,8 +985,10 @@ static int ip6mr_device_event(struct notifier_block *this,
983 v = &net->ipv6.vif6_table[0]; 985 v = &net->ipv6.vif6_table[0];
984 for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) { 986 for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) {
985 if (v->dev == dev) 987 if (v->dev == dev)
986 mif6_delete(net, ct); 988 mif6_delete(net, ct, &list);
987 } 989 }
990 unregister_netdevice_many(&list);
991
988 return NOTIFY_DONE; 992 return NOTIFY_DONE;
989} 993}
990 994
@@ -1110,6 +1114,9 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock)
1110 unsigned char ttls[MAXMIFS]; 1114 unsigned char ttls[MAXMIFS];
1111 int i; 1115 int i;
1112 1116
1117 if (mfc->mf6cc_parent >= MAXMIFS)
1118 return -ENFILE;
1119
1113 memset(ttls, 255, MAXMIFS); 1120 memset(ttls, 255, MAXMIFS);
1114 for (i = 0; i < MAXMIFS; i++) { 1121 for (i = 0; i < MAXMIFS; i++) {
1115 if (IF_ISSET(i, &mfc->mf6cc_ifset)) 1122 if (IF_ISSET(i, &mfc->mf6cc_ifset))
@@ -1188,14 +1195,16 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock)
1188static void mroute_clean_tables(struct net *net) 1195static void mroute_clean_tables(struct net *net)
1189{ 1196{
1190 int i; 1197 int i;
1198 LIST_HEAD(list);
1191 1199
1192 /* 1200 /*
1193 * Shut down all active vif entries 1201 * Shut down all active vif entries
1194 */ 1202 */
1195 for (i = 0; i < net->ipv6.maxvif; i++) { 1203 for (i = 0; i < net->ipv6.maxvif; i++) {
1196 if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC)) 1204 if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC))
1197 mif6_delete(net, i); 1205 mif6_delete(net, i, &list);
1198 } 1206 }
1207 unregister_netdevice_many(&list);
1199 1208
1200 /* 1209 /*
1201 * Wipe the cache 1210 * Wipe the cache
@@ -1297,7 +1306,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
1297 switch (optname) { 1306 switch (optname) {
1298 case MRT6_INIT: 1307 case MRT6_INIT:
1299 if (sk->sk_type != SOCK_RAW || 1308 if (sk->sk_type != SOCK_RAW ||
1300 inet_sk(sk)->num != IPPROTO_ICMPV6) 1309 inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
1301 return -EOPNOTSUPP; 1310 return -EOPNOTSUPP;
1302 if (optlen < sizeof(int)) 1311 if (optlen < sizeof(int))
1303 return -EINVAL; 1312 return -EINVAL;
@@ -1325,7 +1334,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
1325 if (copy_from_user(&mifi, optval, sizeof(mifi_t))) 1334 if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
1326 return -EFAULT; 1335 return -EFAULT;
1327 rtnl_lock(); 1336 rtnl_lock();
1328 ret = mif6_delete(net, mifi); 1337 ret = mif6_delete(net, mifi, NULL);
1329 rtnl_unlock(); 1338 rtnl_unlock();
1330 return ret; 1339 return ret;
1331 1340
@@ -1687,17 +1696,20 @@ ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm)
1687 int ct; 1696 int ct;
1688 struct rtnexthop *nhp; 1697 struct rtnexthop *nhp;
1689 struct net *net = mfc6_net(c); 1698 struct net *net = mfc6_net(c);
1690 struct net_device *dev = net->ipv6.vif6_table[c->mf6c_parent].dev;
1691 u8 *b = skb_tail_pointer(skb); 1699 u8 *b = skb_tail_pointer(skb);
1692 struct rtattr *mp_head; 1700 struct rtattr *mp_head;
1693 1701
1694 if (dev) 1702 /* If cache is unresolved, don't try to parse IIF and OIF */
1695 RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex); 1703 if (c->mf6c_parent > MAXMIFS)
1704 return -ENOENT;
1705
1706 if (MIF_EXISTS(net, c->mf6c_parent))
1707 RTA_PUT(skb, RTA_IIF, 4, &net->ipv6.vif6_table[c->mf6c_parent].dev->ifindex);
1696 1708
1697 mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0)); 1709 mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
1698 1710
1699 for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { 1711 for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
1700 if (c->mfc_un.res.ttls[ct] < 255) { 1712 if (MIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) {
1701 if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) 1713 if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
1702 goto rtattr_failure; 1714 goto rtattr_failure;
1703 nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); 1715 nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));