/* AX25 control commands
 * Copyright 1991 Phil Karn, KA9Q
 *
 * Mods by G1EMM
 * Mods by PA0GRI
 * Mods by N1BEE
 */
/*
** FILE: ax25cmd.c
**
** AX.25 command handler.
**
** 09/24/90 Bob Applegate, wa2zzx
**    Added BCTEXT, BC, and BCINTERVAL commands for broadcasting an id
**    string using UI frames.
**
** 27/09/91 Mike Bilow, N1BEE
**    Added Filter command for axheard control
*/

#include "global.h"
#ifdef AX25
#include "commands.h"
#include "mbuf.h"
#include "timer.h"
#include "proc.h"
#include "iface.h"
#include "mailbox.h"
#ifndef MSDOS
#include "session.h"
#endif
#include "nr4.h"
#include "pktdrvr.h"
#include "netrom.h"
#include "pool.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: ax25cmd.c,v 1.29 2001/05/06 16:32:54 brian Exp $";
#endif

static int doaxdest (int argc,char *argv[],void *p);
static int doaxfilter (int argc, char *argv[], void *p);
static int doaxflush (int argc, char *argv[], void *p);
static int doaxirtt (int argc, char *argv[], void *p);
static int doaxkick (int argc, char *argv[], void *p);
static int doaxreset (int argc, char *argv[], void *p);
static int doaxroute (int argc, char *argv[], void *p);
static int doaxwindow (int argc, char *argv[], void *p);
static int dobc (int argc, char *argv[], void *p);
static int dobcint (int argc, char *argv[], void *p);
static int dobcport (int argc, char *argv[], void *p);
static int dobctext (int argc, char *argv[], void *p);
static int doaxhport (int argc, char *argv[], void *p);
static int doaxhsize (int argc, char *argv[], void *p);
static int doblimit (int argc, char *argv[], void *p);
static int doaxuser (int argc, char *argv[], void *p);
static int dodigipeat (int argc, char *argv[], void *p);
static int domaxframe (int argc, char *argv[], void *p);
static int domycall (int argc, char *argv[], void *p);
static int don2 (int argc, char *argv[], void *p);
static int dopaclen (int argc, char *argv[], void *p);
static int dopthresh (int argc, char *argv[], void *p);
static int dot3 (int argc, char *argv[], void *p);
static int doaxtype (int argc, char *argv[], void *p);
static int dot4 (int argc, char *argv[], void *p);
static int doaxversion (int argc, char *argv[], void *p);
static int doaxmaxwait (int argc, char *argv[], void *p);
static int dosmartroute (int argc, char *argv[], void *p);
static int axdest (struct iface * ifp);
static int dorosecall (int argc, char *argv[], void *p);
static int docall (int argc, char *argv[], void *p, char call[]);
static int doax25paclen (int argc, char *argv[], void *p);
static int doax25timertype (int argc, char *argv[], void *p);
static int doax25irtt (int argc, char *argv[], void *p);
static int doax25version (int argc, char *argv[], void *p);
static int doax25t3 (int argc, char *argv[], void *p);
static int doax25t4 (int argc, char *argv[], void *p);
static int doax25n2 (int argc, char *argv[], void *p);
static int doax25maxframe (int argc, char *argv[], void *p);
static int doax25pthresh (int argc, char *argv[], void *p);
static int doax25window (int argc, char *argv[], void *p);
static int doax25blimit (int argc, char *argv[], void *p);
static int doax25maxwait (int argc, char *argv[], void *p);
static void dobroadtick (void);
static void displaycounters (struct iface *ifp, int addseparator);

#ifdef TUTOR
static int dotutorcall (int argc, char *argv[], void *p);
static int doinfocall (int argc, char *argv[], void *p);
static int donewscall (int argc, char *argv[], void *p);
#endif

#ifdef AXBCSTR
static void ax_bc (struct iface * axif, char *str);
#else
static void ax_bc (struct iface * axif);
#endif

#ifdef TTYCALL
static int dottycall (int argc, char *argv[], void *p);
extern char Ttycall[AXALEN];	/* the ttylink call in 'call' form */
#endif

extern int axheard_filter_flag;	/* in axheard.c */
extern int lapbtimertype;
extern char Tcall[AXALEN];
extern char Icall[AXALEN];
extern char Ncall[AXALEN];
extern char Myalias[AXALEN];
extern char Nralias[ALEN + 1];


/* Defaults for IDing. */
static char *axbctext = NULLCHAR;		/* Text to send */
static struct timer Broadtimer;	/* timer for broadcasts */
char AXRosecall[AXALEN];
int AXSmartRoute = 0;
static long Axmaxwait = 0;
int Maxax25heard;


#ifdef POOLED
extern struct mempool lq_pool;
extern struct mempool ld_pool;
#endif


#ifdef CATALOG
#include "catalog.h"

#define CAT ax25cmd_catalog

#define smartroute	__STR(0)
#define badalias	__STR(1)
#define noiface		__STR(2)
#define notax25		__STR(3)
#define bcaststr	__STR(4)
#define bcasttimer	__STR(5)
#define maxheard	__STR(6)
#define alsonotax25	__STR(7)
#define notactive	__STR(8)
#define heardheader	__STR(9)
#define heardheader2	__STR(10)
#define destheader	__STR(11)
#define heardfilter	__STR(12)
#define filterusage	__STR(13)
#define filtersrc	__STR(14)
#define filterdest	__STR(15)
#define stopstr		__STR(16)
#define lumsstr		__STR(17)
#define srttmdev	__STR(18)
#define T1_4str		__STR(19)
#define blimitstr	__STR(20)
#define maxwaitstr	__STR(21)
#define axversionstr	__STR(22)
#define irttstr		__STR(23)
#define polltimerstr	__STR(24)
#define redundancystr	__STR(25)
#define retrylimitstr	__STR(26)
#define maxframestr	__STR(27)
#define paclenstr	__STR(28)
#define pthreshstr	__STR(29)
#define windowstr	__STR(30)
#define badcallsign	__STR(31)
#define toomany		__STR(32)
#define baddigi		__STR(33)
#define addfailed	__STR(34)
#define routeheader	__STR(35)
#define routeusage	__STR(36)
#define badtarget	__STR(37)
#define notintable	__STR(38)
#define timertypestr	__STR(39)
#define timertypeusage	__STR(40)
#define bctext_str	__STR(41)

#else /* CATALOG */

