
/*
 * New AXUDP code - March, 2001, VE4KLM, Maiko Langelaar
 *
 * Based on AXIP code from the 'ax25.c' module
 *
 * Thanks to Thomas (DL9SAU) for helping out with tests.
 *
 * This implementation works with FlexNet32, Xnet, and WAMPES axudp.
 *
 */

#include "global.h"

#ifdef	AX25

#ifdef	AXUDP

#include "commands.h"
#include "mbuf.h"
#include "iface.h"
#include "arp.h"
#include "netrom.h"
#include "trace.h"
#include "pktdrvr.h"
#include "udp.h"

#include "axudp.h"	/* Note, this is a new header file for AXUDP */

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: axudp.c,v 1.2 2001/05/07 10:28:20 brian Exp $";
#endif

static int axudp_stop (struct iface * iface);
static int axudp_raw (struct iface * iface, struct mbuf * bp);

extern char Mycall[AXALEN];

AXUDPCFG *axudpcfg;	/* information table for AXUDP interfaces */

int AXUDPlinks = MAXUDPLINKS;

extern int16 fcstab[];  /* table used when calculating FCS - in ax25.c */

/*
 * Check if the UDP packet qualifies as a possible AXUDP frame
 *
 * Why the need to go through all interface information ? Well, because
 * I wanted to give the user the flexibilty to configure UDP source and
 * destination ports, instead of hardcoding them to the value of 93.
 *
 * This function is called from the udp.c module.
 */

int axudp_frame (udp)
	struct udp *udp;
{
	int i;

	for (i = 0; i < AXUDPlinks; ++i)
		if (axudpcfg[i].dest == udp->dest && axudpcfg[i].source == udp->source)
			break;

	return (i != AXUDPlinks);
}

/*
 * Handle AX.25 frames received inside UDP
 *
 * This function is called from the udp.c module.
 */

void axudp_input (iface, bp, ip)
	struct iface *iface;
	struct mbuf *bp;
	struct ip *ip;
{
	int i;
	struct mbuf *tbp;
	int16 len, f, fcs = 0xffff;
#ifdef RXECHO
	struct mbuf *bbp;
#endif

	/* make sure this comes from a valid AXUDP interface */
	for (i = 0; i < AXUDPlinks; ++i)
		if (axudpcfg[i].ipaddr == ip->source)
				break;

	/* if not, then drop it */
	if (i == AXUDPlinks)
	{
		free_p (bp);
		return;
	}

	/* now get the information for this interface */
	iface = Ifaces;
	while (iface != NULLIF)
	{
		if (iface->raw == axudp_raw && iface->dev == i)
			/* found the right AX.25 pseudo interface */
			break;
		iface = iface->next;
	}
	if (iface == NULLIF)
	{
		free_p (bp);
		return;
	}

	len = len_p (bp) - sizeof (fcs);
	if (dup_p (&tbp, bp, 0, len) != len)
	{
		free_p (bp);
		return;
	}

	/*lint !e506 */
	while (len--)
		fcs = (fcs >> 8) ^ fcstab[(fcs ^ PULLCHAR (&bp)) & 0x00ff];

	fcs ^= 0xffff;
	f = (int16) PULLCHAR (&bp);		/*lint !e506 */
	f |= (int16) (PULLCHAR (&bp) << 8);	/*lint !e506 !e701 */

	if (fcs == f)
	{
		/* add some tracing - WG7J */
#ifdef TRACE
		dump (iface, IF_TRACE_IN, CL_AX25, tbp);
#endif
#ifdef RXECHO
		/* If configured, echo this packet before handling - WG7J */
		if (iface && iface->rxecho)
		{
			(void) dup_p (&bbp, tbp, 0, len_p (tbp));	/* as it was */
			(void) (*iface->rxecho->raw) (iface->rxecho, bbp);
		}
#endif
		ax_recv (iface, tbp);

	} else free_p (tbp);
}

/* attach a fake AX.25 interface for AX.25 in UDP */

/* argv[0] == "axudp"
 * argv[1] == name of new interface
 * argv[2] == MTU
 * argv[3] == hostname of remote end of wormhole
 * argv[4] == optional AX.25 callsign for this interface, must be specified
 *	      and be different from any other interface callsign if crossband
 *   	      digipeating is going to work properly
 * argv[5] == optional AX.25 callsign for the remote end of this interface
 *            used only by the smart routing, at this time
 *
 * I suppose I could have left the UDP ports at 93, but I wanted to give
 * the user some flexibility to choose what UDP ports can be used.
 *
 * argv[6] == optional UDP source port
 * argv[7] == optional UDP destination port
 *
 * In order to specify the optional UDP ports, you obviously have to
 * specifiy something for the optional AX25.callsigns. Just use '-'
 * for argv[4] and argv[5] if you are not using them.
 *
 */
