X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fnetfilter%2Fnf_conntrack_proto.c;h=a49fc932629b44f7acce1406237497b6f349b2da;hb=d83b14c0db5b238975990c0abda51521120106e9;hp=456155f05c759d3b3726bacc0f994ba311e7cdba;hpb=48c871c1f6a7c7044dd76774fb469e65c7e2e4e8;p=linux-2.6 diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 456155f05c..a49fc93262 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c @@ -28,19 +28,19 @@ #include #include -struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly; +static struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly; struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly; EXPORT_SYMBOL_GPL(nf_ct_l3protos); -#ifdef CONFIG_SYSCTL -static DEFINE_MUTEX(nf_ct_proto_sysctl_mutex); +static DEFINE_MUTEX(nf_ct_proto_mutex); +#ifdef CONFIG_SYSCTL static int -nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_table *path, +nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_path *path, struct ctl_table *table, unsigned int *users) { if (*header == NULL) { - *header = nf_register_sysctl_table(path, table); + *header = register_sysctl_paths(path, table); if (*header == NULL) return -ENOMEM; } @@ -55,7 +55,8 @@ nf_ct_unregister_sysctl(struct ctl_table_header **header, { if (users != NULL && --*users > 0) return; - nf_unregister_sysctl_table(*header, table); + + unregister_sysctl_table(*header); *header = NULL; } #endif @@ -145,18 +146,15 @@ EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put); static int kill_l3proto(struct nf_conn *i, void *data) { - return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num == - ((struct nf_conntrack_l3proto *)data)->l3proto); + return nf_ct_l3num(i) == ((struct nf_conntrack_l3proto *)data)->l3proto; } static int kill_l4proto(struct nf_conn *i, void *data) { struct nf_conntrack_l4proto *l4proto; l4proto = (struct nf_conntrack_l4proto *)data; - return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == - l4proto->l4proto) && - (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num == - l4proto->l3proto); + return nf_ct_protonum(i) == l4proto->l4proto && + nf_ct_l3num(i) == l4proto->l3proto; } static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto) @@ -164,13 +162,11 @@ static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto) int err = 0; #ifdef CONFIG_SYSCTL - mutex_lock(&nf_ct_proto_sysctl_mutex); if (l3proto->ctl_table != NULL) { err = nf_ct_register_sysctl(&l3proto->ctl_table_header, l3proto->ctl_table_path, l3proto->ctl_table, NULL); } - mutex_unlock(&nf_ct_proto_sysctl_mutex); #endif return err; } @@ -178,11 +174,9 @@ static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto) static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto) { #ifdef CONFIG_SYSCTL - mutex_lock(&nf_ct_proto_sysctl_mutex); if (l3proto->ctl_table_header != NULL) nf_ct_unregister_sysctl(&l3proto->ctl_table_header, l3proto->ctl_table, NULL); - mutex_unlock(&nf_ct_proto_sysctl_mutex); #endif } @@ -190,27 +184,23 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) { int ret = 0; - if (proto->l3proto >= AF_MAX) { - ret = -EBUSY; - goto out; - } + if (proto->l3proto >= AF_MAX) + return -EBUSY; - write_lock_bh(&nf_conntrack_lock); + mutex_lock(&nf_ct_proto_mutex); if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_l3proto_generic) { ret = -EBUSY; goto out_unlock; } - rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto); - write_unlock_bh(&nf_conntrack_lock); ret = nf_ct_l3proto_register_sysctl(proto); if (ret < 0) - nf_conntrack_l3proto_unregister(proto); - return ret; + goto out_unlock; + + rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto); out_unlock: - write_unlock_bh(&nf_conntrack_lock); -out: + mutex_unlock(&nf_ct_proto_mutex); return ret; } EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register); @@ -219,14 +209,14 @@ void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto) { BUG_ON(proto->l3proto >= AF_MAX); - write_lock_bh(&nf_conntrack_lock); + mutex_lock(&nf_ct_proto_mutex); BUG_ON(nf_ct_l3protos[proto->l3proto] != proto); rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], &nf_conntrack_l3proto_generic); - write_unlock_bh(&nf_conntrack_lock); - synchronize_rcu(); - nf_ct_l3proto_unregister_sysctl(proto); + mutex_unlock(&nf_ct_proto_mutex); + + synchronize_rcu(); /* Remove all contrack entries for this protocol */ nf_ct_iterate_cleanup(kill_l3proto, proto); @@ -238,7 +228,6 @@ static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto) int err = 0; #ifdef CONFIG_SYSCTL - mutex_lock(&nf_ct_proto_sysctl_mutex); if (l4proto->ctl_table != NULL) { err = nf_ct_register_sysctl(l4proto->ctl_table_header, nf_net_netfilter_sysctl_path, @@ -260,7 +249,6 @@ static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto) } #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ out: - mutex_unlock(&nf_ct_proto_sysctl_mutex); #endif /* CONFIG_SYSCTL */ return err; } @@ -268,7 +256,6 @@ out: static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto) { #ifdef CONFIG_SYSCTL - mutex_lock(&nf_ct_proto_sysctl_mutex); if (l4proto->ctl_table_header != NULL && *l4proto->ctl_table_header != NULL) nf_ct_unregister_sysctl(l4proto->ctl_table_header, @@ -279,7 +266,6 @@ static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto nf_ct_unregister_sysctl(&l4proto->ctl_compat_table_header, l4proto->ctl_compat_table, NULL); #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ - mutex_unlock(&nf_ct_proto_sysctl_mutex); #endif /* CONFIG_SYSCTL */ } @@ -289,68 +275,41 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto) { int ret = 0; - if (l4proto->l3proto >= PF_MAX) { - ret = -EBUSY; - goto out; - } - - if (l4proto == &nf_conntrack_l4proto_generic) - return nf_ct_l4proto_register_sysctl(l4proto); + if (l4proto->l3proto >= PF_MAX) + return -EBUSY; -retry: - write_lock_bh(&nf_conntrack_lock); - if (nf_ct_protos[l4proto->l3proto]) { - if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto] - != &nf_conntrack_l4proto_generic) { - ret = -EBUSY; - goto out_unlock; - } - } else { + mutex_lock(&nf_ct_proto_mutex); + if (!nf_ct_protos[l4proto->l3proto]) { /* l3proto may be loaded latter. */ struct nf_conntrack_l4proto **proto_array; int i; - write_unlock_bh(&nf_conntrack_lock); - - proto_array = (struct nf_conntrack_l4proto **) - kmalloc(MAX_NF_CT_PROTO * - sizeof(struct nf_conntrack_l4proto *), - GFP_KERNEL); + proto_array = kmalloc(MAX_NF_CT_PROTO * + sizeof(struct nf_conntrack_l4proto *), + GFP_KERNEL); if (proto_array == NULL) { ret = -ENOMEM; - goto out; + goto out_unlock; } + for (i = 0; i < MAX_NF_CT_PROTO; i++) proto_array[i] = &nf_conntrack_l4proto_generic; - - write_lock_bh(&nf_conntrack_lock); - if (nf_ct_protos[l4proto->l3proto]) { - /* bad timing, but no problem */ - write_unlock_bh(&nf_conntrack_lock); - kfree(proto_array); - } else { - nf_ct_protos[l4proto->l3proto] = proto_array; - write_unlock_bh(&nf_conntrack_lock); - } - - /* - * Just once because array is never freed until unloading - * nf_conntrack.ko - */ - goto retry; + nf_ct_protos[l4proto->l3proto] = proto_array; + } else if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto] != + &nf_conntrack_l4proto_generic) { + ret = -EBUSY; + goto out_unlock; } - rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], l4proto); - write_unlock_bh(&nf_conntrack_lock); - ret = nf_ct_l4proto_register_sysctl(l4proto); if (ret < 0) - nf_conntrack_l4proto_unregister(l4proto); - return ret; + goto out_unlock; + + rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], + l4proto); out_unlock: - write_unlock_bh(&nf_conntrack_lock); -out: + mutex_unlock(&nf_ct_proto_mutex); return ret; } EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register); @@ -359,21 +318,42 @@ void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto) { BUG_ON(l4proto->l3proto >= PF_MAX); - if (l4proto == &nf_conntrack_l4proto_generic) { - nf_ct_l4proto_unregister_sysctl(l4proto); - return; - } - - write_lock_bh(&nf_conntrack_lock); + mutex_lock(&nf_ct_proto_mutex); BUG_ON(nf_ct_protos[l4proto->l3proto][l4proto->l4proto] != l4proto); rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], &nf_conntrack_l4proto_generic); - write_unlock_bh(&nf_conntrack_lock); - synchronize_rcu(); - nf_ct_l4proto_unregister_sysctl(l4proto); + mutex_unlock(&nf_ct_proto_mutex); + + synchronize_rcu(); /* Remove all contrack entries for this protocol */ nf_ct_iterate_cleanup(kill_l4proto, l4proto); } EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister); + +int nf_conntrack_proto_init(void) +{ + unsigned int i; + int err; + + err = nf_ct_l4proto_register_sysctl(&nf_conntrack_l4proto_generic); + if (err < 0) + return err; + + for (i = 0; i < AF_MAX; i++) + rcu_assign_pointer(nf_ct_l3protos[i], + &nf_conntrack_l3proto_generic); + return 0; +} + +void nf_conntrack_proto_fini(void) +{ + unsigned int i; + + nf_ct_l4proto_unregister_sysctl(&nf_conntrack_l4proto_generic); + + /* free l3proto protocol tables */ + for (i = 0; i < PF_MAX; i++) + kfree(nf_ct_protos[i]); +}