ipv6: Fix inet6_csk_bind_conflict()
[safe/jmp/linux-2.6] / net / ipv4 / ip_fragment.c
index 1472d8e..75347ea 100644 (file)
@@ -32,6 +32,9 @@
 #include <linux/netdevice.h>
 #include <linux/jhash.h>
 #include <linux/random.h>
+#include <linux/slab.h>
+#include <net/route.h>
+#include <net/dst.h>
 #include <net/sock.h>
 #include <net/ip.h>
 #include <net/icmp.h>
@@ -205,11 +208,34 @@ static void ip_expire(unsigned long arg)
        if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) {
                struct sk_buff *head = qp->q.fragments;
 
-               /* Send an ICMP "Fragment Reassembly Timeout" message. */
                rcu_read_lock();
                head->dev = dev_get_by_index_rcu(net, qp->iif);
-               if (head->dev)
-                       icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
+               if (!head->dev)
+                       goto out_rcu_unlock;
+
+               /*
+                * Only search router table for the head fragment,
+                * when defraging timeout at PRE_ROUTING HOOK.
+                */
+               if (qp->user == IP_DEFRAG_CONNTRACK_IN && !skb_dst(head)) {
+                       const struct iphdr *iph = ip_hdr(head);
+                       int err = ip_route_input(head, iph->daddr, iph->saddr,
+                                                iph->tos, head->dev);
+                       if (unlikely(err))
+                               goto out_rcu_unlock;
+
+                       /*
+                        * Only an end host needs to send an ICMP
+                        * "Fragment Reassembly Timeout" message, per RFC792.
+                        */
+                       if (skb_rtable(head)->rt_type != RTN_LOCAL)
+                               goto out_rcu_unlock;
+
+               }
+
+               /* Send an ICMP "Fragment Reassembly Timeout" message. */
+               icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
+out_rcu_unlock:
                rcu_read_unlock();
        }
 out:
@@ -564,7 +590,7 @@ out_oversize:
                printk(KERN_INFO "Oversized IP packet from %pI4.\n",
                        &qp->saddr);
 out_fail:
-       IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_REASMFAILS);
+       IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS);
        return err;
 }
 
@@ -604,7 +630,6 @@ static int zero;
 
 static struct ctl_table ip4_frags_ns_ctl_table[] = {
        {
-               .ctl_name       = NET_IPV4_IPFRAG_HIGH_THRESH,
                .procname       = "ipfrag_high_thresh",
                .data           = &init_net.ipv4.frags.high_thresh,
                .maxlen         = sizeof(int),
@@ -612,7 +637,6 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_IPFRAG_LOW_THRESH,
                .procname       = "ipfrag_low_thresh",
                .data           = &init_net.ipv4.frags.low_thresh,
                .maxlen         = sizeof(int),
@@ -620,26 +644,22 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = {
                .proc_handler   = proc_dointvec
        },
        {
-               .ctl_name       = NET_IPV4_IPFRAG_TIME,
                .procname       = "ipfrag_time",
                .data           = &init_net.ipv4.frags.timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies
        },
        { }
 };
 
 static struct ctl_table ip4_frags_ctl_table[] = {
        {
-               .ctl_name       = NET_IPV4_IPFRAG_SECRET_INTERVAL,
                .procname       = "ipfrag_secret_interval",
                .data           = &ip4_frags.secret_interval,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
-               .strategy       = sysctl_jiffies
        },
        {
                .procname       = "ipfrag_max_dist",
@@ -652,7 +672,7 @@ static struct ctl_table ip4_frags_ctl_table[] = {
        { }
 };
 
-static int ip4_frags_ns_ctl_register(struct net *net)
+static int __net_init ip4_frags_ns_ctl_register(struct net *net)
 {
        struct ctl_table *table;
        struct ctl_table_header *hdr;
@@ -682,7 +702,7 @@ err_alloc:
        return -ENOMEM;
 }
 
-static void ip4_frags_ns_ctl_unregister(struct net *net)
+static void __net_exit ip4_frags_ns_ctl_unregister(struct net *net)
 {
        struct ctl_table *table;
 
@@ -710,7 +730,7 @@ static inline void ip4_frags_ctl_register(void)
 }
 #endif
 
-static int ipv4_frags_init_net(struct net *net)
+static int __net_init ipv4_frags_init_net(struct net *net)
 {
        /*
         * Fragment cache limits. We will commit 256K at one time. Should we
@@ -732,7 +752,7 @@ static int ipv4_frags_init_net(struct net *net)
        return ip4_frags_ns_ctl_register(net);
 }
 
-static void ipv4_frags_exit_net(struct net *net)
+static void __net_exit ipv4_frags_exit_net(struct net *net)
 {
        ip4_frags_ns_ctl_unregister(net);
        inet_frags_exit_net(&net->ipv4.frags, &ip4_frags);