X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fip_conntrack_standalone.c;h=57361408d973bd0d60558020bc3de66b599977a7;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=c561a01b9d5393d37fbfa45bb7e4e2f746202ac7;hpb=ec9397bab20a628530ce3051167d3d0fcc2c1af7;p=linux-2.6.git diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index c561a01b9..57361408d 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -5,7 +5,7 @@ */ /* (C) 1999-2001 Paul `Rusty' Russell - * (C) 2002-2004 Netfilter Core Team + * (C) 2002-2005 Netfilter Core Team * * 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 @@ -27,9 +27,10 @@ #endif #include #include +#include -#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock) -#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock) +#define ASSERT_READ_LOCK(x) +#define ASSERT_WRITE_LOCK(x) #include #include @@ -48,7 +49,7 @@ MODULE_LICENSE("GPL"); extern atomic_t ip_conntrack_count; DECLARE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat); -static int kill_proto(const struct ip_conntrack *i, void *data) +static int kill_proto(struct ip_conntrack *i, void *data) { return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == *((u_int8_t *) data)); @@ -66,7 +67,8 @@ print_tuple(struct seq_file *s, const struct ip_conntrack_tuple *tuple, #ifdef CONFIG_IP_NF_CT_ACCT static unsigned int -seq_print_counters(struct seq_file *s, struct ip_conntrack_counter *counter) +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, @@ -76,104 +78,133 @@ seq_print_counters(struct seq_file *s, struct ip_conntrack_counter *counter) #define seq_print_counters(x, y) 0 #endif -static void *ct_seq_start(struct seq_file *s, loff_t *pos) +struct ct_iter_state { + unsigned int bucket; +}; + +static struct list_head *ct_get_first(struct seq_file *seq) { - if (*pos >= ip_conntrack_htable_size) - return NULL; - return &ip_conntrack_hash[*pos]; + 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 void ct_seq_stop(struct seq_file *s, void *v) + +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_bh(&ip_conntrack_lock); + return ct_get_idx(seq, *pos); } static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos) { (*pos)++; - if (*pos >= ip_conntrack_htable_size) - return NULL; - return &ip_conntrack_hash[*pos]; + return ct_get_next(s, v); } -/* return 0 on success, 1 in case of error */ -static int ct_seq_real_show(const struct ip_conntrack_tuple_hash *hash, - struct seq_file *s) +static void ct_seq_stop(struct seq_file *s, void *v) { - struct ip_conntrack *conntrack = hash->ctrack; + read_unlock_bh(&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); - + ASSERT_READ_LOCK(&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); + proto = __ip_conntrack_proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); IP_NF_ASSERT(proto); - if (seq_printf(s, "%-8s %u %lu ", + if (seq_printf(s, "%-8s %u %ld ", proto->name, conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum, timer_pending(&conntrack->timeout) - ? (conntrack->timeout.expires - jiffies)/HZ : 0) != 0) - return 1; + ? (long)(conntrack->timeout.expires - jiffies)/HZ + : 0) != 0) + return -ENOSPC; if (proto->print_conntrack(s, conntrack)) - return 1; + return -ENOSPC; if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple, proto)) - return 1; + return -ENOSPC; -#warning MEF should make this seq_printf conditional on xid support +#if defined(CONFIG_VNET) || defined(CONFIG_VNET_MODULE) if (seq_printf(s, "xid=%d\n", conntrack->xid[IP_CT_DIR_ORIGINAL])) return 1; +#endif if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_ORIGINAL])) - return 1; + return -ENOSPC; if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status))) if (seq_printf(s, "[UNREPLIED] ")) - return 1; + return -ENOSPC; if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple, proto)) - return 1; + return -ENOSPC; -#warning MEF should make this seq_printf conditional on xid support +#if defined(CONFIG_VNET) || defined(CONFIG_VNET_MODULE) if (seq_printf(s, "xid=%d\n", conntrack->xid[IP_CT_DIR_REPLY])) return 1; +#endif if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_REPLY])) - return 1; + return -ENOSPC; if (test_bit(IPS_ASSURED_BIT, &conntrack->status)) if (seq_printf(s, "[ASSURED] ")) - return 1; + return -ENOSPC; + +#if defined(CONFIG_IP_NF_CONNTRACK_MARK) + if (seq_printf(s, "mark=%u ", conntrack->mark)) + return -ENOSPC; +#endif if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use))) - return 1; + return -ENOSPC; return 0; } -static int ct_seq_show(struct seq_file *s, void *v) -{ - struct list_head *list = v; - int ret = 0; - - /* FIXME: Simply truncates if hash chain too long. */ - READ_LOCK(&ip_conntrack_lock); - if (LIST_FIND(list, ct_seq_real_show, - struct ip_conntrack_tuple_hash *, s)) - ret = -ENOSPC; - READ_UNLOCK(&ip_conntrack_lock); - return ret; -} - static struct seq_operations ct_seq_ops = { .start = ct_seq_start, .next = ct_seq_next, @@ -183,7 +214,23 @@ static struct seq_operations ct_seq_ops = { static int ct_open(struct inode *inode, struct file *file) { - return seq_open(file, &ct_seq_ops); + struct seq_file *seq; + struct ct_iter_state *st; + int ret; + + st = kmalloc(sizeof(struct ct_iter_state), GFP_KERNEL); + if (st == NULL) + return -ENOMEM; + ret = seq_open(file, &ct_seq_ops); + if (ret) + goto out_free; + seq = file->private_data; + seq->private = st; + memset(st, 0, sizeof(struct ct_iter_state)); + return ret; +out_free: + kfree(st); + return ret; } static struct file_operations ct_file_ops = { @@ -191,7 +238,7 @@ static struct file_operations ct_file_ops = { .open = ct_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release + .release = seq_release_private, }; /* expects */ @@ -202,8 +249,7 @@ static void *exp_seq_start(struct seq_file *s, loff_t *pos) /* strange seq_file api calls stop even if we fail, * thus we need to grab lock since stop unlocks */ - READ_LOCK(&ip_conntrack_lock); - READ_LOCK(&ip_conntrack_expect_tuple_lock); + read_lock_bh(&ip_conntrack_lock); if (list_empty(e)) return NULL; @@ -220,6 +266,7 @@ static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos) { struct list_head *e = v; + ++*pos; e = e->next; if (e == &ip_conntrack_expect_list) @@ -230,25 +277,23 @@ static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos) static void exp_seq_stop(struct seq_file *s, void *v) { - READ_UNLOCK(&ip_conntrack_expect_tuple_lock); - READ_UNLOCK(&ip_conntrack_lock); + read_unlock_bh(&ip_conntrack_lock); } static int exp_seq_show(struct seq_file *s, void *v) { struct ip_conntrack_expect *expect = v; - if (expect->expectant->helper->timeout) - seq_printf(s, "%lu ", timer_pending(&expect->timeout) - ? (expect->timeout.expires - jiffies)/HZ : 0); + if (expect->timeout.function) + seq_printf(s, "%ld ", timer_pending(&expect->timeout) + ? (long)(expect->timeout.expires - jiffies)/HZ : 0); else seq_printf(s, "- "); - seq_printf(s, "use=%u proto=%u ", atomic_read(&expect->use), - expect->tuple.dst.protonum); + seq_printf(s, "proto=%u ", expect->tuple.dst.protonum); print_tuple(s, &expect->tuple, - ip_ct_find_proto(expect->tuple.dst.protonum)); + __ip_conntrack_proto_find(expect->tuple.dst.protonum)); return seq_putc(s, '\n'); } @@ -368,7 +413,27 @@ static unsigned int ip_confirm(unsigned int hooknum, int (*okfn)(struct sk_buff *)) { /* We've seen it coming out the other side: confirm it */ - return ip_conntrack_confirm(*pskb); + return ip_conntrack_confirm(pskb); +} + +static unsigned int ip_conntrack_help(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + + /* This is where we call the helper: as the packet goes out. */ + ct = ip_conntrack_get(*pskb, &ctinfo); + if (ct && ct->helper) { + unsigned int ret; + ret = ct->helper->help(pskb, ct, ctinfo); + if (ret != NF_ACCEPT) + return ret; + } + return NF_ACCEPT; } static unsigned int ip_conntrack_defrag(unsigned int hooknum, @@ -377,44 +442,25 @@ static unsigned int ip_conntrack_defrag(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { +#if !defined(CONFIG_IP_NF_NAT) && !defined(CONFIG_IP_NF_NAT_MODULE) /* Previously seen (loopback)? Ignore. Do this before fragment check. */ if ((*pskb)->nfct) return NF_ACCEPT; +#endif /* Gather fragments. */ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { - *pskb = ip_ct_gather_frags(*pskb); + *pskb = ip_ct_gather_frags(*pskb, + hooknum == NF_IP_PRE_ROUTING ? + IP_DEFRAG_CONNTRACK_IN : + IP_DEFRAG_CONNTRACK_OUT); if (!*pskb) return NF_STOLEN; } return NF_ACCEPT; } -static unsigned int ip_refrag(unsigned int hooknum, - struct sk_buff **pskb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - struct rtable *rt = (struct rtable *)(*pskb)->dst; - - /* We've seen it coming out the other side: confirm */ - if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT) - return NF_DROP; - - /* Local packets are never produced too large for their - interface. We degfragment them at LOCAL_OUT, however, - so we have to refragment them here. */ - if ((*pskb)->len > dst_pmtu(&rt->u.dst) && - !skb_shinfo(*pskb)->tso_size) { - /* No hook can be after us, so this should be OK. */ - ip_fragment(*pskb, okfn); - return NF_STOLEN; - } - return NF_ACCEPT; -} - static unsigned int ip_conntrack_local(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, @@ -433,53 +479,63 @@ static unsigned int ip_conntrack_local(unsigned int hooknum, /* Connection tracking may drop packets, but never alters them, so make it the first hook. */ -static struct nf_hook_ops ip_conntrack_defrag_ops = { - .hook = ip_conntrack_defrag, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_PRE_ROUTING, - .priority = NF_IP_PRI_CONNTRACK_DEFRAG, -}; - -static struct nf_hook_ops ip_conntrack_in_ops = { - .hook = ip_conntrack_in, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_PRE_ROUTING, - .priority = NF_IP_PRI_CONNTRACK, -}; - -static struct nf_hook_ops ip_conntrack_defrag_local_out_ops = { - .hook = ip_conntrack_defrag, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_OUT, - .priority = NF_IP_PRI_CONNTRACK_DEFRAG, -}; - -static struct nf_hook_ops ip_conntrack_local_out_ops = { - .hook = ip_conntrack_local, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_OUT, - .priority = NF_IP_PRI_CONNTRACK, -}; - -/* Refragmenter; last chance. */ -static struct nf_hook_ops ip_conntrack_out_ops = { - .hook = ip_refrag, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_POST_ROUTING, - .priority = NF_IP_PRI_LAST, -}; - -static struct nf_hook_ops ip_conntrack_local_in_ops = { - .hook = ip_confirm, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_IN, - .priority = NF_IP_PRI_LAST-1, +static struct nf_hook_ops ip_conntrack_ops[] = { + { + .hook = ip_conntrack_defrag, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_PRE_ROUTING, + .priority = NF_IP_PRI_CONNTRACK_DEFRAG, + }, + { + .hook = ip_conntrack_in, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_PRE_ROUTING, + .priority = NF_IP_PRI_CONNTRACK, + }, + { + .hook = ip_conntrack_defrag, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_OUT, + .priority = NF_IP_PRI_CONNTRACK_DEFRAG, + }, + { + .hook = ip_conntrack_local, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_OUT, + .priority = NF_IP_PRI_CONNTRACK, + }, + { + .hook = ip_conntrack_help, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_CONNTRACK_HELPER, + }, + { + .hook = ip_conntrack_help, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_CONNTRACK_HELPER, + }, + { + .hook = ip_confirm, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_POST_ROUTING, + .priority = NF_IP_PRI_CONNTRACK_CONFIRM, + }, + { + .hook = ip_confirm, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_IN, + .priority = NF_IP_PRI_CONNTRACK_CONFIRM, + }, }; /* Sysctl support */ @@ -491,28 +547,28 @@ extern int ip_conntrack_max; extern unsigned int ip_conntrack_htable_size; /* From ip_conntrack_proto_tcp.c */ -extern unsigned long ip_ct_tcp_timeout_syn_sent; -extern unsigned long ip_ct_tcp_timeout_syn_recv; -extern unsigned long ip_ct_tcp_timeout_established; -extern unsigned long ip_ct_tcp_timeout_fin_wait; -extern unsigned long ip_ct_tcp_timeout_close_wait; -extern unsigned long ip_ct_tcp_timeout_last_ack; -extern unsigned long ip_ct_tcp_timeout_time_wait; -extern unsigned long ip_ct_tcp_timeout_close; -extern unsigned long ip_ct_tcp_timeout_max_retrans; +extern unsigned int ip_ct_tcp_timeout_syn_sent; +extern unsigned int ip_ct_tcp_timeout_syn_recv; +extern unsigned int ip_ct_tcp_timeout_established; +extern unsigned int ip_ct_tcp_timeout_fin_wait; +extern unsigned int ip_ct_tcp_timeout_close_wait; +extern unsigned int ip_ct_tcp_timeout_last_ack; +extern unsigned int ip_ct_tcp_timeout_time_wait; +extern unsigned int ip_ct_tcp_timeout_close; +extern unsigned int ip_ct_tcp_timeout_max_retrans; extern int ip_ct_tcp_loose; extern int ip_ct_tcp_be_liberal; extern int ip_ct_tcp_max_retrans; /* From ip_conntrack_proto_udp.c */ -extern unsigned long ip_ct_udp_timeout; -extern unsigned long ip_ct_udp_timeout_stream; +extern unsigned int ip_ct_udp_timeout; +extern unsigned int ip_ct_udp_timeout_stream; /* From ip_conntrack_proto_icmp.c */ -extern unsigned long ip_ct_icmp_timeout; +extern unsigned int ip_ct_icmp_timeout; /* From ip_conntrack_proto_icmp.c */ -extern unsigned long ip_ct_generic_timeout; +extern unsigned int ip_ct_generic_timeout; /* Log invalid packets of a given protocol */ static int log_invalid_proto_min = 0; @@ -730,20 +786,49 @@ static ctl_table ip_ct_net_table[] = { EXPORT_SYMBOL(ip_ct_log_invalid); #endif /* CONFIG_SYSCTL */ -static int init_or_cleanup(int init) +/* FIXME: Allow NULL functions and sub in pointers to generic for + them. --RR */ +int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto) +{ + int ret = 0; + + write_lock_bh(&ip_conntrack_lock); + if (ip_ct_protos[proto->proto] != &ip_conntrack_generic_protocol) { + ret = -EBUSY; + goto out; + } + ip_ct_protos[proto->proto] = proto; + out: + write_unlock_bh(&ip_conntrack_lock); + return ret; +} + +void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto) +{ + write_lock_bh(&ip_conntrack_lock); + ip_ct_protos[proto->proto] = &ip_conntrack_generic_protocol; + write_unlock_bh(&ip_conntrack_lock); + + /* Somebody could be still looking at the proto in bh. */ + synchronize_net(); + + /* Remove all contrack entries for this protocol */ + ip_ct_iterate_cleanup(kill_proto, &proto->proto); +} + +static int __init ip_conntrack_standalone_init(void) { #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc, *proc_exp, *proc_stat; #endif int ret = 0; - if (!init) goto cleanup; - ret = ip_conntrack_init(); if (ret < 0) - goto cleanup_nothing; + return ret; #ifdef CONFIG_PROC_FS + ret = -ENOMEM; proc = proc_net_fops_create("ip_conntrack", 0440, &ct_file_ops); if (!proc) goto cleanup_init; @@ -759,155 +844,120 @@ static int init_or_cleanup(int init) proc_stat->owner = THIS_MODULE; #endif - ret = nf_register_hook(&ip_conntrack_defrag_ops); + ret = nf_register_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops)); if (ret < 0) { - printk("ip_conntrack: can't register pre-routing defrag hook.\n"); + printk("ip_conntrack: can't register hooks.\n"); goto cleanup_proc_stat; } - ret = nf_register_hook(&ip_conntrack_defrag_local_out_ops); - if (ret < 0) { - printk("ip_conntrack: can't register local_out defrag hook.\n"); - goto cleanup_defragops; - } - ret = nf_register_hook(&ip_conntrack_in_ops); - if (ret < 0) { - printk("ip_conntrack: can't register pre-routing hook.\n"); - goto cleanup_defraglocalops; - } - ret = nf_register_hook(&ip_conntrack_local_out_ops); - if (ret < 0) { - printk("ip_conntrack: can't register local out hook.\n"); - goto cleanup_inops; - } - ret = nf_register_hook(&ip_conntrack_out_ops); - if (ret < 0) { - printk("ip_conntrack: can't register post-routing hook.\n"); - goto cleanup_inandlocalops; - } - ret = nf_register_hook(&ip_conntrack_local_in_ops); - if (ret < 0) { - printk("ip_conntrack: can't register local in hook.\n"); - goto cleanup_inoutandlocalops; - } #ifdef CONFIG_SYSCTL ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0); if (ip_ct_sysctl_header == NULL) { printk("ip_conntrack: can't register to sysctl.\n"); - goto cleanup; + ret = -ENOMEM; + goto cleanup_hooks; } #endif - return ret; - cleanup: #ifdef CONFIG_SYSCTL - unregister_sysctl_table(ip_ct_sysctl_header); + cleanup_hooks: + nf_unregister_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops)); #endif - nf_unregister_hook(&ip_conntrack_local_in_ops); - cleanup_inoutandlocalops: - nf_unregister_hook(&ip_conntrack_out_ops); - cleanup_inandlocalops: - nf_unregister_hook(&ip_conntrack_local_out_ops); - cleanup_inops: - nf_unregister_hook(&ip_conntrack_in_ops); - cleanup_defraglocalops: - nf_unregister_hook(&ip_conntrack_defrag_local_out_ops); - cleanup_defragops: - /* Frag queues may hold fragments with skb->dst == NULL */ - ip_ct_no_defrag = 1; - synchronize_net(); - local_bh_disable(); - ipfrag_flush(); - local_bh_enable(); - nf_unregister_hook(&ip_conntrack_defrag_ops); cleanup_proc_stat: #ifdef CONFIG_PROC_FS - proc_net_remove("ip_conntrack_stat"); -cleanup_proc_exp: + remove_proc_entry("ip_conntrack", proc_net_stat); + cleanup_proc_exp: proc_net_remove("ip_conntrack_expect"); cleanup_proc: proc_net_remove("ip_conntrack"); cleanup_init: #endif /* CONFIG_PROC_FS */ ip_conntrack_cleanup(); - cleanup_nothing: - return ret; -} - -/* FIXME: Allow NULL functions and sub in pointers to generic for - them. --RR */ -int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto) -{ - int ret = 0; - - WRITE_LOCK(&ip_conntrack_lock); - if (ip_ct_protos[proto->proto] != &ip_conntrack_generic_protocol) { - ret = -EBUSY; - goto out; - } - ip_ct_protos[proto->proto] = proto; - out: - WRITE_UNLOCK(&ip_conntrack_lock); return ret; } -void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto) +static void __exit ip_conntrack_standalone_fini(void) { - WRITE_LOCK(&ip_conntrack_lock); - ip_ct_protos[proto->proto] = &ip_conntrack_generic_protocol; - WRITE_UNLOCK(&ip_conntrack_lock); - - /* Somebody could be still looking at the proto in bh. */ synchronize_net(); - - /* Remove all contrack entries for this protocol */ - ip_ct_selective_cleanup(kill_proto, &proto->proto); -} - -static int __init init(void) -{ - return init_or_cleanup(1); -} - -static void __exit fini(void) -{ - init_or_cleanup(0); +#ifdef CONFIG_SYSCTL + unregister_sysctl_table(ip_ct_sysctl_header); +#endif + nf_unregister_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops)); +#ifdef CONFIG_PROC_FS + remove_proc_entry("ip_conntrack", proc_net_stat); + proc_net_remove("ip_conntrack_expect"); + proc_net_remove("ip_conntrack"); +#endif /* CONFIG_PROC_FS */ + ip_conntrack_cleanup(); } -module_init(init); -module_exit(fini); +module_init(ip_conntrack_standalone_init); +module_exit(ip_conntrack_standalone_fini); /* Some modules need us, but don't depend directly on any symbol. They should call this. */ -void need_ip_conntrack(void) +void need_conntrack(void) { } +#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS +EXPORT_SYMBOL_GPL(ip_conntrack_chain); +EXPORT_SYMBOL_GPL(ip_conntrack_expect_chain); +EXPORT_SYMBOL_GPL(ip_conntrack_register_notifier); +EXPORT_SYMBOL_GPL(ip_conntrack_unregister_notifier); +EXPORT_SYMBOL_GPL(__ip_ct_event_cache_init); +EXPORT_PER_CPU_SYMBOL_GPL(ip_conntrack_ecache); +#endif EXPORT_SYMBOL(ip_conntrack_protocol_register); EXPORT_SYMBOL(ip_conntrack_protocol_unregister); +EXPORT_SYMBOL(ip_ct_get_tuple); EXPORT_SYMBOL(invert_tuplepr); EXPORT_SYMBOL(ip_conntrack_alter_reply); EXPORT_SYMBOL(ip_conntrack_destroyed); -EXPORT_SYMBOL(need_ip_conntrack); +EXPORT_SYMBOL(need_conntrack); EXPORT_SYMBOL(ip_conntrack_helper_register); EXPORT_SYMBOL(ip_conntrack_helper_unregister); -EXPORT_SYMBOL(ip_ct_selective_cleanup); -EXPORT_SYMBOL(ip_ct_refresh_acct); -EXPORT_SYMBOL(ip_ct_protos); -EXPORT_SYMBOL(ip_ct_find_proto); -EXPORT_SYMBOL(ip_ct_find_helper); +EXPORT_SYMBOL(ip_ct_iterate_cleanup); +EXPORT_SYMBOL(__ip_ct_refresh_acct); + EXPORT_SYMBOL(ip_conntrack_expect_alloc); +EXPORT_SYMBOL(ip_conntrack_expect_put); +EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); +EXPORT_SYMBOL_GPL(ip_conntrack_expect_find); EXPORT_SYMBOL(ip_conntrack_expect_related); -EXPORT_SYMBOL(ip_conntrack_change_expect); EXPORT_SYMBOL(ip_conntrack_unexpect_related); -EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get); -EXPORT_SYMBOL_GPL(ip_conntrack_expect_put); +EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); +EXPORT_SYMBOL_GPL(ip_ct_unlink_expect); + EXPORT_SYMBOL(ip_conntrack_tuple_taken); EXPORT_SYMBOL(ip_ct_gather_frags); EXPORT_SYMBOL(ip_conntrack_htable_size); -EXPORT_SYMBOL(ip_conntrack_expect_list); EXPORT_SYMBOL(ip_conntrack_lock); EXPORT_SYMBOL(ip_conntrack_hash); EXPORT_SYMBOL(ip_conntrack_untracked); EXPORT_SYMBOL_GPL(ip_conntrack_find_get); -EXPORT_SYMBOL_GPL(ip_conntrack_put); +#ifdef CONFIG_IP_NF_NAT_NEEDED +EXPORT_SYMBOL(ip_conntrack_tcp_update); +#endif + +EXPORT_SYMBOL_GPL(ip_conntrack_flush); +EXPORT_SYMBOL_GPL(__ip_conntrack_find); + +EXPORT_SYMBOL_GPL(ip_conntrack_alloc); +EXPORT_SYMBOL_GPL(ip_conntrack_free); +EXPORT_SYMBOL_GPL(ip_conntrack_hash_insert); + +EXPORT_SYMBOL_GPL(ip_ct_remove_expectations); + +EXPORT_SYMBOL_GPL(ip_conntrack_helper_find_get); +EXPORT_SYMBOL_GPL(ip_conntrack_helper_put); +EXPORT_SYMBOL_GPL(__ip_conntrack_helper_find_byname); + +EXPORT_SYMBOL_GPL(ip_conntrack_proto_find_get); +EXPORT_SYMBOL_GPL(ip_conntrack_proto_put); +EXPORT_SYMBOL_GPL(__ip_conntrack_proto_find); +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) +EXPORT_SYMBOL_GPL(ip_ct_port_tuple_to_nfattr); +EXPORT_SYMBOL_GPL(ip_ct_port_nfattr_to_tuple); +#endif