#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>
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);
}
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);
}
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);
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) {
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;
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;
}
struct ip_conntrack_expect *
-ip_conntrack_expect_alloc()
+ip_conntrack_expect_alloc(void)
{
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) {
* 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,
} 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)) {
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
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 */
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;
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);
}
}
/* 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;