This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / net / ipv4 / netfilter / ip_conntrack_core.c
index 3ea086b..757af68 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/proc_fs.h>
 #include <linux/vmalloc.h>
 #include <net/checksum.h>
+#include <net/ip.h>
 #include <linux/stddef.h>
 #include <linux/sysctl.h>
 #include <linux/slab.h>
@@ -142,6 +143,7 @@ get_tuple(const struct iphdr *iph,
        tuple->src.ip = iph->saddr;
        tuple->dst.ip = iph->daddr;
        tuple->dst.protonum = iph->protocol;
+       tuple->src.u.all = tuple->dst.u.all = 0;
 
        return protocol->pkt_to_tuple(skb, dataoff, tuple);
 }
@@ -155,6 +157,8 @@ invert_tuple(struct ip_conntrack_tuple *inverse,
        inverse->dst.ip = orig->src.ip;
        inverse->dst.protonum = orig->dst.protonum;
 
+       inverse->src.u.all = inverse->dst.u.all = 0;
+
        return protocol->invert_tuple(inverse, orig);
 }
 
@@ -173,13 +177,12 @@ static void
 destroy_expect(struct ip_conntrack_expect *exp)
 {
        DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use));
-       IP_NF_ASSERT(atomic_read(&exp->use));
+       IP_NF_ASSERT(atomic_read(&exp->use) == 0);
        IP_NF_ASSERT(!timer_pending(&exp->timeout));
 
        kfree(exp);
 }
 