static const char smartroute[] = "AX25 Smart Routing";
static const char badalias[] = "can't set alias\n";
static const char noiface[] = "you need to specify an interface\n";
static const char notax25[] = "not an AX.25 interface\n";
static const char bcaststr[] = "Broadcast text: %s\n";
static const char bcasttimer[] = "Broadcast timer %lu/%lu seconds\n";
static const char maxheard[] = "Max ax-heard";
static const char alsonotax25[] = "Interface %s not AX.25 type interface\n";
static const char notactive[] = "not active\n";
static const char heardheader[] = "Interface  Station   Time since send  Pkts sent\n";
static const char heardheader2[] = "Station   Time since heard Pkts rcvd : Station   Time since heard Pkts rcvd\n";
static const char destheader[] = "Station   Last ref         Last heard           Pkts\n";
static const char heardfilter[] = "ax25 heard filter";
static const char filterusage[] = "Usage: ax25 filter <0|1|2|3>\n";
static const char filtersrc[] = "Callsign logging by source %sabled, ";
static const char filterdest[] = "by destination %sabled\n";
static const char stopstr[] = "stop";
static const char lumsstr[] = "/%lu ms; ";
static const char srttmdev[] = "srtt = %lu mdev = %lu ";
static const char T1_4str[] = "T%c: ";
static const char blimitstr[] = "blimit";
static const char maxwaitstr[] = "retry maxwait";
static const char axversionstr[] = "AX25 version";
static const char irttstr[] = "Initial RTT (ms)";
static const char polltimerstr[] = "Idle poll timer (ms)";
static const char redundancystr[] = "Link redundancy timer (sec)";
static const char retrylimitstr[] = "Retry limit";
static const char maxframestr[] = "Window size (frames)";
static const char paclenstr[] = "Max frame length (bytes)";
static const char pthreshstr[] = "Poll threshold (bytes)";
static const char windowstr[] = "AX25 receive window (bytes)";
static const char badcallsign[] = "Bad callsign %s\n";
static const char toomany[] = "Too many digipeaters, or badly formed command.\n";
static const char baddigi[] = "Bad digipeater %s\n";
static const char addfailed[] = "Route add failed\n";
static const char routeheader[] = "Target    Iface  Type  Mode Digipeaters\n";
static const char routeusage[] = "Usage: ax25 route add <target> <iface> [digis...]\n       ax25 route drop <target> <iface>\n       ax25 route mode <target> <iface> [mode]\n";
static const char badtarget[] = "Bad target %s\n";
static const char notintable[] = "Not in table\n";
static const char timertypestr[] = "AX25 timer type is ";
static const char timertypeusage[] = "use: ax25 timertype [original|linear|exponential]\n";
static const char bctext_str[] = "Bctext : %s\n";

#endif /* CATALOG */


static const char lustr[] = "%lu";
static const char unknownmode[] = "Unknown mode %s\n";
static const char unknowncmd[] = "Unknown command %s\n";
static const char originalstr[] = "original\n";
static const char linearstr[] = "linear\n";
static const char exponentialstr[] = "exponential\n";
static const char strCR[] = "%s\n";
static const char heardfmt[] = "%-9s  %-9s   %12s    %7lu\n";
static const char str17[] = "%-17s";

static const char axstatheader[] =
#if defined(UNIX) || defined(TNOS_68K)
	"&AXB     Snd-Q   Rcv-Q   Remote    Local     Iface  State\n";
#else
	"&AXB Snd-Q   Rcv-Q   Remote    Local     Iface  State\n";
#endif

static const char axstatfmt[] =
#if defined(UNIX) || defined(TNOS_68K)
	"%8.8lx %-8d%-8d%-10s%-10s%-7s%s\n";
#else
	"%4.4x %-8d%-8d%-10s%-10s%-7s%s\n";
#endif

static const char axcbheader[] =
#if defined(UNIX) || defined(TNOS_68K)
	"&AXB     Local     Remote    Iface  RB V(S) V(R) Unack P Retry State\n";
#else
	"&AXB Local     Remote    Iface  RB V(S) V(R) Unack P Retry State\n";
#endif

static const char axcbfmt[] =
#if defined(UNIX) || defined(TNOS_68K)
	"%8.8lx %-9s %-9s %-6s %c%c";
#else
	"%4.4x %-9s %-9s %-6s %c%c";
#endif



const char *Ax25states[] =
{
	"",
	"Disconnected",
	"Listening",
	"Conn pending",
	"Disc pending",
	"Connected",
	"Recovery",
};


/* Ascii explanations for the disconnect reasons listed in lapb.h under
 * "reason" in ax25_cb
 */
const char *Axreasons[] =
{
	"Normal",
	"DM received",
	"Timeout"
};



static struct cmds Axcmds[] =
{
	{ "alias",	donralias,	0, 0, NULLCHAR },
	{ "bc",		dobc,		0, 0, NULLCHAR },
	{ "bcinterval",	dobcint,	0, 0, NULLCHAR },
	{ "bcport",	dobcport,	0, 0, NULLCHAR },
	{ "blimit",	doblimit,	0, 0, NULLCHAR },
	{ "bctext",	dobctext,	0, 0, NULLCHAR },
	{ "counters",	doaxcounters,	0, 0, NULLCHAR },
	{ "dest",	doaxdest,	0, 0, NULLCHAR },
	{ "digipeat",	dodigipeat,	0, 0, NULLCHAR },
	{ "filter",	doaxfilter,	0, 0, NULLCHAR },
	{ "flush",	doaxflush,	0, 0, NULLCHAR },
	{ "heard",	doaxheard,	0, 0, NULLCHAR },
	{ "hearddest",	doaxdest,	0, 0, NULLCHAR },
	{ "hport",	doaxhport,	0, 0, NULLCHAR },
	{ "hsize",	doaxhsize,	0, 0, NULLCHAR },
#ifdef TUTOR
	{ "infocall",	doinfocall,	0, 0, NULLCHAR },
#endif
	{ "irtt",	doaxirtt,	0, 0, NULLCHAR },
	{ "kick",	doaxkick,	0, 2, "ax25 kick <axcb>" },
	{ "maxframe",	domaxframe,	0, 0, NULLCHAR },
	{ "maxwait",	doaxmaxwait,	0, 0, NULLCHAR },
	{ "mycall",	domycall,	0, 0, NULLCHAR },
#ifdef TUTOR
	{ "newscall",	donewscall,	0, 0, NULLCHAR },
#endif
	{ "paclen",	dopaclen,	0, 0, NULLCHAR },
	{ "pthresh",	dopthresh,	0, 0, NULLCHAR },
	{ "reset",	doaxreset,	0, 2, "ax25 reset <axcb>" },
	{ "retries",	don2,		0, 0, NULLCHAR },
	{ "rosecall",	dorosecall,	0, 0, NULLCHAR },
	{ "route",	doaxroute,	0, 0, NULLCHAR },
	{ "smartroute",	dosmartroute,	0, 0, NULLCHAR },
	{ "status",	doaxstat,	0, 0, NULLCHAR },
	{ "t3",		dot3,		0, 0, NULLCHAR },
	{ "t4",		dot4,		0, 0, NULLCHAR },
	{ "timertype",	doaxtype,	0, 0, NULLCHAR },
#ifdef TUTOR
	{ "tutorcall",	dotutorcall,	0, 0, NULLCHAR },
#endif
#ifdef TTYCALL
	{ "ttycall",	dottycall,	0, 0, NULLCHAR },
#endif
	{ "user",	doaxuser,	0, 0, NULLCHAR },
	{ "version",	doaxversion,	0, 0, NULLCHAR },
	{ "window",	doaxwindow,	0, 0, NULLCHAR },
	{ NULLCHAR,	NULL,		0, 0, NULLCHAR }
};



