tcp: make challenge acks less predictable
[pandora-kernel.git] / net / ipv6 / ip6mr.c
index def0538..02b3c82 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/pim.h>
 #include <net/addrconf.h>
 #include <linux/netfilter_ipv6.h>
+#include <linux/export.h>
 #include <net/ip6_checksum.h>
 
 struct mr6_table {
@@ -117,7 +118,7 @@ static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
                               struct mfc6_cache *c, struct rtmsg *rtm);
 static int ip6mr_rtm_dumproute(struct sk_buff *skb,
                               struct netlink_callback *cb);
-static void mroute_clean_tables(struct mr6_table *mrt);
+static void mroute_clean_tables(struct mr6_table *mrt, bool all);
 static void ipmr_expire_process(unsigned long arg);
 
 #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
@@ -138,9 +139,12 @@ static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
 static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6,
                            struct mr6_table **mrt)
 {
-       struct ip6mr_result res;
-       struct fib_lookup_arg arg = { .result = &res, };
        int err;
+       struct ip6mr_result res;
+       struct fib_lookup_arg arg = {
+               .result = &res,
+               .flags = FIB_LOOKUP_NOREF,
+       };
 
        err = fib_rules_lookup(net->ipv6.mr6_rules_ops,
                               flowi6_to_flowi(flp6), 0, &arg);
@@ -256,10 +260,12 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
 {
        struct mr6_table *mrt, *next;
 
+       rtnl_lock();
        list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
                list_del(&mrt->list);
                ip6mr_free_table(mrt);
        }
+       rtnl_unlock();
        fib_rules_unregister(net->ipv6.mr6_rules_ops);
 }
 #else
@@ -286,7 +292,10 @@ static int __net_init ip6mr_rules_init(struct net *net)
 
 static void __net_exit ip6mr_rules_exit(struct net *net)
 {
+       rtnl_lock();
        ip6mr_free_table(net->ipv6.mrt6);
+       net->ipv6.mrt6 = NULL;
+       rtnl_unlock();
 }
 #endif
 
@@ -325,8 +334,8 @@ static struct mr6_table *ip6mr_new_table(struct net *net, u32 id)
 
 static void ip6mr_free_table(struct mr6_table *mrt)
 {
-       del_timer(&mrt->ipmr_expire_timer);
-       mroute_clean_tables(mrt);
+       del_timer_sync(&mrt->ipmr_expire_timer);
+       mroute_clean_tables(mrt, true);
        kfree(mrt);
 }
 
@@ -541,7 +550,7 @@ static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
 
        if (it->cache == &mrt->mfc6_unres_queue)
                spin_unlock_bh(&mfc_unres_lock);
-       else if (it->cache == mrt->mfc6_cache_array)
+       else if (it->cache == &mrt->mfc6_cache_array[it->ct])
                read_unlock(&mrt_lock);
 }
 
@@ -1464,7 +1473,7 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
  *     Close the multicast socket, and clear the vif tables etc
  */
 
-static void mroute_clean_tables(struct mr6_table *mrt)
+static void mroute_clean_tables(struct mr6_table *mrt, bool all)
 {
        int i;
        LIST_HEAD(list);
@@ -1474,8 +1483,9 @@ static void mroute_clean_tables(struct mr6_table *mrt)
         *      Shut down all active vif entries
         */
        for (i = 0; i < mrt->maxvif; i++) {
-               if (!(mrt->vif6_table[i].flags & VIFF_STATIC))
-                       mif6_delete(mrt, i, &list);
+               if (!all && (mrt->vif6_table[i].flags & VIFF_STATIC))
+                       continue;
+               mif6_delete(mrt, i, &list);
        }
        unregister_netdevice_many(&list);
 
@@ -1484,7 +1494,7 @@ static void mroute_clean_tables(struct mr6_table *mrt)
         */
        for (i = 0; i < MFC6_LINES; i++) {
                list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) {
-                       if (c->mfc_flags & MFC_STATIC)
+                       if (!all && (c->mfc_flags & MFC_STATIC))
                                continue;
                        write_lock_bh(&mrt_lock);
                        list_del(&c->list);
@@ -1538,7 +1548,7 @@ int ip6mr_sk_done(struct sock *sk)
                        net->ipv6.devconf_all->mc_forwarding--;
                        write_unlock_bh(&mrt_lock);
 
-                       mroute_clean_tables(mrt);
+                       mroute_clean_tables(mrt, false);
                        err = 0;
                        break;
                }