/* $Id: mn.h 1.85 06/05/15 13:45:42+03:00 vnuorval@tcs.hut.fi $ */

#ifndef __MN_H__
#define __MN_H__ 1

#include <net/if.h>
#include <netinet/in.h>
#include "list.h"
#include "hash.h"
#include "prefix.h"
#include "tqueue.h"

#define DEREG_BU_LIFETIME               420
extern const struct timespec dereg_bu_lifetime_ts;
#define DEREG_BU_LIFETIME_TS dereg_bu_lifetime_ts

#define BU_REFRESH_DELAY                95/100
#define MPS_REFRESH_DELAY               9/10
#define MN_RR_BEFORE_EXPIRE             1 /* second */
#define MN_TEST_INIT_DELAY		5 /* XXX: second */

#define	IFA_F_HOMEADDRESS_NODAD	(IFA_F_HOMEADDRESS | IFA_F_NODAD)

#define NON_MIP_CN_LTIME                420 /* s */
extern const struct timespec non_mip_cn_ltime_ts;
#define NON_MIP_CN_LTIME_TS non_mip_cn_ltime_ts

#define MN_BE_TIME_THRESHOLD            10 /* last use of binding at
					    * which we still delete a
					    * bule in response to BE,
					    * in seconds */
#define MN_RO_RESTART_THRESHOLD         10 /* s */
#define MIN_VALID_BU_LIFETIME           4 /* seconds */
extern const struct timespec min_valid_bu_lifetime_ts;
#define MIN_VALID_BU_LIFETIME_TS min_valid_bu_lifetime_ts

struct ha_candidate_list {
	struct list_head home_agents;
	struct tq_elem tqe;
	struct timespec dhaad_delay;
	struct in6_addr last_ha;
	int dhaad_resends;
	int dhaad_id;
	int if_block;
	pthread_mutex_t c_lock;
};

#define	HOME_LINK_BLOCK	0x01
#define	HOME_ADDR_BLOCK	0x02
#define	HOME_ADDR_RULE_BLOCK	0x04
#define	NEMO_RA_BLOCK	0x08
#define	NEMO_FWD_BLOCK	0x10

struct mn_addr {
	struct in6_addr addr;
	int iif;
	struct timespec timestamp;
	struct timespec valid_time;
	struct timespec preferred_time;
};

#define HOME_REG_NONE 0
#define HOME_REG_UNCERTAIN 1
#define HOME_REG_VALID 2

struct home_addr_info {
	struct list_head list;
	struct mn_addr hoa; /* Home address */
	uint8_t plen; 
	uint8_t home_reg_status;
	uint8_t home_block;
	uint8_t use_dhaad;
	uint16_t lladdr_comp;
	uint8_t at_home;
	uint8_t home_plen;
	struct in6_addr home_prefix;
	struct hash bul; /* Binding Update List */
	struct mn_addr primary_coa;
	struct list_head ro_policies;
	struct ha_candidate_list ha_list;	
	struct in6_addr ha_addr;
	int pend_ba;
	int verdict;
	int if_tunnel;
	int if_home;
	int if_block;
	uint8_t altcoa;
	uint16_t mob_rtr;
	char name[IF_NAMESIZE];
	int mnp_count;
	struct list_head mob_net_prefixes;
};

enum {
	MN_HO_NONE,
	MN_HO_INVALIDATE,
	MN_HO_IGNORE,
	MN_HO_PROCEED,
	MN_HO_REESTABLISH,
	MN_HO_CHECK_LIFETIME,
	MN_HO_RETURN_HOME
};

static inline int movement_ho_verdict(int verdict)
{
	return verdict == MN_HO_PROCEED;
}

static inline int positive_ho_verdict(int verdict)
{
	switch (verdict) {
	case MN_HO_PROCEED:
	case MN_HO_REESTABLISH:
	case MN_HO_CHECK_LIFETIME:
	case MN_HO_RETURN_HOME:
		return 1;
	}
	return 0;
}

int mn_init(void);
void mn_cleanup(void);

/* Protects both bul and homelink structures in mn */
extern pthread_rwlock_t mn_lock;

struct home_addr_info *mn_get_home_addr(const struct in6_addr *haddr);
/* Interface to configuration system */

struct bulentry;

void mn_send_cn_bu(struct bulentry *bule);

struct home_addr_info *mn_get_home_addr_by_dhaadid(uint16_t dhaad_id);

struct movement_event;

/* Interface to movement detection */
int mn_movement_event(struct movement_event *event);

struct nd_opt_prefix_info;
int mn_update_home_prefix(struct home_addr_info *hai,
			  const struct timespec *mps_sent,
			  const struct nd_opt_prefix_info *p);

struct ifaddrmsg;
struct rtattr;
int mn_addr_changed(int add, struct ifaddrmsg *ifa, struct rtattr **rta_tb);

int mn_lladdr_dad(struct ifaddrmsg *ifa, struct rtattr *rta_tb[], void *arg);

int mn_rr_start_handoff(void *vbule, void *vcoa);

int mn_rr_post_home_handoff(void *bule, void *vcoa);

void mn_start_ro(struct in6_addr *cn_addr, struct in6_addr *home_addr);

int mn_is_at_home(struct list_head *prefixes,
		  const struct in6_addr *home_prefix, int home_plen);

#endif /* __MN_H__ */