/* Multiplexer for top-level ax25 command */
int
doax25 (int argc, char *argv[], void *p)
{
	return subcmd (Axcmds, argc, argv, p);
}



static int
dosmartroute (int argc, char *argv[], void *p OPTIONAL)
{
	return setbool (&AXSmartRoute, smartroute, argc, argv);
}



int
donralias (int argc, char *argv[], void *p OPTIONAL)
{
char tmp[AXBUF];

	if (argc < 2) {
		tprintf (strCR, pax25 (tmp, Myalias));
		return 0;
	}
	if ((setcall (Myalias, argv[1]) == -1)
#ifdef NETROM
	    || (putalias (Nralias, argv[1], 1) == -1)
#endif
		) {
		tputs (badalias);
		Myalias[0] = '\0';
#ifdef NETROM
		Nralias[0] = '\0';
#endif
		return 0;
	}
#ifdef MAILBOX
	setmbnrid ();
#endif
	return 0;
}



/*
** This function is called to send the current broadcast message
** and reset the timer.
*/

static int 
dobc (int argc, char *argv[], void *p OPTIONAL)
{
struct iface *ifa;

	if (argc < 2) {
		tputs (noiface);
		return 1;
	}
	if ((ifa = if_lookup (argv[1])) == NULLIF)
		tprintf (Badinterface, argv[1]);
	else if (ifa->type != CL_AX25)
		tputs (notax25);
#ifdef AXBCSTR
	else if (argc > 2)
		ax_bc (ifa, argv[2]);
#endif
	else {
#ifdef AXBCSTR
		ax_bc (ifa, ifa->ax25->bctext);
#else
		ax_bc (ifa);
#endif
		start_detached_timer (&Broadtimer);	/* stops if running and fire it up */
	}
	return 0;
}



/*
** View/Change the message we broadcast.
*/

static int 
dobctext (int argc, char *argv[], void *p OPTIONAL)
{
struct iface *ifp;

	if (argc < 2)
		tprintf (bcaststr, axbctext);
	else {
		if (axbctext != NULL)
			free (axbctext);
		axbctext = strdup (argv[1]);
		/* Set all ax.25 interfaces with no bc text */
		for (ifp = Ifaces; ifp->next; ifp = ifp->next)
			if (ifp->type == CL_AX25 && ifp->ax25->bctext == NULL)
				ifp->ax25->bctext = strdup (axbctext);
	}
	return 0;
}



/*
** Examine/change the broadcast interval.
*/

static int 
dobcint (int argc, char *argv[], void *p OPTIONAL)
{
	if (argc < 2) {
		tprintf (bcasttimer,
			 read_timer (&Broadtimer) / 1000L,
			 dur_timer (&Broadtimer) / 1000L);
		return 0;
	}
	stop_timer (&Broadtimer);	/* in case it's already running */
	Broadtimer.func = (void (*)(void *)) dobroadtick;	/* what to call on timeout */
	Broadtimer.arg = NULLCHAR;	/* dummy value */
	set_timer (&Broadtimer, atoi (argv[1]) * 1000L);	/* set timer duration */
	start_detached_timer (&Broadtimer);	/* and fire it up */
	return 0;
}


/* Configure a port to do ax.25 beacon broadcasting */
static int
dobcport (int argc, char *argv[], void *p)
{
	return (dosetflag (argc, argv, p, AX25_BEACON, 1));
}



/* Set the size of the ax.25 heard list */
static int 
doaxhsize (int argc, char *argv[], void *p)
{
	if (argc > 1)		/* if setting new size ... */
		(void) doaxflush (argc, argv, p);	/* we flush to avoid memory problems - K5JB */
	return setint (&Maxax25heard, maxheard, argc, argv);
}



/* Configure a port to do ax.25 heard logging */
static int
doaxhport (int argc, char *argv[], void *p)
{
	return (dosetflag (argc, argv, p, LOG_AXHEARD, 1));
}



static void
dobroadtick ()
{
struct iface *ifa;

	ifa = Ifaces;

	while (ifa != NULL) {
		if (ifa->flags & AX25_BEACON)
#ifdef AXBCSTR
			ax_bc (ifa, ifa->ax25->bctext);
#else
			ax_bc (ifa);
#endif
		ifa = ifa->next;
	}

	/* Restart timer */
	start_detached_timer (&Broadtimer);
}



/*
** This is the low-level broadcast function.
*/

#ifdef AXBCSTR
static void 
ax_bc (struct iface *axif, char *theaxbctext)
#else
static void 
ax_bc (struct iface *axif)
#endif
{
struct mbuf *hbp;
int i;
#ifndef AXBCSTR
char *theaxbctext = axif->ax25->bctext;
#endif

	/* prepare the header */
	if ((theaxbctext == NULLCHAR) || (i = (int) strlen (theaxbctext)) == 0)
		return;

	if ((hbp = alloc_mbuf ((int16) i)) == NULLBUF)
		return;

	hbp->cnt = (int16) i;
	memcpy (hbp->data, theaxbctext, (size_t) i);

	(void) (*axif->output) (axif, Ax25multi[IDCALL], axif->hwaddr, PID_NO_L3, hbp);	/* send it */
}



