/*
 *	AX.25 release 020
 *
 *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
 *	releases, misbehave and/or generally screw up. It might even work. 
 *
 *	This code REQUIRES 1.1.13 or higher/ NET3.014
 *
 *	This module:
 *		This module 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.
 *
 *	Other kernels modules in this kit are generally BSD derived. See the copyright headers.
 *
 *
 *	History
 *	AX.25 020	Jonathan(G4KLX)	First go.
 *	AX.25 022	Jonathan(G4KLX)	Added the actual meat to this - we now have a nice mheard list.
 *
 */
 
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include "ax25.h"
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include "sock.h"
#include <asm/segment.h>
#include <asm/system.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/interrupt.h>


#ifdef CONFIG_AX25

#define	AX25_ROUTE_MAX	40

static struct ax25_route
{
	struct ax25_route *next;
	ax25_address callsign;
	struct device *dev;
	struct timeval stamp;
	int n;
}
*ax25_route = NULL;

void ax25_rt_rx_frame(ax25_address *src, struct device *dev)
{
	extern struct timeval xtime;
	struct ax25_route *ax25_rt;
	struct ax25_route *oldest;
	int count;

	count  = 0;
	oldest = NULL;

	for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next)
	{
		if (count == 0 || ax25_rt->stamp.tv_sec < oldest->stamp.tv_sec)
			oldest = ax25_rt;
		
		if (ax25cmp(&ax25_rt->callsign, src) == 0 && ax25_rt->dev == dev)
		{
			ax25_rt->stamp = xtime;
			ax25_rt->n++;
			return;			
		}

		count++;
	}

	if (count > AX25_ROUTE_MAX)
	{
		oldest->callsign = *src;
		oldest->dev      = dev;
		oldest->stamp    = xtime;
		oldest->n        = 1;
		return;
	}

	if ((ax25_rt = (struct ax25_route *)kmalloc(sizeof(struct ax25_route), GFP_ATOMIC)) == NULL)
		return;		/* No space */

	ax25_rt->callsign = *src;
	ax25_rt->dev      = dev;
	ax25_rt->stamp    = xtime;
	ax25_rt->n        = 1;

	ax25_rt->next = ax25_route;
	ax25_route    = ax25_rt;
}

int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
{
	struct ax25_route *ax25_rt;
	int len = 0;
	off_t pos = 0;
	off_t begin = 0;
  
	cli();

	len += sprintf(buffer, "callsign  dev count time\n");

	for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next)
	{
		len += sprintf(buffer + len, "%-9s %-3s %5d %ld\n",
			ax2asc(&ax25_rt->callsign),
			ax25_rt->dev->name,
			ax25_rt->n,
			ax25_rt->stamp.tv_sec);

		pos = begin + len;

		if (pos < offset)
		{
			len   = 0;
			begin = pos;
		}
		
		if (pos > offset + length)
			break;
	}

	sti();

	*start = buffer + (offset - begin);
	len   -= (offset - begin);

	if (len > length) len = length;

	return(len);
} 

#endif