-
 inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
 {
        IP_NF_ASSERT(exp);
@@ -324,8 +327,9 @@ destroy_conntrack(struct nf_conntrack *nfct)
                ip_conntrack_destroyed(ct);
 
        WRITE_LOCK(&ip_conntrack_lock);
-       /* Delete us from our own list to prevent corruption later */
-       list_del(&ct->sibling_list);
+       /* Make sure don't leave any orphaned expectations lying around */
+       if (ct->expecting)
+               remove_expectations(ct, 1);
 
        /* Delete our master expectation */
        if (ct->master) {
@@ -669,8 +673,10 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
        conntrack->ct_general.destroy = destroy_conntrack;
        conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
        conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
+       conntrack->xid[IP_CT_DIR_ORIGINAL] = -1;
        conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
        conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
+       conntrack->xid[IP_CT_DIR_REPLY] = -1;
        for (i=0; i < IP_CT_NUMBER; i++)
                conntrack->infos[i].master = &conntrack->ct_general;
 
@@ -714,7 +720,6 @@ init_conntrack(const struct ip_conntrack_tuple *tuple,
                DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
                        conntrack, expected);
                /* Welcome, Mr. Bond.  We've been expecting you... */
-               IP_NF_ASSERT(master_ct(conntrack));
                __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
                conntrack->master = expected;
                expected->sibling = conntrack;
@@ -920,7 +925,7 @@ static void expectation_timed_out(unsigned long ul_expect)
 }
 
 struct ip_conntrack_expect *
-ip_conntrack_expect_alloc()
+ip_conntrack_expect_alloc(void)
 {
        struct ip_conntrack_expect *new;
        
@@ -947,9 +952,8 @@ ip_conntrack_expect_insert(struct ip_conntrack_expect *new,
        atomic_set(&new->use, 1);
 
        /* add to expected list for this connection */
-       list_add(&new->expected_list, &related_to->sibling_list);
+       list_add_tail(&new->expected_list, &related_to->sibling_list);
        /* add to global list of expectations */
-
        list_prepend(&ip_conntrack_expect_list, &new->list);
        /* add and start timer if required */
        if (related_to->helper->timeout) {
@@ -975,8 +979,8 @@ int ip_conntrack_expect_related(struct ip_conntrack_expect *expect,
         * so there is no need to use the tuple lock too */
 
        DEBUGP("ip_conntrack_expect_related %p\n", related_to);
-       DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
-       DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask);
+       DEBUGP("tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
+       DEBUGP("mask:  "); DUMP_TUPLE_RAW(&expect->mask);
 
        old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
                        struct ip_conntrack_expect *, &expect->tuple, 
@@ -1003,7 +1007,6 @@ int ip_conntrack_expect_related(struct ip_conntrack_expect *expect,
 
        } else if (related_to->helper->max_expected && 
                   related_to->expecting >= related_to->helper->max_expected) {
-               struct list_head *cur_item;
                /* old == NULL */
                if (!(related_to->helper->flags & 
                      IP_CT_HELPER_F_REUSE_EXPECT)) {
@@ -1029,21 +1032,14 @@ int ip_conntrack_expect_related(struct ip_conntrack_expect *expect,
                       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
  
                /* choose the the oldest expectation to evict */
-               list_for_each(cur_item, &related_to->sibling_list) { 
-                       struct ip_conntrack_expect *cur;
-
-                       cur = list_entry(cur_item, 
-                                        struct ip_conntrack_expect,
-                                        expected_list);
-                       if (cur->sibling == NULL) {
-                               old = cur;
+               list_for_each_entry(old, &related_to->sibling_list, 
+                                                     expected_list)
+                       if (old->sibling == NULL)
                                break;
-                       }
-               }
 
-               /* (!old) cannot happen, since related_to->expecting is the
-                * number of unconfirmed expects */
-               IP_NF_ASSERT(old);
+               /* We cannot fail since related_to->expecting is the number
+                * of unconfirmed expectations */
+               IP_NF_ASSERT(old && old->sibling == NULL);
 
                /* newnat14 does not reuse the real allocated memory
                 * structures but rather unexpects the old and
@@ -1077,15 +1073,14 @@ int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
 
        MUST_BE_READ_LOCKED(&ip_conntrack_lock);
        WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
-
        DEBUGP("change_expect:\n");
-       DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
-       DEBUGP("exp mask:  "); DUMP_TUPLE(&expect->mask);
-       DEBUGP("newtuple:  "); DUMP_TUPLE(newtuple);
+       DEBUGP("exp tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
+       DEBUGP("exp mask:  "); DUMP_TUPLE_RAW(&expect->mask);
+       DEBUGP("newtuple:  "); DUMP_TUPLE_RAW(newtuple);
        if (expect->ct_tuple.dst.protonum == 0) {
                /* Never seen before */
                DEBUGP("change expect: never seen before\n");
-               if (!ip_ct_tuple_equal(&expect->tuple, newtuple) 
+               if (!ip_ct_tuple_mask_cmp(&expect->tuple, newtuple, &expect->mask)
                    && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
                                 struct ip_conntrack_expect *, newtuple, &expect->mask)) {
                        /* Force NAT to find an unused tuple */
@@ -1127,10 +1122,8 @@ int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
        DUMP_TUPLE(newreply);
 
        conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
-       if (!conntrack->master)
-               conntrack->helper = LIST_FIND(&helpers, helper_cmp,
-                                             struct ip_conntrack_helper *,
-                                             newreply);
+       if (!conntrack->master && list_empty(&conntrack->sibling_list))
+               conntrack->helper = ip_ct_find_helper(newreply);
        WRITE_UNLOCK(&ip_conntrack_lock);
 
        return 1;
@@ -1175,21 +1168,39 @@ void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
        synchronize_net();
 }
 
-/* Refresh conntrack for this many jiffies. */
-void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
+static inline void ct_add_counters(struct ip_conntrack *ct,
+                                  enum ip_conntrack_info ctinfo,
+                                  const struct sk_buff *skb)
+{
+#ifdef CONFIG_IP_NF_CT_ACCT
+       if (skb) {
+               ct->counters[CTINFO2DIR(ctinfo)].packets++;
+               ct->counters[CTINFO2DIR(ctinfo)].bytes += 
+                                       ntohs(skb->nh.iph->tot_len);
+       }
+#endif
+}
+
+/* Refresh conntrack for this many jiffies and do accounting (if skb != NULL) */
+void ip_ct_refresh_acct(struct ip_conntrack *ct, 
+                       enum ip_conntrack_info ctinfo,
+                       const struct sk_buff *skb,
+                       unsigned long extra_jiffies)
 {
        IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
 
        /* If not in hash table, timer will not be active yet */
-       if (!is_confirmed(ct))
+       if (!is_confirmed(ct)) {
                ct->timeout.expires = extra_jiffies;
-       else {
+               ct_add_counters(ct, ctinfo, skb);
+       } else {
                WRITE_LOCK(&ip_conntrack_lock);
                /* Need del_timer for race avoidance (may already be dying). */
                if (del_timer(&ct->timeout)) {
                        ct->timeout.expires = jiffies + extra_jiffies;
                        add_timer(&ct->timeout);
                }
+               ct_add_counters(ct, ctinfo, skb);
                WRITE_UNLOCK(&ip_conntrack_lock);
        }
 }
@@ -1300,7 +1311,7 @@ ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
 /* Reversing the socket's dst/src point of view gives us the reply
    mapping. */
 static int
-getorigdst(struct sock *sk, int optval, void *user, int *len)
+getorigdst(struct sock *sk, int optval, void __user *user, int *len)
 {
        struct inet_opt *inet = inet_sk(sk);
        struct ip_conntrack_tuple_hash *h;