/* This file contains all the functions required for the standalone
ip_conntrack module.
These are not required by the compatibility layer.
*/
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/ip.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/percpu.h>
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif
#include <net/checksum.h>
#include <net/ip.h>
#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
#include <linux/netfilter_ipv4/listhelp.h>
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
MODULE_LICENSE("GPL");
extern atomic_t ip_conntrack_count;
DECLARE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);
static int kill_proto(struct ip_conntrack *i, void *data)
{
return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum ==
*((u_int8_t *) data));
}
#ifdef CONFIG_PROC_FS
static int
print_tuple(struct seq_file *s, const struct ip_conntrack_tuple *tuple,
struct ip_conntrack_protocol *proto)
{
seq_printf(s, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip));
return proto->print_tuple(s, tuple);
}
#ifdef CONFIG_IP_NF_CT_ACCT
static unsigned int
seq_print_counters(struct seq_file *s,
const struct ip_conntrack_counter *counter)
{
return seq_printf(s, "packets=%llu bytes=%llu ",
(unsigned long long)counter->packets,
(unsigned long long)counter->bytes);
}
#else
#define seq_print_counters(x, y) 0
#endif
struct ct_iter_state {
unsigned int bucket;
};
static struct list_head *ct_get_first(struct seq_file *seq)
{
struct ct_iter_state *st = seq->private;
for (st->bucket = 0;
st->bucket < ip_conntrack_htable_size;
st->bucket++) {
if (!list_empty(&ip_conntrack_hash[st->bucket]))
return ip_conntrack_hash[st->bucket].next;
}
return NULL;
}
static struct list_head *ct_get_next(struct seq_file *seq, struct list_head *head)
{
struct ct_iter_state *st = seq->private;
head = head->next;
while (head == &ip_conntrack_hash[st->bucket]) {
if (++st->bucket >= ip_conntrack_htable_size)
return NULL;
head = ip_conntrack_hash[st->bucket].next;
}
return head;
}
static struct list_head *ct_get_idx(struct seq_file *seq, loff_t pos)
{
struct list_head *head = ct_get_first(seq);
if (head)
while (pos && (head = ct_get_next(seq, head)))
pos--;
return pos ? NULL : head;
}
static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
{
READ_LOCK(&ip_conntrack_lock);
return ct_get_idx(seq, *pos);
}
static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
(*pos)++;
return ct_get_next(s, v);
}
static void ct_seq_stop(struct seq_file *s, void *v)
{
READ_UNLOCK(&ip_conntrack_lock);
}
static int ct_seq_show(struct seq_file *s, void *v)
{
const struct ip_conntrack_tuple_hash *hash = v;
const struct ip_conntrack *conntrack = tuplehash_to_ctrack(hash);
struct ip_conntrack_protocol *proto;
MUST_BE_READ_LOCKED(&ip_conntrack_lock);
IP_NF_ASSERT(conntrack);
/* we only want to print DIR_ORIGINAL */
if (DIRECTION(hash))
return 0;
proto = ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
.tuple.dst.protonum);
IP_NF_ASSERT(proto);
if (seq_printf(s, "%-8s %u %ld ",