int
doaxheard (int argc, char *argv[], void *p OPTIONAL)
{
struct iface *ifp;

	if (argc > 1) {
		if ((ifp = if_lookup (argv[1])) == NULLIF) {
			tprintf (Badinterface, argv[1]);
			return 1;
		}
		if (ifp->output != ax_output) {
			tprintf (alsonotax25, argv[1]);
			return 1;
		}
		if (ifp->flags & LOG_AXHEARD)
			(void) axheard (ifp);
		else
			tputs (notactive);
		return 0;
	}
	for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
		if (ifp->output != ax_output)
			continue;	/* Not an ax.25 interface */
		if (axheard (ifp) == EOF)
			break;
	}
	return 0;
}



int
axheard (struct iface *ifp)
{
int col = 0;
struct lq *lp;
char tmp[AXBUF];

	if (ifp->hwaddr == NULLCHAR)
		return 0;

	tputs (heardheader);
	tprintf (heardfmt, ifp->name, pax25 (tmp, ifp->hwaddr),
		 tformat (secclock () - ifp->lastsent), ifp->rawsndcnt);

	tputs (heardheader2);
	for (lp = Lq; lp != NULLLQ; lp = lp->next) {
		if (lp->iface != ifp)
			continue;
		if (col)
			tputs ("  : ");
		if (tprintf ("%-9s   %12s    %7lu", pax25 (tmp, lp->addr), tformat (secclock () - lp->time), lp->currxcnt) == EOF)
			return EOF;
		if (col) {
			if (tputc ('\n') == EOF)
				return EOF;
			else
				col = 0;
		} else
			col = 1;
	}
	if (col)
		tputc ('\n');
	return 0;
}



static int
doaxdest (int argc, char *argv[], void *p OPTIONAL)
{
struct iface *ifp;

	if (argc > 1) {
		if ((ifp = if_lookup (argv[1])) == NULLIF) {
			tprintf (Badinterface, argv[1]);
			return 1;
		}
		if (ifp->output != ax_output) {
			tprintf (alsonotax25, argv[1]);
			return 1;
		}
		(void) axdest (ifp);
		return 0;
	}
	for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
		if (ifp->output != ax_output)
			continue;	/* Not an ax.25 interface */
		if (axdest (ifp) == EOF)
			break;
	}
	return 0;
}



static int
axdest (struct iface *ifp)
{
struct ld *lp;
struct lq *lq;
char tmp[AXBUF];

	if (ifp->hwaddr == NULLCHAR)
		return 0;
	tprintf ("%s:\n", ifp->name);
	tputs (destheader);
	for (lp = Ld; lp != NULLLD; lp = lp->next) {
		if (lp->iface != ifp)
			continue;

		tprintf ("%-10s%-17s", pax25 (tmp, lp->addr), tformat (secclock () - lp->time));

		if (addreq (lp->addr, ifp->hwaddr)) {
			/* Special case; it's our address */
			tprintf (str17, tformat (secclock () - ifp->lastsent));
		} else if ((lq = al_lookup (ifp, lp->addr, 0)) == NULLLQ)
			tprintf (str17, "");
		else
			tprintf (str17, tformat (secclock () - lq->time));

		if (tprintf ("%8lu\n", lp->currxcnt) == EOF)
			return EOF;
	}
	return 0;
}



static int
doaxfilter (int argc, char *argv[], void *p OPTIONAL)
{
	if (argc >= 2)
		(void) setint (&axheard_filter_flag, heardfilter, argc, argv);
	else {
		tputs (filterusage);
		return 1;
	}

	tprintf (filtersrc, (axheard_filter_flag & AXHEARD_NOSRC) ? "dis" : "en");
	tprintf (filterdest, (axheard_filter_flag & AXHEARD_NODST) ? "dis" : "en");
	return 0;
}



static int
doaxflush (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
struct iface *ifp;
#ifndef POOLED
struct lq *lp, *lp1;
struct ld *ld, *ld1;
#endif

	for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next) {
		if (ifp->output != ax_output)
			continue;	/* Not an ax.25 interface */
		ifp->rawsndcnt = 0;
	}
#ifdef POOLED
	pool_free (&lq_pool);
#else
	for (lp = Lq; lp != NULLLQ; lp = lp1) {
		lp1 = lp->next;
		free ((char *) lp);
	}
#endif
	Lq = NULLLQ;
#ifdef POOLED
	pool_free (&ld_pool);
#else
	for (ld = Ld; ld != NULLLD; ld = ld1) {
		ld1 = ld->next;
		free ((char *) ld);
	}
#endif
	Ld = NULLLD;
	return 0;
}



static int
doaxreset (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
struct ax25_cb *axp;

	axp = (struct ax25_cb *) htoi (argv[1]);
	if (!ax25val (axp)) {
		tputs (Notval);
		return 1;
	}
	(void) reset_ax25 (axp);
	return 0;
}



/* Display AX.25 link level control blocks */
int
doaxstat (int argc, char *argv[], void *p OPTIONAL)
{
register struct ax25_cb *axp;
char tmp[AXBUF];
char tmp2[AXBUF];

	if (argc < 2) {
		tputs (axstatheader);
		for (axp = Ax25_cb; axp != NULLAX25; axp = axp->next) {
			if (tprintf (axstatfmt, axp, len_q (axp->txq), len_p (axp->rxq),
			   pax25 (tmp, axp->remote), pax25 (tmp2, axp->local),
			   (axp->iface) ? axp->iface->name : "", Ax25states[axp->state]) == EOF)
				return 0;
		}
		return 0;
	}
	axp = (struct ax25_cb *) htoi (argv[1]);
	if (!ax25val (axp)) {
		tputs (Notval);
		return 1;
	}
	st_ax25 (axp);
	return 0;
}



static void
displaycounters (struct iface *ifp, int addseparator)
{
struct ax25_counters *ac;

	ac = &ifp->axcnt;
#if 0
	if (addseparator)
		tprintf ("---------------------------------------------------------------------\n");
	tprintf ("\nAX25 Counters for Interface: %s\n\n", ifp->name);

	tprintf ("Total Frames: %10ld in %10ld out\n Data Frames: %10ld in %10ld out\n",
		ac->msgin, ac->msgout, ac->datain, ac->dataout);
	tprintf ("    Segments: %10ld in %10ld out %10ld errors\n        RNRs: %10ld in %10ld out\n",
		ac->segin, ac->segout, ac->segerr, ac->rnrin, ac->rnrout);
	tprintf ("        REJs: %10ld in %10ld out\n     Retries: %10ld\n   FRMR Recv: %10ld\n\n",
		ac->rejin, ac->rejout, ac->retries, ac->frmerr);
#else
	if (!addseparator)
		tprintf ("\nAX25 Counters:\n\n"
			"       <-Frame Count-> <-Data Frames-> <-Segmented-> <--RNR--> <-REJ->     FRMR\n"
			"name        in     out      in     out   in  out err   in  out  in out Rtry  in\n"
			"------ ------- ------- ------- ------- ---- ---- --- ---- ---- --- --- ---- ---\n");
	else if ((addseparator % 5) == 0)
		tprintf ("-------------------------------------------------------------------------------\n");
	
	tprintf ("%-7.7s%7ld %7ld %7ld %7ld %4ld %4ld %3ld %4ld %4ld %3ld %3ld %4ld %3ld\n",
		ifp->name, ac->msgin, ac->msgout, ac->datain, ac->dataout, ac->segin,
		ac->segout, ac->segerr, ac->rnrin, ac->rnrout, ac->rejin, ac->rejout,
		ac->retries, ac->frmerr);
#endif
}



