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 3142bad1daSAdrian Bunk static struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly; 32ae5718fbSMartin Josefsson struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly; 3313b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_ct_l3protos); 348f03dea5SMartin Josefsson 35b19caa0cSPatrick McHardy static DEFINE_MUTEX(nf_ct_proto_mutex); 36d62f9ed4SPatrick McHardy 37b19caa0cSPatrick McHardy #ifdef CONFIG_SYSCTL 38d62f9ed4SPatrick McHardy static int 39d62f9ed4SPatrick McHardy nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_table *path, 40d62f9ed4SPatrick McHardy struct ctl_table *table, unsigned int *users) 41d62f9ed4SPatrick McHardy { 42d62f9ed4SPatrick McHardy if (*header == NULL) { 43d62f9ed4SPatrick McHardy *header = nf_register_sysctl_table(path, table); 44d62f9ed4SPatrick McHardy if (*header == NULL) 45d62f9ed4SPatrick McHardy return -ENOMEM; 46d62f9ed4SPatrick McHardy } 47d62f9ed4SPatrick McHardy if (users != NULL) 48d62f9ed4SPatrick McHardy (*users)++; 49d62f9ed4SPatrick McHardy return 0; 50d62f9ed4SPatrick McHardy } 51d62f9ed4SPatrick McHardy 52d62f9ed4SPatrick McHardy static void 53d62f9ed4SPatrick McHardy nf_ct_unregister_sysctl(struct ctl_table_header **header, 54d62f9ed4SPatrick McHardy struct ctl_table *table, unsigned int *users) 55d62f9ed4SPatrick McHardy { 56d62f9ed4SPatrick McHardy if (users != NULL && --*users > 0) 57d62f9ed4SPatrick McHardy return; 58d62f9ed4SPatrick McHardy nf_unregister_sysctl_table(*header, table); 59d62f9ed4SPatrick McHardy *header = NULL; 60d62f9ed4SPatrick McHardy } 61d62f9ed4SPatrick McHardy #endif 62d62f9ed4SPatrick McHardy 63605dcad6SMartin Josefsson struct nf_conntrack_l4proto * 64605dcad6SMartin Josefsson __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto) 658f03dea5SMartin Josefsson { 668f03dea5SMartin Josefsson if (unlikely(l3proto >= AF_MAX || nf_ct_protos[l3proto] == NULL)) 67605dcad6SMartin Josefsson return &nf_conntrack_l4proto_generic; 688f03dea5SMartin Josefsson 69923f4902SPatrick McHardy return rcu_dereference(nf_ct_protos[l3proto][l4proto]); 708f03dea5SMartin Josefsson } 7113b18339SPatrick McHardy EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find); 728f03dea5SMartin Josefsson 738f03dea5SMartin Josefsson /* this is guaranteed to always return a valid protocol helper, since 748f03dea5SMartin Josefsson * it falls back to generic_protocol */ 75605dcad6SMartin Josefsson struct nf_conntrack_l4proto * 76605dcad6SMartin Josefsson nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto) 778f03dea5SMartin Josefsson { 78605dcad6SMartin Josefsson struct nf_conntrack_l4proto *p; 798f03dea5SMartin Josefsson 80923f4902SPatrick McHardy rcu_read_lock(); 81605dcad6SMartin Josefsson p = __nf_ct_l4proto_find(l3proto, l4proto); 828f03dea5SMartin Josefsson if (!try_module_get(p->me)) 83605dcad6SMartin Josefsson p = &nf_conntrack_l4proto_generic; 84923f4902SPatrick McHardy rcu_read_unlock(); 858f03dea5SMartin Josefsson 868f03dea5SMartin Josefsson return p; 878f03dea5SMartin Josefsson } 8813b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get); 898f03dea5SMartin Josefsson 90605dcad6SMartin Josefsson void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p) 918f03dea5SMartin Josefsson { 928f03dea5SMartin Josefsson module_put(p->me); 938f03dea5SMartin Josefsson } 9413b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_ct_l4proto_put); 958f03dea5SMartin Josefsson 968f03dea5SMartin Josefsson struct nf_conntrack_l3proto * 978f03dea5SMartin Josefsson nf_ct_l3proto_find_get(u_int16_t l3proto) 988f03dea5SMartin Josefsson { 998f03dea5SMartin Josefsson struct nf_conntrack_l3proto *p; 1008f03dea5SMartin Josefsson 101923f4902SPatrick McHardy rcu_read_lock(); 1028f03dea5SMartin Josefsson p = __nf_ct_l3proto_find(l3proto); 1038f03dea5SMartin Josefsson if (!try_module_get(p->me)) 104605dcad6SMartin Josefsson p = &nf_conntrack_l3proto_generic; 105923f4902SPatrick McHardy rcu_read_unlock(); 1068f03dea5SMartin Josefsson 1078f03dea5SMartin Josefsson return p; 1088f03dea5SMartin Josefsson } 10913b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_ct_l3proto_find_get); 1108f03dea5SMartin Josefsson 1118f03dea5SMartin Josefsson void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p) 1128f03dea5SMartin Josefsson { 1138f03dea5SMartin Josefsson module_put(p->me); 1148f03dea5SMartin Josefsson } 11513b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_ct_l3proto_put); 1168f03dea5SMartin Josefsson 1178f03dea5SMartin Josefsson int 1188f03dea5SMartin Josefsson nf_ct_l3proto_try_module_get(unsigned short l3proto) 1198f03dea5SMartin Josefsson { 1208f03dea5SMartin Josefsson int ret; 1218f03dea5SMartin Josefsson struct nf_conntrack_l3proto *p; 1228f03dea5SMartin Josefsson 1238f03dea5SMartin Josefsson retry: p = nf_ct_l3proto_find_get(l3proto); 124605dcad6SMartin Josefsson if (p == &nf_conntrack_l3proto_generic) { 1258f03dea5SMartin Josefsson ret = request_module("nf_conntrack-%d", l3proto); 1268f03dea5SMartin Josefsson if (!ret) 1278f03dea5SMartin Josefsson goto retry; 1288f03dea5SMartin Josefsson 1298f03dea5SMartin Josefsson return -EPROTOTYPE; 1308f03dea5SMartin Josefsson } 1318f03dea5SMartin Josefsson 1328f03dea5SMartin Josefsson return 0; 1338f03dea5SMartin Josefsson } 13413b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_ct_l3proto_try_module_get); 1358f03dea5SMartin Josefsson 1368f03dea5SMartin Josefsson void nf_ct_l3proto_module_put(unsigned short l3proto) 1378f03dea5SMartin Josefsson { 1388f03dea5SMartin Josefsson struct nf_conntrack_l3proto *p; 1398f03dea5SMartin Josefsson 140923f4902SPatrick McHardy /* rcu_read_lock not necessary since the caller holds a reference */ 1418f03dea5SMartin Josefsson p = __nf_ct_l3proto_find(l3proto); 1428f03dea5SMartin Josefsson module_put(p->me); 1438f03dea5SMartin Josefsson } 14413b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put); 1458f03dea5SMartin Josefsson 1468f03dea5SMartin Josefsson static int kill_l3proto(struct nf_conn *i, void *data) 1478f03dea5SMartin Josefsson { 1488f03dea5SMartin Josefsson return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num == 1498f03dea5SMartin Josefsson ((struct nf_conntrack_l3proto *)data)->l3proto); 1508f03dea5SMartin Josefsson } 1518f03dea5SMartin Josefsson 152605dcad6SMartin Josefsson static int kill_l4proto(struct nf_conn *i, void *data) 1538f03dea5SMartin Josefsson { 154605dcad6SMartin Josefsson struct nf_conntrack_l4proto *l4proto; 155605dcad6SMartin Josefsson l4proto = (struct nf_conntrack_l4proto *)data; 1568f03dea5SMartin Josefsson return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == 157605dcad6SMartin Josefsson l4proto->l4proto) && 1588f03dea5SMartin Josefsson (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num == 159605dcad6SMartin Josefsson l4proto->l3proto); 1608f03dea5SMartin Josefsson } 1618f03dea5SMartin Josefsson 162d62f9ed4SPatrick McHardy static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto) 163d62f9ed4SPatrick McHardy { 164d62f9ed4SPatrick McHardy int err = 0; 165d62f9ed4SPatrick McHardy 166d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 167d62f9ed4SPatrick McHardy if (l3proto->ctl_table != NULL) { 168d62f9ed4SPatrick McHardy err = nf_ct_register_sysctl(&l3proto->ctl_table_header, 169d62f9ed4SPatrick McHardy l3proto->ctl_table_path, 170d62f9ed4SPatrick McHardy l3proto->ctl_table, NULL); 171d62f9ed4SPatrick McHardy } 172d62f9ed4SPatrick McHardy #endif 173d62f9ed4SPatrick McHardy return err; 174d62f9ed4SPatrick McHardy } 175d62f9ed4SPatrick McHardy 176d62f9ed4SPatrick McHardy static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto) 177d62f9ed4SPatrick McHardy { 178d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 179d62f9ed4SPatrick McHardy if (l3proto->ctl_table_header != NULL) 180d62f9ed4SPatrick McHardy nf_ct_unregister_sysctl(&l3proto->ctl_table_header, 181d62f9ed4SPatrick McHardy l3proto->ctl_table, NULL); 182d62f9ed4SPatrick McHardy #endif 183d62f9ed4SPatrick McHardy } 184d62f9ed4SPatrick McHardy 1858f03dea5SMartin Josefsson int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) 1868f03dea5SMartin Josefsson { 1878f03dea5SMartin Josefsson int ret = 0; 1888f03dea5SMartin Josefsson 1890661cca9SPatrick McHardy if (proto->l3proto >= AF_MAX) 1900661cca9SPatrick McHardy return -EBUSY; 1918f03dea5SMartin Josefsson 192b19caa0cSPatrick McHardy mutex_lock(&nf_ct_proto_mutex); 193ae5718fbSMartin Josefsson if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_l3proto_generic) { 194ae5718fbSMartin Josefsson ret = -EBUSY; 195ae5718fbSMartin Josefsson goto out_unlock; 196ae5718fbSMartin Josefsson } 197d62f9ed4SPatrick McHardy 198d62f9ed4SPatrick McHardy ret = nf_ct_l3proto_register_sysctl(proto); 199d62f9ed4SPatrick McHardy if (ret < 0) 2000661cca9SPatrick McHardy goto out_unlock; 2010661cca9SPatrick McHardy 2020661cca9SPatrick McHardy rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto); 203ae5718fbSMartin Josefsson 204ae5718fbSMartin Josefsson out_unlock: 205b19caa0cSPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 2068f03dea5SMartin Josefsson return ret; 2078f03dea5SMartin Josefsson } 20813b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register); 2098f03dea5SMartin Josefsson 210fe3eb20cSPatrick McHardy void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto) 2118f03dea5SMartin Josefsson { 212fe3eb20cSPatrick McHardy BUG_ON(proto->l3proto >= AF_MAX); 213ae5718fbSMartin Josefsson 214b19caa0cSPatrick McHardy mutex_lock(&nf_ct_proto_mutex); 215fe3eb20cSPatrick McHardy BUG_ON(nf_ct_l3protos[proto->l3proto] != proto); 216923f4902SPatrick McHardy rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], 217923f4902SPatrick McHardy &nf_conntrack_l3proto_generic); 218d62f9ed4SPatrick McHardy nf_ct_l3proto_unregister_sysctl(proto); 2190661cca9SPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 2200661cca9SPatrick McHardy 2210661cca9SPatrick McHardy synchronize_rcu(); 222d62f9ed4SPatrick McHardy 2238f03dea5SMartin Josefsson /* Remove all contrack entries for this protocol */ 2248f03dea5SMartin Josefsson nf_ct_iterate_cleanup(kill_l3proto, proto); 2258f03dea5SMartin Josefsson } 22613b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister); 2278f03dea5SMartin Josefsson 228d62f9ed4SPatrick McHardy static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto) 229d62f9ed4SPatrick McHardy { 230d62f9ed4SPatrick McHardy int err = 0; 231d62f9ed4SPatrick McHardy 232d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 233d62f9ed4SPatrick McHardy if (l4proto->ctl_table != NULL) { 234d62f9ed4SPatrick McHardy err = nf_ct_register_sysctl(l4proto->ctl_table_header, 235d62f9ed4SPatrick McHardy nf_net_netfilter_sysctl_path, 236d62f9ed4SPatrick McHardy l4proto->ctl_table, 237d62f9ed4SPatrick McHardy l4proto->ctl_table_users); 238a999e683SPatrick McHardy if (err < 0) 239a999e683SPatrick McHardy goto out; 240d62f9ed4SPatrick McHardy } 241a999e683SPatrick McHardy #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 242a999e683SPatrick McHardy if (l4proto->ctl_compat_table != NULL) { 243a999e683SPatrick McHardy err = nf_ct_register_sysctl(&l4proto->ctl_compat_table_header, 244a999e683SPatrick McHardy nf_net_ipv4_netfilter_sysctl_path, 245a999e683SPatrick McHardy l4proto->ctl_compat_table, NULL); 246a999e683SPatrick McHardy if (err == 0) 247a999e683SPatrick McHardy goto out; 248a999e683SPatrick McHardy nf_ct_unregister_sysctl(l4proto->ctl_table_header, 249a999e683SPatrick McHardy l4proto->ctl_table, 250a999e683SPatrick McHardy l4proto->ctl_table_users); 251a999e683SPatrick McHardy } 252a999e683SPatrick McHardy #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 253a999e683SPatrick McHardy out: 254933a41e7SPatrick McHardy #endif /* CONFIG_SYSCTL */ 255d62f9ed4SPatrick McHardy return err; 256d62f9ed4SPatrick McHardy } 257d62f9ed4SPatrick McHardy 258d62f9ed4SPatrick McHardy static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto) 259d62f9ed4SPatrick McHardy { 260d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 261d62f9ed4SPatrick McHardy if (l4proto->ctl_table_header != NULL && 262d62f9ed4SPatrick McHardy *l4proto->ctl_table_header != NULL) 263d62f9ed4SPatrick McHardy nf_ct_unregister_sysctl(l4proto->ctl_table_header, 264d62f9ed4SPatrick McHardy l4proto->ctl_table, 265d62f9ed4SPatrick McHardy l4proto->ctl_table_users); 266a999e683SPatrick McHardy #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 267a999e683SPatrick McHardy if (l4proto->ctl_compat_table_header != NULL) 268a999e683SPatrick McHardy nf_ct_unregister_sysctl(&l4proto->ctl_compat_table_header, 269a999e683SPatrick McHardy l4proto->ctl_compat_table, NULL); 270a999e683SPatrick McHardy #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 271933a41e7SPatrick McHardy #endif /* CONFIG_SYSCTL */ 272d62f9ed4SPatrick McHardy } 273d62f9ed4SPatrick McHardy 2748f03dea5SMartin Josefsson /* FIXME: Allow NULL functions and sub in pointers to generic for 2758f03dea5SMartin Josefsson them. --RR */ 276605dcad6SMartin Josefsson int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto) 2778f03dea5SMartin Josefsson { 2788f03dea5SMartin Josefsson int ret = 0; 2798f03dea5SMartin Josefsson 2800661cca9SPatrick McHardy if (l4proto->l3proto >= PF_MAX) 2810661cca9SPatrick McHardy return -EBUSY; 282ae5718fbSMartin Josefsson 283b19caa0cSPatrick McHardy mutex_lock(&nf_ct_proto_mutex); 284c6a1e615SPatrick McHardy if (!nf_ct_protos[l4proto->l3proto]) { 2858f03dea5SMartin Josefsson /* l3proto may be loaded latter. */ 286605dcad6SMartin Josefsson struct nf_conntrack_l4proto **proto_array; 2878f03dea5SMartin Josefsson int i; 2888f03dea5SMartin Josefsson 289c6a1e615SPatrick McHardy proto_array = kmalloc(MAX_NF_CT_PROTO * 290605dcad6SMartin Josefsson sizeof(struct nf_conntrack_l4proto *), 2918f03dea5SMartin Josefsson GFP_KERNEL); 2928f03dea5SMartin Josefsson if (proto_array == NULL) { 2938f03dea5SMartin Josefsson ret = -ENOMEM; 294b19caa0cSPatrick McHardy goto out_unlock; 2958f03dea5SMartin Josefsson } 296c6a1e615SPatrick McHardy 2978f03dea5SMartin Josefsson for (i = 0; i < MAX_NF_CT_PROTO; i++) 298605dcad6SMartin Josefsson proto_array[i] = &nf_conntrack_l4proto_generic; 299605dcad6SMartin Josefsson nf_ct_protos[l4proto->l3proto] = proto_array; 300c6a1e615SPatrick McHardy } else if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto] != 301c6a1e615SPatrick McHardy &nf_conntrack_l4proto_generic) { 302c6a1e615SPatrick McHardy ret = -EBUSY; 303c6a1e615SPatrick McHardy goto out_unlock; 3048f03dea5SMartin Josefsson } 3058f03dea5SMartin Josefsson 306d62f9ed4SPatrick McHardy ret = nf_ct_l4proto_register_sysctl(l4proto); 307d62f9ed4SPatrick McHardy if (ret < 0) 3080661cca9SPatrick McHardy goto out_unlock; 3090661cca9SPatrick McHardy 310c6a1e615SPatrick McHardy rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 311c6a1e615SPatrick McHardy l4proto); 3128f03dea5SMartin Josefsson 3138f03dea5SMartin Josefsson out_unlock: 314b19caa0cSPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 3158f03dea5SMartin Josefsson return ret; 3168f03dea5SMartin Josefsson } 31713b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register); 3188f03dea5SMartin Josefsson 319fe3eb20cSPatrick McHardy void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto) 3208f03dea5SMartin Josefsson { 321fe3eb20cSPatrick McHardy BUG_ON(l4proto->l3proto >= PF_MAX); 322ae5718fbSMartin Josefsson 323b19caa0cSPatrick McHardy mutex_lock(&nf_ct_proto_mutex); 324fe3eb20cSPatrick McHardy BUG_ON(nf_ct_protos[l4proto->l3proto][l4proto->l4proto] != l4proto); 325923f4902SPatrick McHardy rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 326923f4902SPatrick McHardy &nf_conntrack_l4proto_generic); 327d62f9ed4SPatrick McHardy nf_ct_l4proto_unregister_sysctl(l4proto); 3280661cca9SPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 3290661cca9SPatrick McHardy 3300661cca9SPatrick McHardy synchronize_rcu(); 331d62f9ed4SPatrick McHardy 3328f03dea5SMartin Josefsson /* Remove all contrack entries for this protocol */ 333605dcad6SMartin Josefsson nf_ct_iterate_cleanup(kill_l4proto, l4proto); 3348f03dea5SMartin Josefsson } 33513b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister); 336ac5357ebSPatrick McHardy 337ac5357ebSPatrick McHardy int nf_conntrack_proto_init(void) 338ac5357ebSPatrick McHardy { 339ac5357ebSPatrick McHardy unsigned int i; 340ac5357ebSPatrick McHardy int err; 341ac5357ebSPatrick McHardy 342ac5357ebSPatrick McHardy err = nf_ct_l4proto_register_sysctl(&nf_conntrack_l4proto_generic); 343ac5357ebSPatrick McHardy if (err < 0) 344ac5357ebSPatrick McHardy return err; 345ac5357ebSPatrick McHardy 346ac5357ebSPatrick McHardy for (i = 0; i < AF_MAX; i++) 347ac5357ebSPatrick McHardy rcu_assign_pointer(nf_ct_l3protos[i], 348ac5357ebSPatrick McHardy &nf_conntrack_l3proto_generic); 349ac5357ebSPatrick McHardy return 0; 350ac5357ebSPatrick McHardy } 351ac5357ebSPatrick McHardy 352ac5357ebSPatrick McHardy void nf_conntrack_proto_fini(void) 353ac5357ebSPatrick McHardy { 354ac5357ebSPatrick McHardy unsigned int i; 355ac5357ebSPatrick McHardy 356ac5357ebSPatrick McHardy nf_ct_l4proto_unregister_sysctl(&nf_conntrack_l4proto_generic); 357ac5357ebSPatrick McHardy 358ac5357ebSPatrick McHardy /* free l3proto protocol tables */ 359ac5357ebSPatrick McHardy for (i = 0; i < PF_MAX; i++) 360ac5357ebSPatrick McHardy kfree(nf_ct_protos[i]); 361ac5357ebSPatrick McHardy } 362