int axudp_attach (int argc, char *argv[], void *p OPTIONAL)
{
	struct iface *ifp;

	int i, port;

	/* Check for too long iface names - WG7J */
	if (strlen (argv[1]) >= ILEN)
	{
		tprintf ("interface max %d chars\n", ILEN - 1);
		return -1;
	}
	if (if_lookup (argv[1]) != NULLIF)
	{
		tprintf ("interface %s already attached\n", argv[1]);
		return -1;
	}
	for (i = 0; i < AXUDPlinks; ++i)
		if (axudpcfg[i].ipaddr == 0)
			break;
	if (i == AXUDPlinks)
	{
		tputs ("too many AXUDP interfaces attached\n");
		return -1;
	}
	if ((axudpcfg[i].ipaddr = resolve (argv[3])) == 0)
	{
		tputs ("invalid address\n");
		return -1;
	}
	ifp = (struct iface *) callocw (1, sizeof (struct iface));

	ifp->dev = i;
	ifp->addr = Ip_addr;
	ifp->name = strdup (argv[1]);
	ifp->iface_metric = 1;
	ifp->hwaddr = mallocw (AXALEN);
	memcpy (ifp->hwaddr, Mycall, AXALEN);
	ifp->ipcall = mallocw (AXALEN);
	memcpy (ifp->ipcall, Mycall, AXALEN);
	ifp->mtu = (int16) atoi (argv[2]);
	(void) setencap (ifp, "AX25");

	/*
	 * had to add the check for the '-' character if we want to leave
	 * a particular optional parameter alone, yet be allowed to parse
	 * other options that follow after it
	 */

	if (argc > 4 && *argv[4] != '-')
	{
		free (ifp->hwaddr);
		free (ifp->ipcall);
		ifp->hwaddr = mallocw ((unsigned) ifp->iftype->hwalen);
		(void) (*ifp->iftype->scan) (ifp->hwaddr, argv[4]);
		ifp->ipcall = mallocw ((unsigned) ifp->iftype->hwalen);
		(void) (*ifp->iftype->scan) (ifp->ipcall, argv[4]);
	}

	if (argc > 5 && *argv[5] != '-')
	{
		ifp->rmtaddr = mallocw ((unsigned) ifp->iftype->hwalen);
		(void) (*ifp->iftype->scan) (ifp->rmtaddr, argv[5]);
	}

	/* default source and dest UDP ports to 93 */
	axudpcfg[i].dest = axudpcfg[i].source = 93;

	/* allow users to customize which UDP ports to use for AXUDP */
	if (argc > 6)
	{
		if ((port = atoi (argv[6])) > 0)
			axudpcfg[i].source = port;
		else
		{
			tputs ("invalid source port\n");
			return -1;
		}
	}
	if (argc > 7)
	{
		if ((port = atoi (argv[7])) > 0)
			axudpcfg[i].dest = port;
		else
		{
			tputs ("invalid destination port\n");
			return -1;
		}
	}

	ifp->raw = axudp_raw;
	ifp->stop = axudp_stop;
	ifp->next = Ifaces;
	Ifaces = ifp;
	return 0;
}

static int axudp_stop (struct iface *iface)
{
	axudpcfg[iface->dev].ipaddr = 0;

	return 0;
}

/* raw routine for sending AX.25 on top of UDP */

static int axudp_raw (iface, bp)
	struct iface *iface;		/* Pointer to interface control block */
	struct mbuf *bp;		/* Data field */
{
	int16 len, fcs = 0xffff;
	struct mbuf *bp1;

	struct socket lsock, fsock;	/* use example from GPS code */

	dump (iface, IF_TRACE_OUT, (unsigned) iface->type, bp);

	lsock.address = INADDR_ANY;
	fsock.address = axudpcfg[iface->dev].ipaddr;
	lsock.port = axudpcfg[iface->dev].source;
	fsock.port = axudpcfg[iface->dev].dest;

	iface->rawsndcnt++;
	iface->lastsent = secclock ();

	len = len_p (bp);
	if (dup_p (&bp1, bp, 0, len) != len)
	{
		free_p (bp);
		return -1;
	}

	/*lint !e506 */
	while (len--)		/* calculate FCS */
		fcs = (fcs >> 8) ^ fcstab[(fcs ^ PULLCHAR (&bp1)) & 0x00ff];

	fcs ^= 0xffff;		/* final FCS (is this right?) */
	if ((bp1 = alloc_mbuf (sizeof (fcs))) == NULLBUF)
	{
		free_p (bp);
		return -1;
	}

	*bp1->data = fcs & 0xff;
	*(bp1->data + 1) = (fcs >> 8) & 0xff;

	bp1->cnt += sizeof (fcs);

	append (&bp, bp1);

	/* set length to 0, let function determine this */
    send_udp (&lsock, &fsock, 0, 0, bp, 0, 0, 0);

	return 0; 
}

#endif	/* AXUDP */

#endif /* AX25 */