/* Display AX.25 link level counters */
int
doaxcounters (int argc, char *argv[], void *p OPTIONAL)
{
struct iface *ifp;
int count = 0;
int k;

	if (argc < 2) {
		for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next)	{
			if (ifp->iftype->type == CL_AX25)	{
				displaycounters (ifp, count);
				count++;
			}
		}
		return 0;
	}
	for (k = 1; k < argc; k++)	{
		if ((ifp = if_lookup (argv[k])) == NULLIF) {
			tprintf (Badinterface, argv[k]);
			return 1;
		}
		displaycounters (ifp, count);
		count++;
	}
	return 0;
}



/* Dump one control block */
void
st_ax25 (register struct ax25_cb *axp)
{
char tmp[AXBUF];
char tmp2[AXBUF];
int i;
char target[AXALEN];

	if (axp == NULLAX25)
		return;
	tputs (axcbheader);
	tprintf (axcbfmt, axp, pax25 (tmp, axp->local),
		 pax25 (tmp2, axp->remote), (axp->iface) ? axp->iface->name : "",
		 axp->flags.rejsent ? 'R' : ' ', axp->flags.remotebusy ? 'B' : ' ');
	tprintf (" %4d %4d", axp->vs, axp->vr);
	tprintf (" %02u/%02u %u", axp->unack, axp->maxframe, axp->proto);
	tprintf (" %02u/%02u", axp->retries, axp->n2);
	tprintf (" %s\n", Ax25states[axp->state]);
	tprintf (srttmdev, axp->srt, axp->mdev);
	tprintf (T1_4str, '1');
	if (run_timer (&axp->t1))
		tprintf (lustr, read_timer (&axp->t1));
	else
		tputs (stopstr);
	tprintf (lumsstr, dur_timer (&axp->t1));

	tprintf (T1_4str, '3');
	if (run_timer (&axp->t3))
		tprintf (lustr, read_timer (&axp->t3));
	else
		tputs (stopstr);
	tprintf (lumsstr, dur_timer (&axp->t3));

	tprintf (T1_4str, '4');
	if (run_timer (&axp->t4))
		tprintf (lustr, (read_timer (&axp->t4) / 1000L));
	else
		tputs (stopstr);
	tprintf ("/%lu sec\n", (dur_timer (&axp->t4) / 1000L));
	if (axp->route != NULLAXR)	{
		/* if the route is set, then it is a connection that
		   originated from here, and we know definitively this info */
		tputs ("mode = ");
		switch (axp->route->mode) {
			case AX_VC_MODE:	tputs ("VC");
						break;
			case AX_DATMODE:	tputs ("DG");
						break;
			case AX_DEFMODE:	tputs ("IF");
						break;
			default:		tputs ("??");
						break;
		}
		tputs ("  Digipeaters =");
		for (i = 0; i < axp->route->ndigis; i++) {
			memcpy (target, axp->route->digis[i], AXALEN);
			tprintf (" %s", pax25 (tmp, target));
		}
		tputc ('\n');
	}
}



/* Set limit on retransmission backoff */
static int
doax25blimit (int argc, char *argv[], void *p)
{
	return setlong ((long *) p, blimitstr, argc, argv);
}



/* Set limit on retransmission backoff */
static int
doblimit (int argc, char *argv[], void *p OPTIONAL)
{
	return doax25blimit (argc, argv, (void *) &Blimit);
}



/* Set limit on retransmission in ms */
static int
doax25maxwait (int argc, char *argv[], void *p)
{
	return setlong ((long *) p, maxwaitstr, argc, argv);
}



static int
doaxmaxwait (int argc, char *argv[], void *p OPTIONAL)
{
	return doax25maxwait (argc, argv, (void *) &Axmaxwait);
}



/* Display or change our AX.25 address */
static int
domycall (int argc, char *argv[], void *p OPTIONAL)
{
char tmp[AXBUF];

	if (argc < 2) {
		tprintf (strCR, pax25 (tmp, Mycall));
		return 0;
	}
	if (setcall (Mycall, argv[1]) == -1)
		return -1;
#ifdef MAILBOX
	setmbnrid ();
#endif
	if (!memcmp (AXuser, NOCALL, AXALEN))
		(void) setcall (AXuser, argv[1]);
	return 0;
}



#ifdef TTYCALL
/* Display or change ttylink AX.25 address */
static int
dottycall (int argc, char *argv[], void *p OPTIONAL)
{
char tmp[AXBUF];

	if (argc < 2) {
		tprintf (strCR, pax25 (tmp, Ttycall));
		return 0;
	}
	if (setcall (Ttycall, argv[1]) == -1)
		return -1;
	return 0;
}
#endif



static int
doaxuser (int argc, char *argv[], void *p OPTIONAL)
{
char tmp[AXBUF];

	if (argc < 2) {
		tprintf (strCR, pax25 (tmp, AXuser));
		return 0;
	}
	if (setcall (AXuser, argv[1]) == -1)
		return -1;
	return 0;
}



/* Control AX.25 digipeating */
static int
dodigipeat (int argc, char *argv[], void *p)
{
	return (dosetflag (argc, argv, p, AX25_DIGI, 1));
}



static int
doax25version (int argc, char *argv[], void *p)
{
	return setshort ((unsigned short *) p, axversionstr, argc, argv);
}



static int
doaxversion (int argc, char *argv[], void *p OPTIONAL)
{
	return doax25version (argc, argv, (void *) &Axversion);
}



static int
doax25irtt (int argc, char *argv[], void *p)
{
	return setlong ((long *) p, irttstr, argc, argv);
}



static int
doaxirtt (int argc, char *argv[], void *p OPTIONAL)
{
	return doax25irtt (argc, argv, (void *) &Axirtt);
}



