static int __init nf_conntrack_l3proto_ipv6_init(void)
{
	int ret = 0;

	need_conntrack();

	ret = nf_ct_frag6_init();
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't initialize frag6.\n");
		return ret;
	}
	ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register tcp.\n");
		goto cleanup_frag6;
	}

	ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register udp.\n");
		goto cleanup_tcp;
	}

	ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmpv6);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register icmpv6.\n");
		goto cleanup_udp;
	}

	ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register ipv6\n");
		goto cleanup_icmpv6;
	}

	ret = nf_register_hooks(ipv6_conntrack_ops,
				ARRAY_SIZE(ipv6_conntrack_ops));
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register pre-routing defrag "
		       "hook.\n");
		goto cleanup_ipv6;
	}
	return ret;

 cleanup_ipv6:
	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
 cleanup_icmpv6:
	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6);
 cleanup_udp:
	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6);
 cleanup_tcp:
	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
 cleanup_frag6:
	nf_ct_frag6_cleanup();
	return ret;
}
static void __exit nf_conntrack_l3proto_ipv6_fini(void)
{
	synchronize_net();
	nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6);
	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6);
	nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
	nf_ct_frag6_cleanup();
}
static int __init nf_defrag_init(void)
{
	int ret = 0;

	ret = nf_ct_frag6_init();
	if (ret < 0) {
		pr_err("nf_defrag_ipv6: can't initialize frag6.\n");
		return ret;
	}
	ret = nf_register_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops));
	if (ret < 0) {
		pr_err("nf_defrag_ipv6: can't register hooks\n");
		goto cleanup_frag6;
	}
	return ret;

cleanup_frag6:
	nf_ct_frag6_cleanup();
	return ret;

}
static void __exit nf_defrag_fini(void)
{
	nf_unregister_hooks(ipv6_defrag_ops, ARRAY_SIZE(ipv6_defrag_ops));
	nf_ct_frag6_cleanup();
}
static int init_or_cleanup(int init)
{
	int ret = 0;

	if (!init) goto cleanup;

	ret = nf_ct_frag6_init();
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't initialize frag6.\n");
		goto cleanup_nothing;
	}
	ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp6);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register tcp.\n");
		goto cleanup_frag6;
	}

	ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_udp6);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register udp.\n");
		goto cleanup_tcp;
	}

	ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_icmpv6);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register icmpv6.\n");
		goto cleanup_udp;
	}

	ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register ipv6\n");
		goto cleanup_icmpv6;
	}

	ret = nf_register_hook(&ipv6_conntrack_defrag_ops);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register pre-routing defrag "
		       "hook.\n");
		goto cleanup_ipv6;
	}

	ret = nf_register_hook(&ipv6_conntrack_defrag_local_out_ops);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register local_out defrag "
		       "hook.\n");
		goto cleanup_defragops;
	}

	ret = nf_register_hook(&ipv6_conntrack_in_ops);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register pre-routing hook.\n");
		goto cleanup_defraglocalops;
	}

	ret = nf_register_hook(&ipv6_conntrack_local_out_ops);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register local out hook.\n");
		goto cleanup_inops;
	}

	ret = nf_register_hook(&ipv6_conntrack_out_ops);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register post-routing hook.\n");
		goto cleanup_inandlocalops;
	}

	ret = nf_register_hook(&ipv6_conntrack_local_in_ops);
	if (ret < 0) {
		printk("nf_conntrack_ipv6: can't register local in hook.\n");
		goto cleanup_inoutandlocalops;
	}

#ifdef CONFIG_SYSCTL
	nf_ct_ipv6_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
	if (nf_ct_ipv6_sysctl_header == NULL) {
		printk("nf_conntrack: can't register to sysctl.\n");
		ret = -ENOMEM;
		goto cleanup_localinops;
	}
#endif
	return ret;

 cleanup:
	synchronize_net();
#ifdef CONFIG_SYSCTL
 	unregister_sysctl_table(nf_ct_ipv6_sysctl_header);
 cleanup_localinops:
#endif
	nf_unregister_hook(&ipv6_conntrack_local_in_ops);
 cleanup_inoutandlocalops:
	nf_unregister_hook(&ipv6_conntrack_out_ops);
 cleanup_inandlocalops:
	nf_unregister_hook(&ipv6_conntrack_local_out_ops);
 cleanup_inops:
	nf_unregister_hook(&ipv6_conntrack_in_ops);
 cleanup_defraglocalops:
	nf_unregister_hook(&ipv6_conntrack_defrag_local_out_ops);
 cleanup_defragops:
	nf_unregister_hook(&ipv6_conntrack_defrag_ops);
 cleanup_ipv6:
	nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
 cleanup_icmpv6:
	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmpv6);
 cleanup_udp:
	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp6);
 cleanup_tcp:
	nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp6);
 cleanup_frag6:
	nf_ct_frag6_cleanup();
 cleanup_nothing:
	return ret;
}