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> 155a0e3ad6STejun Heo #include <linux/slab.h> 16d62f9ed4SPatrick McHardy #include <linux/mutex.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/notifier.h> 228f03dea5SMartin Josefsson #include <linux/kernel.h> 238f03dea5SMartin Josefsson #include <linux/netdevice.h> 24efb9a8c2SAlexey Dobriyan #include <linux/rtnetlink.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 310906a372SArnd Bergmann static struct nf_conntrack_l4proto __rcu **nf_ct_protos[PF_MAX] __read_mostly; 320906a372SArnd Bergmann struct nf_conntrack_l3proto __rcu *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 39f99e8f71SEric W. Biederman nf_ct_register_sysctl(struct ctl_table_header **header, const char *path, 40d62f9ed4SPatrick McHardy struct ctl_table *table, unsigned int *users) 41d62f9ed4SPatrick McHardy { 42d62f9ed4SPatrick McHardy if (*header == NULL) { 43f99e8f71SEric W. Biederman *header = register_net_sysctl(&init_net, 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; 58b3fd3ffeSPavel Emelyanov 595dd3df10SEric W. Biederman unregister_net_sysctl_table(*header); 60d62f9ed4SPatrick McHardy *header = NULL; 61d62f9ed4SPatrick McHardy } 62d62f9ed4SPatrick McHardy #endif 63d62f9ed4SPatrick McHardy 64605dcad6SMartin Josefsson struct nf_conntrack_l4proto * 65605dcad6SMartin Josefsson __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto) 668f03dea5SMartin Josefsson { 678f03dea5SMartin Josefsson if (unlikely(l3proto >= AF_MAX || nf_ct_protos[l3proto] == NULL)) 68605dcad6SMartin Josefsson return &nf_conntrack_l4proto_generic; 698f03dea5SMartin Josefsson 70923f4902SPatrick McHardy return rcu_dereference(nf_ct_protos[l3proto][l4proto]); 718f03dea5SMartin Josefsson } 7213b18339SPatrick McHardy EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find); 738f03dea5SMartin Josefsson 748f03dea5SMartin Josefsson /* this is guaranteed to always return a valid protocol helper, since 758f03dea5SMartin Josefsson * it falls back to generic_protocol */ 768f03dea5SMartin Josefsson struct nf_conntrack_l3proto * 778f03dea5SMartin Josefsson nf_ct_l3proto_find_get(u_int16_t l3proto) 788f03dea5SMartin Josefsson { 798f03dea5SMartin Josefsson struct nf_conntrack_l3proto *p; 808f03dea5SMartin Josefsson 81923f4902SPatrick McHardy rcu_read_lock(); 828f03dea5SMartin Josefsson p = __nf_ct_l3proto_find(l3proto); 838f03dea5SMartin Josefsson if (!try_module_get(p->me)) 84605dcad6SMartin Josefsson p = &nf_conntrack_l3proto_generic; 85923f4902SPatrick McHardy rcu_read_unlock(); 868f03dea5SMartin Josefsson 878f03dea5SMartin Josefsson return p; 888f03dea5SMartin Josefsson } 8913b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_ct_l3proto_find_get); 908f03dea5SMartin Josefsson 918f03dea5SMartin Josefsson void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p) 928f03dea5SMartin Josefsson { 938f03dea5SMartin Josefsson module_put(p->me); 948f03dea5SMartin Josefsson } 9513b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_ct_l3proto_put); 968f03dea5SMartin Josefsson 978f03dea5SMartin Josefsson int 988f03dea5SMartin Josefsson nf_ct_l3proto_try_module_get(unsigned short l3proto) 998f03dea5SMartin Josefsson { 1008f03dea5SMartin Josefsson int ret; 1018f03dea5SMartin Josefsson struct nf_conntrack_l3proto *p; 1028f03dea5SMartin Josefsson 1038f03dea5SMartin Josefsson retry: p = nf_ct_l3proto_find_get(l3proto); 104605dcad6SMartin Josefsson if (p == &nf_conntrack_l3proto_generic) { 1058f03dea5SMartin Josefsson ret = request_module("nf_conntrack-%d", l3proto); 1068f03dea5SMartin Josefsson if (!ret) 1078f03dea5SMartin Josefsson goto retry; 1088f03dea5SMartin Josefsson 1098f03dea5SMartin Josefsson return -EPROTOTYPE; 1108f03dea5SMartin Josefsson } 1118f03dea5SMartin Josefsson 1128f03dea5SMartin Josefsson return 0; 1138f03dea5SMartin Josefsson } 11413b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_ct_l3proto_try_module_get); 1158f03dea5SMartin Josefsson 1168f03dea5SMartin Josefsson void nf_ct_l3proto_module_put(unsigned short l3proto) 1178f03dea5SMartin Josefsson { 1188f03dea5SMartin Josefsson struct nf_conntrack_l3proto *p; 1198f03dea5SMartin Josefsson 1203b254c54SPatrick McHardy /* rcu_read_lock not necessary since the caller holds a reference, but 1213b254c54SPatrick McHardy * taken anyways to avoid lockdep warnings in __nf_ct_l3proto_find() 1223b254c54SPatrick McHardy */ 1233b254c54SPatrick McHardy rcu_read_lock(); 1248f03dea5SMartin Josefsson p = __nf_ct_l3proto_find(l3proto); 1258f03dea5SMartin Josefsson module_put(p->me); 1263b254c54SPatrick McHardy rcu_read_unlock(); 1278f03dea5SMartin Josefsson } 12813b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put); 1298f03dea5SMartin Josefsson 130c1ebd7dfSPablo Neira Ayuso struct nf_conntrack_l4proto * 131c1ebd7dfSPablo Neira Ayuso nf_ct_l4proto_find_get(u_int16_t l3num, u_int8_t l4num) 132c1ebd7dfSPablo Neira Ayuso { 133c1ebd7dfSPablo Neira Ayuso struct nf_conntrack_l4proto *p; 134c1ebd7dfSPablo Neira Ayuso 135c1ebd7dfSPablo Neira Ayuso rcu_read_lock(); 136c1ebd7dfSPablo Neira Ayuso p = __nf_ct_l4proto_find(l3num, l4num); 137c1ebd7dfSPablo Neira Ayuso if (!try_module_get(p->me)) 138c1ebd7dfSPablo Neira Ayuso p = &nf_conntrack_l4proto_generic; 139c1ebd7dfSPablo Neira Ayuso rcu_read_unlock(); 140c1ebd7dfSPablo Neira Ayuso 141c1ebd7dfSPablo Neira Ayuso return p; 142c1ebd7dfSPablo Neira Ayuso } 143c1ebd7dfSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get); 144c1ebd7dfSPablo Neira Ayuso 145c1ebd7dfSPablo Neira Ayuso void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p) 146c1ebd7dfSPablo Neira Ayuso { 147c1ebd7dfSPablo Neira Ayuso module_put(p->me); 148c1ebd7dfSPablo Neira Ayuso } 149c1ebd7dfSPablo Neira Ayuso EXPORT_SYMBOL_GPL(nf_ct_l4proto_put); 150c1ebd7dfSPablo Neira Ayuso 1518f03dea5SMartin Josefsson static int kill_l3proto(struct nf_conn *i, void *data) 1528f03dea5SMartin Josefsson { 1535e8fbe2aSPatrick McHardy return nf_ct_l3num(i) == ((struct nf_conntrack_l3proto *)data)->l3proto; 1548f03dea5SMartin Josefsson } 1558f03dea5SMartin Josefsson 156605dcad6SMartin Josefsson static int kill_l4proto(struct nf_conn *i, void *data) 1578f03dea5SMartin Josefsson { 158605dcad6SMartin Josefsson struct nf_conntrack_l4proto *l4proto; 159605dcad6SMartin Josefsson l4proto = (struct nf_conntrack_l4proto *)data; 1605e8fbe2aSPatrick McHardy return nf_ct_protonum(i) == l4proto->l4proto && 1615e8fbe2aSPatrick McHardy nf_ct_l3num(i) == l4proto->l3proto; 1628f03dea5SMartin Josefsson } 1638f03dea5SMartin Josefsson 164d62f9ed4SPatrick McHardy static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto) 165d62f9ed4SPatrick McHardy { 166d62f9ed4SPatrick McHardy int err = 0; 167d62f9ed4SPatrick McHardy 168d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 169d62f9ed4SPatrick McHardy if (l3proto->ctl_table != NULL) { 170d62f9ed4SPatrick McHardy err = nf_ct_register_sysctl(&l3proto->ctl_table_header, 171d62f9ed4SPatrick McHardy l3proto->ctl_table_path, 172d62f9ed4SPatrick McHardy l3proto->ctl_table, NULL); 173d62f9ed4SPatrick McHardy } 174d62f9ed4SPatrick McHardy #endif 175d62f9ed4SPatrick McHardy return err; 176d62f9ed4SPatrick McHardy } 177d62f9ed4SPatrick McHardy 178d62f9ed4SPatrick McHardy static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto) 179d62f9ed4SPatrick McHardy { 180d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 181d62f9ed4SPatrick McHardy if (l3proto->ctl_table_header != NULL) 182d62f9ed4SPatrick McHardy nf_ct_unregister_sysctl(&l3proto->ctl_table_header, 183d62f9ed4SPatrick McHardy l3proto->ctl_table, NULL); 184d62f9ed4SPatrick McHardy #endif 185d62f9ed4SPatrick McHardy } 186d62f9ed4SPatrick McHardy 1878f03dea5SMartin Josefsson int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) 1888f03dea5SMartin Josefsson { 1898f03dea5SMartin Josefsson int ret = 0; 1900e60ebe0SEric Dumazet struct nf_conntrack_l3proto *old; 1918f03dea5SMartin Josefsson 1920661cca9SPatrick McHardy if (proto->l3proto >= AF_MAX) 1930661cca9SPatrick McHardy return -EBUSY; 1948f03dea5SMartin Josefsson 195d0dba725SHolger Eitzenberger if (proto->tuple_to_nlattr && !proto->nlattr_tuple_size) 196d0dba725SHolger Eitzenberger return -EINVAL; 197d0dba725SHolger Eitzenberger 198b19caa0cSPatrick McHardy mutex_lock(&nf_ct_proto_mutex); 1990e60ebe0SEric Dumazet old = rcu_dereference_protected(nf_ct_l3protos[proto->l3proto], 2000e60ebe0SEric Dumazet lockdep_is_held(&nf_ct_proto_mutex)); 2010e60ebe0SEric Dumazet if (old != &nf_conntrack_l3proto_generic) { 202ae5718fbSMartin Josefsson ret = -EBUSY; 203ae5718fbSMartin Josefsson goto out_unlock; 204ae5718fbSMartin Josefsson } 205d62f9ed4SPatrick McHardy 206d62f9ed4SPatrick McHardy ret = nf_ct_l3proto_register_sysctl(proto); 207d62f9ed4SPatrick McHardy if (ret < 0) 2080661cca9SPatrick McHardy goto out_unlock; 2090661cca9SPatrick McHardy 210d0dba725SHolger Eitzenberger if (proto->nlattr_tuple_size) 211d0dba725SHolger Eitzenberger proto->nla_size = 3 * proto->nlattr_tuple_size(); 212d0dba725SHolger Eitzenberger 2130661cca9SPatrick McHardy rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto); 214ae5718fbSMartin Josefsson 215ae5718fbSMartin Josefsson out_unlock: 216b19caa0cSPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 2178f03dea5SMartin Josefsson return ret; 2188f03dea5SMartin Josefsson } 21913b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register); 2208f03dea5SMartin Josefsson 221fe3eb20cSPatrick McHardy void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto) 2228f03dea5SMartin Josefsson { 223678d6675SAlexey Dobriyan struct net *net; 224678d6675SAlexey Dobriyan 225fe3eb20cSPatrick McHardy BUG_ON(proto->l3proto >= AF_MAX); 226ae5718fbSMartin Josefsson 227b19caa0cSPatrick McHardy mutex_lock(&nf_ct_proto_mutex); 2280e60ebe0SEric Dumazet BUG_ON(rcu_dereference_protected(nf_ct_l3protos[proto->l3proto], 2290e60ebe0SEric Dumazet lockdep_is_held(&nf_ct_proto_mutex) 2300e60ebe0SEric Dumazet ) != proto); 231923f4902SPatrick McHardy rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], 232923f4902SPatrick McHardy &nf_conntrack_l3proto_generic); 233d62f9ed4SPatrick McHardy nf_ct_l3proto_unregister_sysctl(proto); 2340661cca9SPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 2350661cca9SPatrick McHardy 2360661cca9SPatrick McHardy synchronize_rcu(); 237d62f9ed4SPatrick McHardy 2388f03dea5SMartin Josefsson /* Remove all contrack entries for this protocol */ 239efb9a8c2SAlexey Dobriyan rtnl_lock(); 240678d6675SAlexey Dobriyan for_each_net(net) 241678d6675SAlexey Dobriyan nf_ct_iterate_cleanup(net, kill_l3proto, proto); 242efb9a8c2SAlexey Dobriyan rtnl_unlock(); 2438f03dea5SMartin Josefsson } 24413b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister); 2458f03dea5SMartin Josefsson 246d62f9ed4SPatrick McHardy static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto) 247d62f9ed4SPatrick McHardy { 248d62f9ed4SPatrick McHardy int err = 0; 249d62f9ed4SPatrick McHardy 250d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 251d62f9ed4SPatrick McHardy if (l4proto->ctl_table != NULL) { 252d62f9ed4SPatrick McHardy err = nf_ct_register_sysctl(l4proto->ctl_table_header, 253f99e8f71SEric W. Biederman "net/netfilter", 254d62f9ed4SPatrick McHardy l4proto->ctl_table, 255d62f9ed4SPatrick McHardy l4proto->ctl_table_users); 256a999e683SPatrick McHardy if (err < 0) 257a999e683SPatrick McHardy goto out; 258d62f9ed4SPatrick McHardy } 259a999e683SPatrick McHardy #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 260a999e683SPatrick McHardy if (l4proto->ctl_compat_table != NULL) { 261a999e683SPatrick McHardy err = nf_ct_register_sysctl(&l4proto->ctl_compat_table_header, 262f99e8f71SEric W. Biederman "net/ipv4/netfilter", 263a999e683SPatrick McHardy l4proto->ctl_compat_table, NULL); 264a999e683SPatrick McHardy if (err == 0) 265a999e683SPatrick McHardy goto out; 266a999e683SPatrick McHardy nf_ct_unregister_sysctl(l4proto->ctl_table_header, 267a999e683SPatrick McHardy l4proto->ctl_table, 268a999e683SPatrick McHardy l4proto->ctl_table_users); 269a999e683SPatrick McHardy } 270a999e683SPatrick McHardy #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 271a999e683SPatrick McHardy out: 272933a41e7SPatrick McHardy #endif /* CONFIG_SYSCTL */ 273d62f9ed4SPatrick McHardy return err; 274d62f9ed4SPatrick McHardy } 275d62f9ed4SPatrick McHardy 276d62f9ed4SPatrick McHardy static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto) 277d62f9ed4SPatrick McHardy { 278d62f9ed4SPatrick McHardy #ifdef CONFIG_SYSCTL 279d62f9ed4SPatrick McHardy if (l4proto->ctl_table_header != NULL && 280d62f9ed4SPatrick McHardy *l4proto->ctl_table_header != NULL) 281d62f9ed4SPatrick McHardy nf_ct_unregister_sysctl(l4proto->ctl_table_header, 282d62f9ed4SPatrick McHardy l4proto->ctl_table, 283d62f9ed4SPatrick McHardy l4proto->ctl_table_users); 284a999e683SPatrick McHardy #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 285a999e683SPatrick McHardy if (l4proto->ctl_compat_table_header != NULL) 286a999e683SPatrick McHardy nf_ct_unregister_sysctl(&l4proto->ctl_compat_table_header, 287a999e683SPatrick McHardy l4proto->ctl_compat_table, NULL); 288a999e683SPatrick McHardy #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 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 2980661cca9SPatrick McHardy if (l4proto->l3proto >= PF_MAX) 2990661cca9SPatrick McHardy return -EBUSY; 300ae5718fbSMartin Josefsson 301d0dba725SHolger Eitzenberger if ((l4proto->to_nlattr && !l4proto->nlattr_size) 302d0dba725SHolger Eitzenberger || (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size)) 303d0dba725SHolger Eitzenberger return -EINVAL; 304d0dba725SHolger Eitzenberger 305b19caa0cSPatrick McHardy mutex_lock(&nf_ct_proto_mutex); 306c6a1e615SPatrick McHardy if (!nf_ct_protos[l4proto->l3proto]) { 3078f03dea5SMartin Josefsson /* l3proto may be loaded latter. */ 308c5d277d2SEric Dumazet struct nf_conntrack_l4proto __rcu **proto_array; 3098f03dea5SMartin Josefsson int i; 3108f03dea5SMartin Josefsson 311c6a1e615SPatrick McHardy proto_array = kmalloc(MAX_NF_CT_PROTO * 312605dcad6SMartin Josefsson sizeof(struct nf_conntrack_l4proto *), 3138f03dea5SMartin Josefsson GFP_KERNEL); 3148f03dea5SMartin Josefsson if (proto_array == NULL) { 3158f03dea5SMartin Josefsson ret = -ENOMEM; 316b19caa0cSPatrick McHardy goto out_unlock; 3178f03dea5SMartin Josefsson } 318c6a1e615SPatrick McHardy 3198f03dea5SMartin Josefsson for (i = 0; i < MAX_NF_CT_PROTO; i++) 320c5d277d2SEric Dumazet RCU_INIT_POINTER(proto_array[i], &nf_conntrack_l4proto_generic); 321d817d29dSEric Dumazet 322d817d29dSEric Dumazet /* Before making proto_array visible to lockless readers, 323d817d29dSEric Dumazet * we must make sure its content is committed to memory. 324d817d29dSEric Dumazet */ 325d817d29dSEric Dumazet smp_wmb(); 326d817d29dSEric Dumazet 327605dcad6SMartin Josefsson nf_ct_protos[l4proto->l3proto] = proto_array; 3280e60ebe0SEric Dumazet } else if (rcu_dereference_protected( 3290e60ebe0SEric Dumazet nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 3300e60ebe0SEric Dumazet lockdep_is_held(&nf_ct_proto_mutex) 3310e60ebe0SEric Dumazet ) != &nf_conntrack_l4proto_generic) { 332c6a1e615SPatrick McHardy ret = -EBUSY; 333c6a1e615SPatrick McHardy goto out_unlock; 3348f03dea5SMartin Josefsson } 3358f03dea5SMartin Josefsson 336d62f9ed4SPatrick McHardy ret = nf_ct_l4proto_register_sysctl(l4proto); 337d62f9ed4SPatrick McHardy if (ret < 0) 3380661cca9SPatrick McHardy goto out_unlock; 3390661cca9SPatrick McHardy 340d0dba725SHolger Eitzenberger l4proto->nla_size = 0; 341d0dba725SHolger Eitzenberger if (l4proto->nlattr_size) 342d0dba725SHolger Eitzenberger l4proto->nla_size += l4proto->nlattr_size(); 343d0dba725SHolger Eitzenberger if (l4proto->nlattr_tuple_size) 344d0dba725SHolger Eitzenberger l4proto->nla_size += 3 * l4proto->nlattr_tuple_size(); 345d0dba725SHolger Eitzenberger 346c6a1e615SPatrick McHardy rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 347c6a1e615SPatrick McHardy l4proto); 3488f03dea5SMartin Josefsson 3498f03dea5SMartin Josefsson out_unlock: 350b19caa0cSPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 3518f03dea5SMartin Josefsson return ret; 3528f03dea5SMartin Josefsson } 35313b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register); 3548f03dea5SMartin Josefsson 355fe3eb20cSPatrick McHardy void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto) 3568f03dea5SMartin Josefsson { 357678d6675SAlexey Dobriyan struct net *net; 358678d6675SAlexey Dobriyan 359fe3eb20cSPatrick McHardy BUG_ON(l4proto->l3proto >= PF_MAX); 360ae5718fbSMartin Josefsson 361b19caa0cSPatrick McHardy mutex_lock(&nf_ct_proto_mutex); 3620e60ebe0SEric Dumazet BUG_ON(rcu_dereference_protected( 3630e60ebe0SEric Dumazet nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 3640e60ebe0SEric Dumazet lockdep_is_held(&nf_ct_proto_mutex) 3650e60ebe0SEric Dumazet ) != l4proto); 366923f4902SPatrick McHardy rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], 367923f4902SPatrick McHardy &nf_conntrack_l4proto_generic); 368d62f9ed4SPatrick McHardy nf_ct_l4proto_unregister_sysctl(l4proto); 3690661cca9SPatrick McHardy mutex_unlock(&nf_ct_proto_mutex); 3700661cca9SPatrick McHardy 3710661cca9SPatrick McHardy synchronize_rcu(); 372d62f9ed4SPatrick McHardy 3738f03dea5SMartin Josefsson /* Remove all contrack entries for this protocol */ 374efb9a8c2SAlexey Dobriyan rtnl_lock(); 375678d6675SAlexey Dobriyan for_each_net(net) 376678d6675SAlexey Dobriyan nf_ct_iterate_cleanup(net, kill_l4proto, l4proto); 377efb9a8c2SAlexey Dobriyan rtnl_unlock(); 3788f03dea5SMartin Josefsson } 37913b18339SPatrick McHardy EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister); 380ac5357ebSPatrick McHardy 381ac5357ebSPatrick McHardy int nf_conntrack_proto_init(void) 382ac5357ebSPatrick McHardy { 383ac5357ebSPatrick McHardy unsigned int i; 384ac5357ebSPatrick McHardy int err; 385ac5357ebSPatrick McHardy 386ac5357ebSPatrick McHardy err = nf_ct_l4proto_register_sysctl(&nf_conntrack_l4proto_generic); 387ac5357ebSPatrick McHardy if (err < 0) 388ac5357ebSPatrick McHardy return err; 389ac5357ebSPatrick McHardy 390ac5357ebSPatrick McHardy for (i = 0; i < AF_MAX; i++) 391ac5357ebSPatrick McHardy rcu_assign_pointer(nf_ct_l3protos[i], 392ac5357ebSPatrick McHardy &nf_conntrack_l3proto_generic); 393ac5357ebSPatrick McHardy return 0; 394ac5357ebSPatrick McHardy } 395ac5357ebSPatrick McHardy 396ac5357ebSPatrick McHardy void nf_conntrack_proto_fini(void) 397ac5357ebSPatrick McHardy { 398ac5357ebSPatrick McHardy unsigned int i; 399ac5357ebSPatrick McHardy 400ac5357ebSPatrick McHardy nf_ct_l4proto_unregister_sysctl(&nf_conntrack_l4proto_generic); 401ac5357ebSPatrick McHardy 402ac5357ebSPatrick McHardy /* free l3proto protocol tables */ 403ac5357ebSPatrick McHardy for (i = 0; i < PF_MAX; i++) 404ac5357ebSPatrick McHardy kfree(nf_ct_protos[i]); 405ac5357ebSPatrick McHardy } 406