/* Set idle timer */
static int
doax25t3 (int argc, char *argv[], void *p)
{
	return setlong ((long *) p, polltimerstr, argc, argv);
}



/* Set idle timer */
static int
dot3 (int argc, char *argv[], void *p OPTIONAL)
{
	return doax25t3 (argc, argv, &T3init);
}



/* Set link redundancy timer */
static int
doax25t4 (int argc, char *argv[], void *p)
{
	return setlong ((long *) p, redundancystr, argc, argv);
}



/* Set link redundancy timer */
static int
dot4 (int argc, char *argv[], void *p OPTIONAL)
{
	return doax25t4 (argc, argv, (long *) &T4init);
}



/* Set retry limit count */
static int
doax25n2 (int argc, char *argv[], void *p)
{
	return setshort ((unsigned short *) p, retrylimitstr, argc, argv);
}



/* Set retry limit count */
static int
don2 (int argc, char *argv[], void *p OPTIONAL)
{
	return doax25n2 (argc, argv, (void *) &N2);
}



/* Force a retransmission */
static int
doaxkick (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
struct ax25_cb *axp;

	axp = (struct ax25_cb *) htoi (argv[1]);
	if (!ax25val (axp)) {
		tputs (Notval);
		return 1;
	}
	(void) kick_ax25 (axp);
	return 0;
}



/* Set maximum number of frames that will be allowed in flight */
static int
doax25maxframe (int argc, char *argv[], void *p)
{
	return setshort ((unsigned short *) p, maxframestr, argc, argv);
}



/* Set maximum number of frames that will be allowed in flight */
static int
domaxframe (int argc, char *argv[], void *p OPTIONAL)
{
	return doax25maxframe (argc, argv, (void *) &Maxframe);
}



/* Set maximum length of I-frame data field */
static int
doax25paclen (int argc, char *argv[], void *p)
{
	return setshort ((unsigned short *) p, paclenstr, argc, argv);
}



/* Set maximum length of I-frame data field */
static int
dopaclen (int argc, char *argv[], void *p OPTIONAL)
{
	return doax25paclen (argc, argv, (void *) &Paclen);
}



/* Set size of I-frame above which polls will be sent after a timeout */
static int
doax25pthresh (int argc, char *argv[], void *p)
{
	return setshort ((unsigned short *) p, pthreshstr, argc, argv);
}



/* Set size of I-frame above which polls will be sent after a timeout */
static int
dopthresh (int argc, char *argv[], void *p OPTIONAL)
{
	return doax25pthresh (argc, argv, (void *) &Pthresh);
}



/* Set high water mark on receive queue that triggers RNR */
static int
doax25window (int argc, char *argv[], void *p)
{
	return setshort ((unsigned short *) p, windowstr, argc, argv);
}



/* Set high water mark on receive queue that triggers RNR */
static int
doaxwindow (int argc, char *argv[], void *p OPTIONAL)
{
	return doax25window (argc, argv, (void *) &Axwindow);
}



/* End of ax25 subcommands */

#if defined(AX25) || defined(MAILBOX) || defined(AXUI)
/* Consolidate into one place the parsing of a connect path containing digipeaters.
 * This is for gateway connects, by console connect cmd, by the
 * axui command, and by the BBS forwarding process.
 * We will place the derived path into the ax25 route table.
 * Input: tokenized cmd line argc/argv: cmd iface target [via] digi1 [,] digi2 ... digiN
 *        interface *ifp.
 *        target, the node reached via digipeating.
 * Output: ax25 route table is updated.
 * Return code: 0 => error, else number of digis in path.  -- K5JB
*/
int
connect_filt (int argc, char *argv[], char target[], struct iface *ifp, int mode)
{
int i, rtn_argc, ndigis, dreg_flag = 0;
char digis[MAXDIGIS][AXALEN];
char *nargv[MAXDIGIS + 1];
char *cp, *dreg = NULLCHAR;

	ndigis = argc - 3;	/* worst case */

	for (i = 0, rtn_argc = 0; i < ndigis && rtn_argc < MAXDIGIS + 1; i++) {
		cp = argv[i + 3];

get_dreg:
		switch (*cp) {
			case ',':
				if (!*(cp + 1))	/* lone comma */
					continue;	/* skip it */
				else {	/* leading comma, a faux pas */
					nargv[rtn_argc++] = ++cp;
					if (*cp == ',') {	/* sequential commas are illegal */
						rtn_argc = MAXDIGIS + 1;	/* force for() loop exit */
						continue;
					}
					break;
				}
			case 'v':
				if (!strncmp ("via", cp, strlen (cp)))	/* should get 'em all */
					continue;	/* skip it */
			default:
				nargv[rtn_argc++] = cp;
				break;
		}
		for (; *cp; cp++)	/* remove any trailing commas */
			if (*cp == ',') {
				*cp = '\0';
				if (*(cp + 1) != '\0') {	/* something dangling */
					dreg = cp + 1;	/* restart scan here */
					dreg_flag = 1;
				}
				break;
			}
		if (dreg_flag) {
			dreg_flag = 0;
			cp = dreg;	/* go back and get the dreg */
			goto get_dreg;
		}
	}

	if (rtn_argc > MAXDIGIS || ndigis < 1) {
		tputs (toomany);
		return 0;
	}
	for (i = 0; i < rtn_argc; i++) {
		if (setcall (digis[i], nargv[i]) == -1) {	/*lint !e771 */
			tprintf (baddigi, nargv[i]);
			return 0;
		}
	}
	if (ax_add (target, mode, digis, rtn_argc, ifp) == NULLAXR) {
		tputs (addfailed);
		return 0;
	}
	return (rtn_argc);
}

#endif



