Example #1
0
static int __init nf_nat_standalone_init(void)
{
    int ret = 0;

    need_ipv4_conntrack();

#ifdef CONFIG_XFRM
    BUG_ON(ip_nat_decode_session != NULL);
    rcu_assign_pointer_nonull(ip_nat_decode_session, nat_decode_session);
#endif
    ret = nf_nat_rule_init();
    if (ret < 0) {
        pr_err("nf_nat_init: can't setup rules.\n");
        goto cleanup_decode_session;
    }
    ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
    if (ret < 0) {
        pr_err("nf_nat_init: can't register hooks.\n");
        goto cleanup_rule_init;
    }
    return ret;

cleanup_rule_init:
    nf_nat_rule_cleanup();
cleanup_decode_session:
#ifdef CONFIG_XFRM
    rcu_assign_pointer(ip_nat_decode_session, NULL);
    synchronize_net();
#endif
    return ret;
}
/* FIXME: Allow NULL functions and sub in pointers to generic for
   them. --RR */
int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
{
	int ret = 0;

	if (l4proto->l3proto >= PF_MAX)
		return -EBUSY;

	if ((l4proto->to_nlattr && !l4proto->nlattr_size)
		|| (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size))
		return -EINVAL;

	mutex_lock(&nf_ct_proto_mutex);
	if (!nf_ct_protos[l4proto->l3proto]) {
		/* l3proto may be loaded latter. */
		struct nf_conntrack_l4proto __rcu **proto_array;
		int i;

		proto_array = kmalloc(MAX_NF_CT_PROTO *
				      sizeof(struct nf_conntrack_l4proto *),
				      GFP_KERNEL);
		if (proto_array == NULL) {
			ret = -ENOMEM;
			goto out_unlock;
		}

		for (i = 0; i < MAX_NF_CT_PROTO; i++)
			RCU_INIT_POINTER(proto_array[i], &nf_conntrack_l4proto_generic);

		/* Before making proto_array visible to lockless readers,
		 * we must make sure its content is committed to memory.
		 */
		smp_wmb();

		nf_ct_protos[l4proto->l3proto] = proto_array;
	} else if (rcu_dereference_protected(
			nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
			lockdep_is_held(&nf_ct_proto_mutex)
			) != &nf_conntrack_l4proto_generic) {
		ret = -EBUSY;
		goto out_unlock;
	}

	ret = nf_ct_l4proto_register_sysctl(l4proto);
	if (ret < 0)
		goto out_unlock;

	l4proto->nla_size = 0;
	if (l4proto->nlattr_size)
		l4proto->nla_size += l4proto->nlattr_size();
	if (l4proto->nlattr_tuple_size)
		l4proto->nla_size += 3 * l4proto->nlattr_tuple_size();

	rcu_assign_pointer_nonull(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
			   l4proto);

out_unlock:
	mutex_unlock(&nf_ct_proto_mutex);
	return ret;
}
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_nonull(nf_ct_l3protos[i],
				   &nf_conntrack_l3proto_generic);
	return 0;
}
static int __init nf_nat_sip_init(void)
{
	BUG_ON(nf_nat_sip_hook != NULL);
	BUG_ON(nf_nat_sip_seq_adjust_hook != NULL);
	BUG_ON(nf_nat_sip_expect_hook != NULL);
	BUG_ON(nf_nat_sdp_addr_hook != NULL);
	BUG_ON(nf_nat_sdp_port_hook != NULL);
	BUG_ON(nf_nat_sdp_session_hook != NULL);
	BUG_ON(nf_nat_sdp_media_hook != NULL);
	rcu_assign_pointer_nonull(nf_nat_sip_hook, ip_nat_sip);
	rcu_assign_pointer_nonull(nf_nat_sip_seq_adjust_hook, ip_nat_sip_seq_adjust);
	rcu_assign_pointer_nonull(nf_nat_sip_expect_hook, ip_nat_sip_expect);
	rcu_assign_pointer_nonull(nf_nat_sdp_addr_hook, ip_nat_sdp_addr);
	rcu_assign_pointer_nonull(nf_nat_sdp_port_hook, ip_nat_sdp_port);
	rcu_assign_pointer_nonull(nf_nat_sdp_session_hook, ip_nat_sdp_session);
	rcu_assign_pointer_nonull(nf_nat_sdp_media_hook, ip_nat_sdp_media);
	return 0;
}
void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
{
	struct net *net;

	BUG_ON(l4proto->l3proto >= PF_MAX);

	mutex_lock(&nf_ct_proto_mutex);
	BUG_ON(nf_ct_protos[l4proto->l3proto][l4proto->l4proto] != l4proto);
	rcu_assign_pointer_nonull(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
			   &nf_conntrack_l4proto_generic);
	nf_ct_l4proto_unregister_sysctl(l4proto);
	mutex_unlock(&nf_ct_proto_mutex);

	synchronize_rcu();

	/* Remove all contrack entries for this protocol */
	rtnl_lock();
	for_each_net(net)
		nf_ct_iterate_cleanup(net, kill_l4proto, l4proto);
	rtnl_unlock();
}
void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
{
	struct net *net;

	BUG_ON(proto->l3proto >= AF_MAX);

	mutex_lock(&nf_ct_proto_mutex);
	BUG_ON(rcu_dereference_protected(nf_ct_l3protos[proto->l3proto],
					 lockdep_is_held(&nf_ct_proto_mutex)
					 ) != proto);
	rcu_assign_pointer_nonull(nf_ct_l3protos[proto->l3proto],
			   &nf_conntrack_l3proto_generic);
	nf_ct_l3proto_unregister_sysctl(proto);
	mutex_unlock(&nf_ct_proto_mutex);

	synchronize_rcu();

	/* Remove all contrack entries for this protocol */
	rtnl_lock();
	for_each_net(net)
		nf_ct_iterate_cleanup(net, kill_l3proto, proto);
	rtnl_unlock();
}
static int __init nf_nat_ftp_init(void)
{
	BUG_ON(nf_nat_ftp_hook != NULL);
	rcu_assign_pointer_nonull(nf_nat_ftp_hook, nf_nat_ftp);
	return 0;
}