/*
 *	Mobile IPv6 Common Module
 *
 *	Authors:
 *	Sami Kivisaari          <skivisaa@cc.hut.fi>
 *	Antti Tuominen          <ajtuomin@tml.hut.fi>
 *
 *	$Id: module_cn.c,v 1.2 2003/06/17 18:53:13 jamey Exp $
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	as published by the Free Software Foundation; either version
 *	2 of the License, or (at your option) any later version.
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>

#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
#endif /* CONFIG_SYSCTL */

#include <net/mipglue.h>

#include "bcache.h"
#include "stats.h"
#include "mobhdr.h"
#include "exthdrs.h"

int mipv6_debug = 1;
int mipv6_use_auth = 0;

#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
MODULE_AUTHOR("MIPL Team");
MODULE_DESCRIPTION("Mobile IPv6");
MODULE_LICENSE("GPL");
MODULE_PARM(mipv6_debug, "i");
#endif

#include "config.h"
int mipv6_cap = 0;

#define MIPV6_BCACHE_SIZE 128

/**********************************************************************
 *
 * MIPv6 CN Module Init / Cleanup
 *
 **********************************************************************/

#ifdef CONFIG_SYSCTL
/* Sysctl table */
ctl_table mipv6_mobility_table[] = {
	{NET_IPV6_MOBILITY_DEBUG, "debuglevel",
	 &mipv6_debug, sizeof(int), 0644, NULL,
	 &proc_dointvec},
	{NET_IPV6_MOBILITY_AUTH, "use_auth",
	 &mipv6_use_auth, sizeof(int), 0644, NULL,
	 &proc_dointvec},
	{0}
};
ctl_table mipv6_table[] = {
	{NET_IPV6_MOBILITY, "mobility", NULL, 0, 0555, mipv6_mobility_table},
	{0}
};

static struct ctl_table_header *mipv6_sysctl_header;
static struct ctl_table mipv6_net_table[];
static struct ctl_table mipv6_root_table[];

ctl_table mipv6_net_table[] = {
	{NET_IPV6, "ipv6", NULL, 0, 0555, mipv6_table},
	{0}
};

ctl_table mipv6_root_table[] = {
	{CTL_NET, "net", NULL, 0, 0555, mipv6_net_table},
	{0}
};
#endif /* CONFIG_SYSCTL */

extern void mipv6_rr_init(void);

/*  Initialize the module  */
int __init init_module(void)
{
	int err = 0;

	printk(KERN_INFO "MIPL Mobile IPv6 for Linux Correspondent Node %s (%s)\n",
	       MIPLVERSION, MIPV6VERSION);
	mipv6_cap = CAP_CN;

#ifdef CONFIG_IPV6_MOBILITY_DEBUG
	printk(KERN_INFO "Debug-level: %d\n", mipv6_debug);
#endif
	if ((err = mipv6_bcache_init(MIPV6_BCACHE_SIZE)) < 0)
		goto bcache_fail;

	if ((err = mipv6_stats_init()) < 0)
		goto stats_fail;
	mipv6_rr_init();

#ifdef CONFIG_SYSCTL
	mipv6_sysctl_header = register_sysctl_table(mipv6_root_table, 0);
#endif

	if ((err = mipv6_mh_common_init()) < 0)
		goto mh_fail;

	MIPV6_SETCALL(mipv6_modify_txoptions, mipv6_modify_txoptions);
		
	MIPV6_SETCALL(mipv6_handle_homeaddr, mipv6_handle_homeaddr);
	MIPV6_SETCALL(mipv6_icmp_handle_homeaddr, mipv6_icmp_handle_homeaddr);

	return 0;

mh_fail:
#ifdef CONFIG_SYSCTL
	unregister_sysctl_table(mipv6_sysctl_header);
#endif
	mipv6_stats_exit();
stats_fail:
	mipv6_bcache_exit();
bcache_fail:
	return err;
}

/*  Cleanup module  */
void __exit cleanup_module(void)
{
	printk(KERN_INFO "exiting.\n");
#ifdef CONFIG_SYSCTL
	unregister_sysctl_table(mipv6_sysctl_header);
#endif

	/* Invalidate all custom kernel hooks.  No need to do this
           separately for all hooks. */
	mipv6_invalidate_calls();

	mipv6_mh_common_exit();
	mipv6_stats_exit();
	mipv6_bcache_exit();
}
