18f03dea5SMartin Josefsson /* L3/L4 protocol support for nf_conntrack. */ 28f03dea5SMartin Josefsson 38f03dea5SMartin Josefsson /* (C) 1999-2001 Paul `Rusty' Russell 48f03dea5SMartin Josefsson * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 58f03dea5SMartin Josefsson * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> 68f03dea5SMartin Josefsson * 78f03dea5SMartin Josefsson * This program is free software; you can redistribute it and/or modify 88f03dea5SMartin Josefsson * it under the terms of the GNU General Public License version 2 as 98f03dea5SMartin Josefsson * published by the Free Software Foundation. 108f03dea5SMartin Josefsson */ 118f03dea5SMartin Josefsson 128f03dea5SMartin Josefsson #include <linux/types.h> 138f03dea5SMartin Josefsson #include <linux/netfilter.h> 148f03dea5SMartin Josefsson #include <linux/module.h> 15d62f9ed4SPatrick McHardy #include <linux/mutex.h> 168f03dea5SMartin Josefsson #include <linux/skbuff.h> 178f03dea5SMartin Josefsson #include <linux/vmalloc.h> 188f03dea5SMartin Josefsson #include <linux/stddef.h> 198f03dea5SMartin Josefsson #include <linux/err.h> 208f03dea5SMartin Josefsson #include <linux/percpu.h> 218f03dea5SMartin Josefsson #include <linux/moduleparam.h> 228f03dea5SMartin Josefsson #include <linux/notifier.h> 238f03dea5SMartin Josefsson #include <linux/kernel.h> 248f03dea5SMartin Josefsson #include <linux/netdevice.h> 258f03dea5SMartin Josefsson 268f03dea5SMartin Josefsson #include <net/netfilter/nf_conntrack.h> 278f03dea5SMartin Josefsson #include <net/netfilter/nf_conntrack_l3proto.h> 28605dcad6SMartin Josefsson #include <net/netfilter/nf_conntrack_l4proto.h> 298f03dea5SMartin Josefsson #include <net/netfilter/nf_conntrack_core.h> 308f03dea5SMartin Josefsson 31605dcad6SMartin Josefsson struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly; 32ae5718fbSMartin Josefsson struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly; 338f03dea5SMartin Josefsson 34d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 35d62f9ed4SPatrick McHardy static DEFINE_MUTEX(nf_ct_proto_sysctl_mutex); 36d62f9ed4SPatrick McHardy 37d62f9ed4SPatrick McHardy static int 38d62f9ed4SPatrick McHardy nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_table *path, 39d62f9ed4SPatrick McHardy struct ctl_table *table, unsigned int *users) 40d62f9ed4SPatrick McHardy { 41d62f9ed4SPatrick McHardy if (*header == NULL) { 42d62f9ed4SPatrick McHardy *header = nf_register_sysctl_table(path, table); 43d62f9ed4SPatrick McHardy if (*header == NULL) 44d62f9ed4SPatrick McHardy return -ENOMEM; 45d62f9ed4SPatrick McHardy } 46d62f9ed4SPatrick McHardy if (users != NULL) 47d62f9ed4SPatrick McHardy (*users)++; 48d62f9ed4SPatrick McHardy return 0; 49d62f9ed4SPatrick McHardy } 50d62f9ed4SPatrick McHardy 51d62f9ed4SPatrick McHardy static void 52d62f9ed4SPatrick McHardy nf_ct_unregister_sysctl(struct ctl_table_header **header, 53d62f9ed4SPatrick McHardy struct ctl_table *table, unsigned int *users) 54d62f9ed4SPatrick McHardy { 55d62f9ed4SPatrick McHardy if (users != NULL && --*users > 0) 56d62f9ed4SPatrick McHardy return; 57d62f9ed4SPatrick McHardy nf_unregister_sysctl_table(*header, table); 58d62f9ed4SPatrick McHardy *header = NULL; 59d62f9ed4SPatrick McHardy } 60d62f9ed4SPatrick McHardy #endif 61d62f9ed4SPatrick McHardy 62605dcad6SMartin Josefsson struct nf_conntrack_l4proto * 63605dcad6SMartin Josefsson __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto) 648f03dea5SMartin Josefsson { 658f03dea5SMartin Josefsson if (unlikely(l3proto >= AF_MAX || nf_ct_protos[l3proto] == NULL)) 66605dcad6SMartin Josefsson return &nf_conntrack_l4proto_generic; 678f03dea5SMartin Josefsson 68605dcad6SMartin Josefsson return nf_ct_protos[l3proto][l4proto]; 698f03dea5SMartin Josefsson } 708f03dea5SMartin Josefsson 718f03dea5SMartin Josefsson /* this is guaranteed to always return a valid protocol helper, since 728f03dea5SMartin Josefsson * it falls back to generic_protocol */ 73605dcad6SMartin Josefsson struct nf_conntrack_l4proto * 74605dcad6SMartin Josefsson nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto) 758f03dea5SMartin Josefsson { 76605dcad6SMartin Josefsson struct nf_conntrack_l4proto *p; 778f03dea5SMartin Josefsson 788f03dea5SMartin Josefsson preempt_disable(); 79605dcad6SMartin Josefsson p = __nf_ct_l4proto_find(l3proto, l4proto); 808f03dea5SMartin Josefsson if (!try_module_get(p->me)) 81605dcad6SMartin Josefsson p = &nf_conntrack_l4proto_generic; 828f03dea5SMartin Josefsson preempt_enable(); 838f03dea5SMartin Josefsson 848f03dea5SMartin Josefsson return p; 858f03dea5SMartin Josefsson } 868f03dea5SMartin Josefsson 87605dcad6SMartin Josefsson void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p) 888f03dea5SMartin Josefsson { 898f03dea5SMartin Josefsson module_put(p->me); 908f03dea5SMartin Josefsson } 918f03dea5SMartin Josefsson 928f03dea5SMartin Josefsson struct nf_conntrack_l3proto * 938f03dea5SMartin Josefsson nf_ct_l3proto_find_get(u_int16_t l3proto) 948f03dea5SMartin Josefsson { 958f03dea5SMartin Josefsson struct nf_conntrack_l3proto *p; 968f03dea5SMartin Josefsson 978f03dea5SMartin Josefsson preempt_disable(); 988f03dea5SMartin Josefsson p = __nf_ct_l3proto_find(l3proto); 998f03dea5SMartin Josefsson if (!try_module_get(p->me)) 100605dcad6SMartin Josefsson p = &nf_conntrack_l3proto_generic; 1018f03dea5SMartin Josefsson preempt_enable(); 1028f03dea5SMartin Josefsson 1038f03dea5SMartin Josefsson return p; 1048f03dea5SMartin Josefsson } 1058f03dea5SMartin Josefsson 1068f03dea5SMartin Josefsson void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p) 1078f03dea5SMartin Josefsson { 1088f03dea5SMartin Josefsson module_put(p->me); 1098f03dea5SMartin Josefsson } 1108f03dea5SMartin Josefsson 1118f03dea5SMartin Josefsson int 1128f03dea5SMartin Josefsson nf_ct_l3proto_try_module_get(unsigned short l3proto) 1138f03dea5SMartin Josefsson { 1148f03dea5SMartin Josefsson int ret; 1158f03dea5SMartin Josefsson struct nf_conntrack_l3proto *p; 1168f03dea5SMartin Josefsson 1178f03dea5SMartin Josefsson retry: p = nf_ct_l3proto_find_get(l3proto); 118605dcad6SMartin Josefsson if (p == &nf_conntrack_l3proto_generic) { 1198f03dea5SMartin Josefsson ret = request_module("nf_conntrack-%d", l3proto); 1208f03dea5SMartin Josefsson if (!ret) 1218f03dea5SMartin Josefsson goto retry; 1228f03dea5SMartin Josefsson 1238f03dea5SMartin Josefsson return -EPROTOTYPE; 1248f03dea5SMartin Josefsson } 1258f03dea5SMartin Josefsson 1268f03dea5SMartin Josefsson return 0; 1278f03dea5SMartin Josefsson } 1288f03dea5SMartin Josefsson 1298f03dea5SMartin Josefsson void nf_ct_l3proto_module_put(unsigned short l3proto) 1308f03dea5SMartin Josefsson { 1318f03dea5SMartin Josefsson struct nf_conntrack_l3proto *p; 1328f03dea5SMartin Josefsson 1338f03dea5SMartin Josefsson preempt_disable(); 1348f03dea5SMartin Josefsson p = __nf_ct_l3proto_find(l3proto); 1358f03dea5SMartin Josefsson preempt_enable(); 1368f03dea5SMartin Josefsson 1378f03dea5SMartin Josefsson module_put(p->me); 1388f03dea5SMartin Josefsson } 1398f03dea5SMartin Josefsson 1408f03dea5SMartin Josefsson static int kill_l3proto(struct nf_conn *i, void *data) 1418f03dea5SMartin Josefsson { 1428f03dea5SMartin Josefsson return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num == 1438f03dea5SMartin Josefsson ((struct nf_conntrack_l3proto *)data)->l3proto); 1448f03dea5SMartin Josefsson } 1458f03dea5SMartin Josefsson 146605dcad6SMartin Josefsson static int kill_l4proto(struct nf_conn *i, void *data) 1478f03dea5SMartin Josefsson { 148605dcad6SMartin Josefsson struct nf_conntrack_l4proto *l4proto; 149605dcad6SMartin Josefsson l4proto = (struct nf_conntrack_l4proto *)data; 1508f03dea5SMartin Josefsson return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == 151605dcad6SMartin Josefsson l4proto->l4proto) && 1528f03dea5SMartin Josefsson (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num == 153605dcad6SMartin Josefsson l4proto->l3proto); 1548f03dea5SMartin Josefsson } 1558f03dea5SMartin Josefsson 156d62f9ed4SPatrick McHardy static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto) 157d62f9ed4SPatrick McHardy { 158d62f9ed4SPatrick McHardy int err = 0; 159d62f9ed4SPatrick McHardy 160d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 161d62f9ed4SPatrick McHardy mutex_lock(&nf_ct_proto_sysctl_mutex); 162d62f9ed4SPatrick McHardy if (l3proto->ctl_table != NULL) { 163d62f9ed4SPatrick McHardy err = nf_ct_register_sysctl(&l3proto->ctl_table_header, 164d62f9ed4SPatrick McHardy l3proto->ctl_table_path, 165d62f9ed4SPatrick McHardy l3proto->ctl_table, NULL); 166d62f9ed4SPatrick McHardy } 167d62f9ed4SPatrick McHardy mutex_unlock(&nf_ct_proto_sysctl_mutex); 168d62f9ed4SPatrick McHardy #endif 169d62f9ed4SPatrick McHardy return err; 170d62f9ed4SPatrick McHardy } 171d62f9ed4SPatrick McHardy 172d62f9ed4SPatrick McHardy static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto) 173d62f9ed4SPatrick McHardy { 174d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 175d62f9ed4SPatrick McHardy mutex_lock(&nf_ct_proto_sysctl_mutex); 176d62f9ed4SPatrick McHardy if (l3proto->ctl_table_header != NULL) 177d62f9ed4SPatrick McHardy nf_ct_unregister_sysctl(&l3proto->ctl_table_header, 178d62f9ed4SPatrick McHardy l3proto->ctl_table, NULL); 179d62f9ed4SPatrick McHardy mutex_unlock(&nf_ct_proto_sysctl_mutex); 180d62f9ed4SPatrick McHardy #endif 181d62f9ed4SPatrick McHardy } 182d62f9ed4SPatrick McHardy 1838f03dea5SMartin Josefsson int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) 1848f03dea5SMartin Josefsson { 1858f03dea5SMartin Josefsson int ret = 0; 1868f03dea5SMartin Josefsson 187ae5718fbSMartin Josefsson if (proto->l3proto >= AF_MAX) { 1888f03dea5SMartin Josefsson ret = -EBUSY; 1898f03dea5SMartin Josefsson goto out; 1908f03dea5SMartin Josefsson } 1918f03dea5SMartin Josefsson 192ae5718fbSMartin Josefsson write_lock_bh(&nf_conntrack_lock); 193ae5718fbSMartin Josefsson if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_l3proto_generic) { 194ae5718fbSMartin Josefsson ret = -EBUSY; 195ae5718fbSMartin Josefsson goto out_unlock; 196ae5718fbSMartin Josefsson } 197ae5718fbSMartin Josefsson nf_ct_l3protos[proto->l3proto] = proto; 198d62f9ed4SPatrick McHardy write_unlock_bh(&nf_conntrack_lock); 199d62f9ed4SPatrick McHardy 200d62f9ed4SPatrick McHardy ret = nf_ct_l3proto_register_sysctl(proto); 201d62f9ed4SPatrick McHardy if (ret < 0) 202d62f9ed4SPatrick McHardy nf_conntrack_l3proto_unregister(proto); 203d62f9ed4SPatrick McHardy return ret; 204ae5718fbSMartin Josefsson 205ae5718fbSMartin Josefsson out_unlock: 206ae5718fbSMartin Josefsson write_unlock_bh(&nf_conntrack_lock); 207ae5718fbSMartin Josefsson out: 2088f03dea5SMartin Josefsson return ret; 2098f03dea5SMartin Josefsson } 2108f03dea5SMartin Josefsson 211ae5718fbSMartin Josefsson int nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto) 2128f03dea5SMartin Josefsson { 213ae5718fbSMartin Josefsson int ret = 0; 214ae5718fbSMartin Josefsson 215ae5718fbSMartin Josefsson if (proto->l3proto >= AF_MAX) { 216ae5718fbSMartin Josefsson ret = -EBUSY; 217ae5718fbSMartin Josefsson goto out; 218ae5718fbSMartin Josefsson } 219ae5718fbSMartin Josefsson 2208f03dea5SMartin Josefsson write_lock_bh(&nf_conntrack_lock); 221ae5718fbSMartin Josefsson if (nf_ct_l3protos[proto->l3proto] != proto) { 222ae5718fbSMartin Josefsson write_unlock_bh(&nf_conntrack_lock); 223ae5718fbSMartin Josefsson ret = -EBUSY; 224ae5718fbSMartin Josefsson goto out; 225ae5718fbSMartin Josefsson } 226ae5718fbSMartin Josefsson 227605dcad6SMartin Josefsson nf_ct_l3protos[proto->l3proto] = &nf_conntrack_l3proto_generic; 2288f03dea5SMartin Josefsson write_unlock_bh(&nf_conntrack_lock); 2298f03dea5SMartin Josefsson 230d62f9ed4SPatrick McHardy nf_ct_l3proto_unregister_sysctl(proto); 231d62f9ed4SPatrick McHardy 2328f03dea5SMartin Josefsson /* Somebody could be still looking at the proto in bh. */ 2338f03dea5SMartin Josefsson synchronize_net(); 2348f03dea5SMartin Josefsson 2358f03dea5SMartin Josefsson /* Remove all contrack entries for this protocol */ 2368f03dea5SMartin Josefsson nf_ct_iterate_cleanup(kill_l3proto, proto); 237ae5718fbSMartin Josefsson 238ae5718fbSMartin Josefsson out: 239ae5718fbSMartin Josefsson return ret; 2408f03dea5SMartin Josefsson } 2418f03dea5SMartin Josefsson 242d62f9ed4SPatrick McHardy static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto) 243d62f9ed4SPatrick McHardy { 244d62f9ed4SPatrick McHardy int err = 0; 245d62f9ed4SPatrick McHardy 246d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 247d62f9ed4SPatrick McHardy mutex_lock(&nf_ct_proto_sysctl_mutex); 248d62f9ed4SPatrick McHardy if (l4proto->ctl_table != NULL) { 249d62f9ed4SPatrick McHardy err = nf_ct_register_sysctl(l4proto->ctl_table_header, 250d62f9ed4SPatrick McHardy nf_net_netfilter_sysctl_path, 251d62f9ed4SPatrick McHardy l4proto->ctl_table, 252d62f9ed4SPatrick McHardy l4proto->ctl_table_users); 253a999e683SPatrick McHardy if (err < 0) 254a999e683SPatrick McHardy goto out; 255d62f9ed4SPatrick McHardy } 256a999e683SPatrick McHardy #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 257a999e683SPatrick McHardy if (l4proto->ctl_compat_table != NULL) { 258a999e683SPatrick McHardy err = nf_ct_register_sysctl(&l4proto->ctl_compat_table_header, 259a999e683SPatrick McHardy nf_net_ipv4_netfilter_sysctl_path, 260a999e683SPatrick McHardy l4proto->ctl_compat_table, NULL); 261a999e683SPatrick McHardy if (err == 0) 262a999e683SPatrick McHardy goto out; 263a999e683SPatrick McHardy nf_ct_unregister_sysctl(l4proto->ctl_table_header, 264a999e683SPatrick McHardy l4proto->ctl_table, 265a999e683SPatrick McHardy l4proto->ctl_table_users); 266a999e683SPatrick McHardy } 267a999e683SPatrick McHardy #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 268a999e683SPatrick McHardy out: 269d62f9ed4SPatrick McHardy mutex_unlock(&nf_ct_proto_sysctl_mutex); 270933a41e7SPatrick McHardy #endif /* CONFIG_SYSCTL */ 271d62f9ed4SPatrick McHardy return err; 272d62f9ed4SPatrick McHardy } 273d62f9ed4SPatrick McHardy 274d62f9ed4SPatrick McHardy static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto) 275d62f9ed4SPatrick McHardy { 276d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 277d62f9ed4SPatrick McHardy mutex_lock(&nf_ct_proto_sysctl_mutex); 278d62f9ed4SPatrick McHardy if (l4proto->ctl_table_header != NULL && 279d62f9ed4SPatrick McHardy *l4proto->ctl_table_header != NULL) 280d62f9ed4SPatrick McHardy nf_ct_unregister_sysctl(l4proto->ctl_table_header, 281d62f9ed4SPatrick McHardy l4proto->ctl_table, 282d62f9ed4SPatrick McHardy l4proto->ctl_table_users); 283a999e683SPatrick McHardy #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 284a999e683SPatrick McHardy if (l4proto->ctl_compat_table_header != NULL) 285a999e683SPatrick McHardy nf_ct_unregister_sysctl(&l4proto->ctl_compat_table_header, 286a999e683SPatrick McHardy l4proto->ctl_compat_table, NULL); 287a999e683SPatrick McHardy #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 288d62f9ed4SPatrick McHardy mutex_unlock(&nf_ct_proto_sysctl_mutex); 289933a41e7SPatrick McHardy #endif /* CONFIG_SYSCTL */ 290d62f9ed4SPatrick McHardy } 291d62f9ed4SPatrick McHardy 2928f03dea5SMartin Josefsson /* FIXME: Allow NULL functions and sub in pointers to generic for 2938f03dea5SMartin Josefsson them. --RR */ 294605dcad6SMartin Josefsson int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto) 2958f03dea5SMartin Josefsson { 2968f03dea5SMartin Josefsson int ret = 0; 2978f03dea5SMartin Josefsson 298ae5718fbSMartin Josefsson if (l4proto->l3proto >= PF_MAX) { 299ae5718fbSMartin Josefsson ret = -EBUSY; 300ae5718fbSMartin Josefsson goto out; 301ae5718fbSMartin Josefsson } 302ae5718fbSMartin Josefsson 303933a41e7SPatrick McHardy if (l4proto == &nf_conntrack_l4proto_generic) 304933a41e7SPatrick McHardy return nf_ct_l4proto_register_sysctl(l4proto); 305933a41e7SPatrick McHardy 3068f03dea5SMartin Josefsson retry: 3078f03dea5SMartin Josefsson write_lock_bh(&nf_conntrack_lock); 308605dcad6SMartin Josefsson if (nf_ct_protos[l4proto->l3proto]) { 309605dcad6SMartin Josefsson if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto] 310605dcad6SMartin Josefsson != &nf_conntrack_l4proto_generic) { 3118f03dea5SMartin Josefsson ret = -EBUSY; 3128f03dea5SMartin Josefsson goto out_unlock; 3138f03dea5SMartin Josefsson } 3148f03dea5SMartin Josefsson } else { 3158f03dea5SMartin Josefsson /* l3proto may be loaded latter. */ 316605dcad6SMartin Josefsson struct nf_conntrack_l4proto **proto_array; 3178f03dea5SMartin Josefsson int i; 3188f03dea5SMartin Josefsson 3198f03dea5SMartin Josefsson write_unlock_bh(&nf_conntrack_lock); 3208f03dea5SMartin Josefsson 321605dcad6SMartin Josefsson proto_array = (struct nf_conntrack_l4proto **) 3228f03dea5SMartin Josefsson kmalloc(MAX_NF_CT_PROTO * 323605dcad6SMartin Josefsson sizeof(struct nf_conntrack_l4proto *), 3248f03dea5SMartin Josefsson GFP_KERNEL); 3258f03dea5SMartin Josefsson if (proto_array == NULL) { 3268f03dea5SMartin Josefsson ret = -ENOMEM; 3278f03dea5SMartin Josefsson goto out; 3288f03dea5SMartin Josefsson } 3298f03dea5SMartin Josefsson for (i = 0; i < MAX_NF_CT_PROTO; i++) 330605dcad6SMartin Josefsson proto_array[i] = &nf_conntrack_l4proto_generic; 3318f03dea5SMartin Josefsson 3328f03dea5SMartin Josefsson write_lock_bh(&nf_conntrack_lock); 333605dcad6SMartin Josefsson if (nf_ct_protos[l4proto->l3proto]) { 3348f03dea5SMartin Josefsson /* bad timing, but no problem */ 3358f03dea5SMartin Josefsson write_unlock_bh(&nf_conntrack_lock); 3368f03dea5SMartin Josefsson kfree(proto_array); 3378f03dea5SMartin Josefsson } else { 338605dcad6SMartin Josefsson nf_ct_protos[l4proto->l3proto] = proto_array; 3398f03dea5SMartin Josefsson write_unlock_bh(&nf_conntrack_lock); 3408f03dea5SMartin Josefsson } 3418f03dea5SMartin Josefsson 3428f03dea5SMartin Josefsson /* 3438f03dea5SMartin Josefsson * Just once because array is never freed until unloading 3448f03dea5SMartin Josefsson * nf_conntrack.ko 3458f03dea5SMartin Josefsson */ 3468f03dea5SMartin Josefsson goto retry; 3478f03dea5SMartin Josefsson } 3488f03dea5SMartin Josefsson 349605dcad6SMartin Josefsson nf_ct_protos[l4proto->l3proto][l4proto->l4proto] = l4proto; 350d62f9ed4SPatrick McHardy write_unlock_bh(&nf_conntrack_lock); 351d62f9ed4SPatrick McHardy 352d62f9ed4SPatrick McHardy ret = nf_ct_l4proto_register_sysctl(l4proto); 353d62f9ed4SPatrick McHardy if (ret < 0) 354d62f9ed4SPatrick McHardy nf_conntrack_l4proto_unregister(l4proto); 355d62f9ed4SPatrick McHardy return ret; 3568f03dea5SMartin Josefsson 3578f03dea5SMartin Josefsson out_unlock: 3588f03dea5SMartin Josefsson write_unlock_bh(&nf_conntrack_lock); 3598f03dea5SMartin Josefsson out: 3608f03dea5SMartin Josefsson return ret; 3618f03dea5SMartin Josefsson } 3628f03dea5SMartin Josefsson 363ae5718fbSMartin Josefsson int nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto) 3648f03dea5SMartin Josefsson { 365ae5718fbSMartin Josefsson int ret = 0; 366ae5718fbSMartin Josefsson 367ae5718fbSMartin Josefsson if (l4proto->l3proto >= PF_MAX) { 368ae5718fbSMartin Josefsson ret = -EBUSY; 369ae5718fbSMartin Josefsson goto out; 370ae5718fbSMartin Josefsson } 371ae5718fbSMartin Josefsson 372933a41e7SPatrick McHardy if (l4proto == &nf_conntrack_l4proto_generic) { 373933a41e7SPatrick McHardy nf_ct_l4proto_unregister_sysctl(l4proto); 374933a41e7SPatrick McHardy goto out; 375933a41e7SPatrick McHardy } 376933a41e7SPatrick McHardy 3778f03dea5SMartin Josefsson write_lock_bh(&nf_conntrack_lock); 378ae5718fbSMartin Josefsson if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto] 379ae5718fbSMartin Josefsson != l4proto) { 380ae5718fbSMartin Josefsson write_unlock_bh(&nf_conntrack_lock); 381ae5718fbSMartin Josefsson ret = -EBUSY; 382ae5718fbSMartin Josefsson goto out; 383ae5718fbSMartin Josefsson } 384605dcad6SMartin Josefsson nf_ct_protos[l4proto->l3proto][l4proto->l4proto] 385605dcad6SMartin Josefsson = &nf_conntrack_l4proto_generic; 3868f03dea5SMartin Josefsson write_unlock_bh(&nf_conntrack_lock); 3878f03dea5SMartin Josefsson 388d62f9ed4SPatrick McHardy nf_ct_l4proto_unregister_sysctl(l4proto); 389d62f9ed4SPatrick McHardy 3908f03dea5SMartin Josefsson /* Somebody could be still looking at the proto in bh. */ 3918f03dea5SMartin Josefsson synchronize_net(); 3928f03dea5SMartin Josefsson 3938f03dea5SMartin Josefsson /* Remove all contrack entries for this protocol */ 394605dcad6SMartin Josefsson nf_ct_iterate_cleanup(kill_l4proto, l4proto); 395ae5718fbSMartin Josefsson 396ae5718fbSMartin Josefsson out: 397ae5718fbSMartin Josefsson return ret; 3988f03dea5SMartin Josefsson } 399