/*
 * Functions that deal with those pesky routers.
 *
 * Remember people (including you Craig) that the definition of router here
 * is the source of a link-state bulletin.  If you want to fiddle with the
 * adjacent router info, go play with the adjacency stuff and leave this alone.
 * If you don't 0.08 is never going to get out.
 */
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <net/if.h>
#include <linux/ax25.h>
#include "rspfd.h"
#include "queue.h" 
#include "deltaq.h"
#include "rspfrtr.h"

struct queue *routerq;
extern int debug_mode;
extern struct rspf_mib rspf_stats;
 
 void rtr_setup()
 {
 	routerq = create_queue();
 }
 
struct router *getrtrbyid(u_long addr)
{
	struct router *rtr;	
	qmark rtr_qm;

	rtr = (struct router*)qmove_first(routerq, &rtr_qm);
	while (rtr != NULL)
	{
		if (addr == rtr->addr)
			return rtr;
		rtr = (struct router*)qmove_next(routerq, &rtr_qm);
	}		
	return NULL;
}

int add_router(u_long addr, u_int seq_no, u_int sub_seq_no, time_t bulltime)
{
	struct router *rtr;
	qmark rtr_qm;
	
	rtr = (struct router*)qmove_first(routerq, &rtr_qm);
	while(rtr != NULL)
	{
		if (rtr->addr == addr)
		{
			rtr->seq_no = seq_no;
			rtr->sub_seq_no = sub_seq_no;
			rtr->bulltime = bulltime;
			return 0;
		}
		rtr = (struct router*)qmove_next(routerq, &rtr_qm);
	}
	/* A new router! */
	if ((rtr = (struct router*)malloc(sizeof(struct router))) == NULL)
	{
		syslog(LOG_DAEMON | LOG_ERR, "add_router(): Out of memory.");
		return -1;
	}
	rtr->addr = addr;
	rtr->seq_no = seq_no;
	rtr->sub_seq_no = sub_seq_no;
	rtr->bulltime = bulltime;
	return 1;
}	
			

/*
 * check_routers()
 *
 * Check any routers that we have not heard any information from for
 * a long time and remove them.  This is so we don't have routers in 
 * our table forever
 *
 * Returns:
 *	Nothing
 *
 * Arguments:
 *	int	Timer id
 */
void check_routers(int id)
{ 
	static int timer_id = 0;
	struct router *rtr;
	time_t now;
	qmark rtr_qm;
	u_int mintime;	
	long timediff;
	int ls_changed;
	
	if (debug_mode >= 2)
		printf("check_routers(): id = %#3x.\n", id);
		
	/*
	 * Sanity check for the timer id
	 */
	if (timer_id != id)
	{
		syslog(LOG_DAEMON | LOG_ERR, "check_routers(): Incorrect timer ID. Got %#3x, expected %#3x.\n", id, timer_id);
		return;
	}
			
	/* The most we will wait before checking again is a set parameter */
	mintime = rspf_stats.rspfBullTimeout;
	ls_changed = 0;

	rtr = (struct router*)qmove_first(routerq, &rtr_qm);		
	while (rtr != NULL) {

		now = time(NULL);
		timediff = rspf_stats.rspfBullTimer - (u_int) (now - rtr->bulltime);
		if (timediff <= 0L)
		{
			/* Remove all links for this router */
			del_link_source(rtr->addr, rtr->seq_no + 1);
			del_qnode(routerq, rtr_qm, 1);
			ls_changed = 1;
			rtr = (struct router*)qmove_first(routerq, &rtr_qm);
		} else 
		{
			/* Determine when we have to next look here 
			 * in other words when the next router will be 
			 * lost
			 */
			if (mintime  > timediff)
				mintime = timediff;
			/* Move onto next one */
			rtr = (struct router*)qmove_next(routerq, &rtr_qm);
		}

	}

	/* 
	 * We have to do  SPF if we have removed any links
	 */
	if (ls_changed)
		do_spf();
		
	/* Setup timer for next check 
	 * mintime is the number of seconds before any node can be
	 * suspect, so we don't bother to come back until that happens
	 */
	if (mintime < 1)
		mintime = 1;
	timer_id = dq_add(mintime, check_routers);

} /* check_routers */