/* Initiate interactive AX.25 connect to remote station */
int
doconnect (int argc, char *argv[], void *p OPTIONAL)
{
struct sockaddr_ax fsocket;
struct session *sp;
struct iface *ifp;
char target[AXALEN];
int split = 0;
char tmp[AXBUF];

	/*Make sure this comes from console - WG7J*/
	if (Curproc->input != Command->input)
		return 0;

#ifdef ALLSERV
	if (argv[0][0] == 's')	/* use split screen */
		split = 1;
#endif

	if (((ifp = if_lookup (argv[1])) != NULLIF) && (ifp->type != CL_AX25)) {
		tprintf (alsonotax25, argv[1]);
		return 1;
	}
	if (ifp == NULLIF) {
		tprintf (Badinterface, argv[1]);
#if defined(MAILBOX) && defined(GATECMDS)
		(void) dombports (0, NULL, NULL);
#endif
		return 1;
	}
	if (argc > 3 && !strcmp (argv[3], "@")) {
		free (argv[3]);
		argv[3] = strdup (pax25 (tmp, AXRosecall));
	}
	if (setcall (target, argv[2]) == -1) {
		tprintf (badcallsign, argv[2]);
		return 1;
	}
	/* If digipeaters are given, put them in the routing table */
	if (argc > 3) {
		if (connect_filt (argc, argv, target, ifp, AX_SETUP) == 0)
			return 1;
	}
	/* Allocate a session descriptor */
	if ((sp = newsession (argv[2], AX25TNC, split)) == NULLSESSION) {
		tputs (TooManySessions);
		return 1;
	}
	if ((sp->s = socket (AF_AX25, SOCK_STREAM, 0)) == -1) {
		tputs (Nosock);
		freesession (sp);
		(void) keywait (NULLCHAR, 1);
		return 1;
	}
	fsocket.sax_family = AF_AX25;

	memcpy (fsocket.ax25_addr, AXuser, AXALEN);
	(void) bind (sp->s, (char *) &fsocket, sizeof (struct sockaddr_ax));

	(void) setcall (fsocket.ax25_addr, argv[2]);
	strncpy (fsocket.iface, argv[1], ILEN - 1);
	return tel_connect (sp, (char *) &fsocket, sizeof (struct sockaddr_ax));
}



/* Display and modify AX.25 routing table */
static int
doaxroute (int argc, char *argv[], void *p OPTIONAL)
{
char tmp[AXBUF];
int i, ndigis;
register struct ax_route *axr;
struct ax_route **routetbl = &Ax_setups;
char target[AXALEN], digis[MAXDIGIS][AXALEN];
struct iface *iface;
const char *typestr;

	if (argc < 2) {
		tputs (routeheader);
		do	{
			for (axr = *routetbl; axr != NULLAXR; axr = axr->next) {
				memcpy (target, axr->target, AXALEN);
				target[AXALEN - 1] |= (AXN | Q);
				switch (axr->type)	{
					case AX_LOCAL:		typestr = "Local";
								break;
					case AX_SETUP:		typestr = "Setup";
								break;
					default:		typestr = "Auto";
				}
				tprintf ("%-10s%-7s%-6s", pax25 (tmp, target),
					 axr->iface->name, typestr);
				switch (axr->mode) {
					case AX_VC_MODE:	tputs (" VC ");
								break;
					case AX_DATMODE:	tputs (" DG ");
								break;
					case AX_DEFMODE:	tputs (" IF ");
								break;
					default:		tputs (" ?? ");
								break;
				}

				for (i = 0; i < axr->ndigis; i++) {
					memcpy (target, axr->digis[i], AXALEN);
#if 0					/* shouldn't be needed */
					target[AXALEN - 1] |= (AXN | Q);
#endif
					tprintf (" %s", pax25 (tmp, target));
				}
				if (tputc ('\n') == EOF)
					return 0;
			}
			if (routetbl == &Ax_setups)
				routetbl = &Ax_routes;
			else
				routetbl = (struct ax_route **)0;
		} while (routetbl != (struct ax_route **)0);
		return 0;
	}
	if (argc < 4) {
		tputs (routeusage);
		return 1;
	}
	if (setcall (target, argv[2]) == -1) {
		tprintf (badtarget, argv[2]);
		return 1;
	}
	if ((iface = if_lookup (argv[3])) == NULLIF) {
		tprintf (Badinterface, argv[3]);
		return 1;
	}
	switch (argv[1][0]) {
		case 'a':	/* Add route */
			ndigis = argc - 4;
			if (ndigis > MAXDIGIS) {
				tputs (toomany);
				return 1;
			}
			for (i = 0; i < ndigis; i++) {
				if (setcall (digis[i], argv[i + 4]) == -1) {
					tprintf (baddigi, argv[i + 4]);
					return 1;
				}
			}
			if (ax_add (target, AX_LOCAL, digis, ndigis, iface) == NULLAXR) {
				tputs (addfailed);
				return 1;
			}
			break;
		case 'd':	/* Drop route */
			if (ax_drop (target, iface, AX_NONSETUP) == -1) {
				tputs (notintable);
				return 1;
			}
			break;
		case 'm':	/* Alter route mode */
			if (argc < 5) {
				tputs (routeusage);
				return 1;
			}
			if ((axr = ax_lookup (NULLCHAR, target, iface, AX_NONSETUP)) == NULLAXR) {
				tputs (notintable);
				return 1;
			}
			switch (argv[4][0]) {
				case 'i':	/* use default interface mode */
					axr->mode = AX_DEFMODE;
					break;
				case 'v':	/* use virtual circuit mode */
					axr->mode = AX_VC_MODE;
					break;
				case 'd':	/* use datagram mode */
					axr->mode = AX_DATMODE;
					break;
				default:
					tprintf (unknownmode, argv[4]);
					return 1;
			}
			break;
		default:
			tprintf (unknowncmd, argv[1]);
			return 1;
	}
	return 0;
}



/* ax25 timers type - linear v exponential */
static int
doax25timertype (int argc, char *argv[], void *p)
{

	if (argc < 2) {
		tputs (timertypestr);
		switch (*(int *) p) {
			case 2:
				tputs (originalstr);
				break;
			case 1:
				tputs (linearstr);
				break;
			case 0:
				tputs (exponentialstr);
				break;
			default:
				break;
		}
		return 0;
	}
	switch (argv[1][0]) {
		case 'o':
		case 'O':	*(int *) p = 2;
				break;
		case 'l':
		case 'L':	*(int *) p = 1;
				break;
		case 'e':
		case 'E':	*(int *) p = 0;
				break;
		default:	tputs (timertypeusage);
				return -1;
	}

	return 0;
}



/* ax25 timers type - linear v exponential */
static int
doaxtype (int argc, char *argv[], void *p OPTIONAL)
{
	return doax25timertype (argc, argv, (void *) &lapbtimertype);
}



/* Display or change an AX.25 tutorial-type call */
static int
docall (int argc, char *argv[], void *p OPTIONAL, char call[])
{
char tmp[AXBUF];

	if (argc < 2) {
		tprintf (strCR, pax25 (tmp, call));
		return 0;
	}
	if (setcall (call, argv[1]) == -1)
		return -1;
	return 0;
}



/* Display or change our AX.25 rose entry call */
static int
dorosecall (int argc, char *argv[], void *p)
{
	return (docall (argc, argv, p, AXRosecall));
}



#ifdef TUTOR
/* Display or change our AX.25 tutorial call */
static int
dotutorcall (int argc, char *argv[], void *p)
{
	return (docall (argc, argv, p, Tcall));
}



/* Display or change our AX.25 info call */
static int
doinfocall (int argc, char *argv[], void *p)
{
	return (docall (argc, argv, p, Icall));
}



/* Display or change our AX.25 news call */
static int
donewscall (int argc, char *argv[], void *p)
{
	return (docall (argc, argv, p, Ncall));
}
#endif



void 
init_ifax25 (struct ifax25 *ax25)
{
	if (!ax25)
		return;
	/* Set interface to the defaults */
	ax25->paclen = Paclen;
	ax25->lapbtimertype = lapbtimertype;
	ax25->irtt = Axirtt;
	ax25->version = Axversion;
	ax25->t3 = T3init;
	ax25->t4 = T4init;
	ax25->n2 = N2;
	ax25->maxframe = Maxframe;
	ax25->pthresh = Pthresh;
	ax25->window = Axwindow;
	ax25->blimit = Blimit;
	ax25->maxwait = Axmaxwait;
	if (axbctext)
		ax25->bctext = strdup (axbctext);
}


static int doifax25paclen (int argc, char *argv[], void *p);
static int doifax25timertype (int argc, char *argv[], void *p);
static int doifax25irtt (int argc, char *argv[], void *p);
static int doifax25version (int argc, char *argv[], void *p);
static int doifax25t3 (int argc, char *argv[], void *p);
static int doifax25t4 (int argc, char *argv[], void *p);
static int doifax25n2 (int argc, char *argv[], void *p);
static int doifax25maxframe (int argc, char *argv[], void *p);
static int doifax25pthresh (int argc, char *argv[], void *p);
static int doifax25window (int argc, char *argv[], void *p);
static int doifax25blimit (int argc, char *argv[], void *p);
static int doifax25maxwait (int argc, char *argv[], void *p);
static int doifax25bctext (int argc, char *argv[], void *p);



/* These are the command that set ax.25 parameters per interface */
static struct cmds Ifaxcmds[] =
{
	{ "bctext",	doifax25bctext,		0, 0, NULLCHAR },
	{ "blimit",	doifax25blimit,		0, 0, NULLCHAR },
	{ "irtt",	doifax25irtt,		0, 0, NULLCHAR },
	{ "maxframe",	doifax25maxframe,	0, 0, NULLCHAR },
	{ "maxwait",	doifax25maxwait,	0, 0, NULLCHAR },
	{ "paclen",	doifax25paclen,		0, 0, NULLCHAR },
	{ "pthresh",	doifax25pthresh,	0, 0, NULLCHAR },
	{ "retries",	doifax25n2,		0, 0, NULLCHAR },
	{ "timertype",	doifax25timertype,	0, 0, NULLCHAR },
	{ "t3",		doifax25t3,		0, 0, NULLCHAR },
	{ "t4",		doifax25t4,		0, 0, NULLCHAR },
	{ "version",	doifax25version,	0, 0, NULLCHAR },
	{ "window",	doifax25window,		0, 0, NULLCHAR },
	{ NULLCHAR,	NULL,			0, 0, NULLCHAR }
};



int 
ifax25 (int argc, char *argv[], void *p)
{

	if (((struct iface *) p)->type != CL_AX25)
		return tputs (notax25);
	return subcmd (Ifaxcmds, argc, argv, p);
}



/* Set ax.25 bctext */
static int
doifax25bctext (int argc, char *argv[], void *p)
{
struct iface *ifp = p;

	if (argc == 1)
		tprintf (bctext_str, ifp->ax25->bctext);
	else {
		if (ifp->ax25->bctext)
			free (ifp->ax25->bctext);
		if (strlen (argv[1]) == 0)	/* clearing the buffer */
			ifp->ax25->bctext = NULL;
		else
			ifp->ax25->bctext = strdup (argv[1]);
	}
	return 0;
}



static int
doifax25blimit (int argc, char *argv[], void *p)
{
struct iface *ifp = p;

	return doax25blimit (argc, argv, (void *) &ifp->ax25->blimit);
}



static int
doifax25irtt (int argc, char *argv[], void *p)
{
struct iface *ifp = p;

	return doax25irtt (argc, argv, (void *) &ifp->ax25->irtt);
}



static int
doifax25maxframe (int argc, char *argv[], void *p)
{
struct iface *ifp = p;

	return doax25maxframe (argc, argv, (void *) &ifp->ax25->maxframe);
}



static int
doifax25maxwait (int argc, char *argv[], void *p)
{
struct iface *ifp = p;

	return doax25maxwait (argc, argv, (void *) &ifp->ax25->maxwait);
}



/* Set interface AX.25 Paclen, and adjust the NETROM mtu for the
 * smallest paclen. - WG7J
 */
static int
doifax25paclen (int argc, char *argv[], void *p)
{
struct iface *ifp = p;
#ifdef NETROM
int tmp;
#endif

	(void) doax25paclen (argc, argv, (void *) &ifp->ax25->paclen);
#ifdef NETROM
	if (argc > 1 && ifp->flags & IS_NR_IFACE) {
		if ((tmp = ifp->ax25->paclen - 20) < Nr_iface->mtu)
			Nr_iface->mtu = (int16) tmp;
	}
#endif
	return 0;
}



static int
doifax25pthresh (int argc, char *argv[], void *p)
{
struct iface *ifp = p;

	return doax25pthresh (argc, argv, (void *) &ifp->ax25->pthresh);
}



static int
doifax25n2 (int argc, char *argv[], void *p)
{
struct iface *ifp = p;

	return doax25n2 (argc, argv, (void *) &ifp->ax25->n2);
}



static int
doifax25timertype (int argc, char *argv[], void *p)
{
struct iface *ifp = p;

	return doax25timertype (argc, argv, (void *) &ifp->ax25->lapbtimertype);
}



static int
doifax25t3 (int argc, char *argv[], void *p)
{
struct iface *ifp = p;

	return doax25t3 (argc, argv, (void *) &ifp->ax25->t3);
}



static int
doifax25t4 (int argc, char *argv[], void *p)
{
struct iface *ifp = p;

	return doax25t4 (argc, argv, (void *) &ifp->ax25->t4);
}



static int
doifax25version (int argc, char *argv[], void *p)
{
struct iface *ifp = p;

	return doax25version (argc, argv, (void *) &ifp->ax25->version);
}



static int
doifax25window (int argc, char *argv[], void *p)
{
struct iface *ifp = p;

	return doax25window (argc, argv, (void *) &ifp->ax25->window);
}

#endif /* AX25 */
