/* IP interface control and configuration routines
 * Copyright 1991 Phil Karn, KA9Q
 *
 * Mods by PA0GRI
 */
#include "global.h"
#include "ctype.h"
#include "commands.h"
#include "mbuf.h"
#include "proc.h"
#ifndef MSDOS
#include "iface.h"
#endif
#ifdef ETHER
#include "enet.h"
#endif
#include "arp.h"
#include "pktdrvr.h"
#include "nr4.h"
#include "mailbox.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: iface.c,v 1.25 1997/09/07 00:31:16 root Exp $";
#endif

#ifdef NETROM
extern struct iface *Nr_iface;
extern char Nralias[];
#endif

static void showiface (struct iface * ifp);
static int ifipaddr (int argc, char *argv[], void *p);
static int ifipcall (int argc, char *argv[], void *p);
static int iflinkadr (int argc, char *argv[], void *p);
static int ifbroad (int argc, char *argv[], void *p);
static int ifnetmsk (int argc, char *argv[], void *p);
static int ifmtu (int argc, char *argv[], void *p);
static int ifmetric (int argc, char *argv[], void *p);
static int ifforw (int argc, char *argv[], void *p);
static int ifencap (int argc, char *argv[], void *p);
static int ifdescr (int argc, char *argv[], void *p);

#ifdef RXECHO
static int ifrxecho (int argc, char *argv[], void *p);
#endif


static const char subcommands[] = "valid subcommands:\n";
static const char nochangeIP[] = "Cannot change IP address !\n";
static const char setIPcall[] = "Can't set IP call\n";
static const char setlinkaddr[] = "Can't set link address\n";
static const char encaperr[] = "Encapsulation mode '%s' unknown\n";
static const char notsametype[] = "'%s not the same type!\n";
static const char showfmt[] = "%-10s IP addr %s MTU %u Metric %d Link encap ";
static const char notset[] = "not set\n";
static const char showlink[] = "           Link addr %s";
static const char showsent[] = "           sent: ip %lu tot %lu idle %s\n";
static const char showrecv[] = "           recv: ip %lu tot %lu idle %s\n";
static const char showdescr[] = "           descr: %s";
static const char detnope[] = "Can't detach loopback or encap interface\n";
static const char showflags[] = "           flags 0x%lx trace 0x%x netmask 0x%08lx broadcast %s\n";
static const char showforw[] = "           output forward to %s\n";

#ifdef AX25
static const char showIPcall[] = "   IP call %s";
static const char showlenirtt[] = "   Paclen %d   Irtt %lu\n";
static const char showbctext[] = "           BCText: %s\n";
static const char showremote[] = "           Remote call %s";
#ifdef AXIP
static const char showremoteIP[] = "   Remote IP addr %s\n";
#endif
#endif

#ifdef RXECHO
static const char showrxecho[] = "         rx packets echoed to %s\n";
#endif



struct iftcp def_iftcp = {DEF_RTT, 0L, DEF_WND, DEF_MSS, 31, DEF_RETRIES, 0, 0};

/* Interface list header */
struct iface *Ifaces = &Loopback;

#ifdef AXIP
extern uint32 *axipaddr;	/* table of IP addresses of AX.25 interfaces */
#endif


/* Loopback pseudo-interface */
struct iface Loopback =
{
#ifdef ENCAP
	&Encap,			/* Link to next entry */
#else
	NULLIF,
#endif
	"loopback",		/* name     */
	NULLCHAR,		/* description */
	0x7f000001UL,		/* addr		127.0.0.1 */
	0xffffffffUL,		/* broadcast	255.255.255.255 */
	0xffffffffUL,		/* netmask	255.255.255.255 */
	MAXINT16,		/* mtu		No limit */
	1,			/* metric */
	0,			/* flags    */
#ifdef NETROM
	0,			/* quality  */
#endif
	0,			/* trace	*/
	NULLCHAR,		/* trfile	*/
	NULLFILE,		/* trfp		*/
	-1,			/* trsock       */
	NULLIF,			/* forw		*/
#ifdef RXECHO
	NULLIF,			/* rxecho       */
#endif
	NULLPROC,		/* rxproc	*/
	NULLPROC,		/* txproc	*/
	NULLPROC,		/* supv		*/
	0,			/* dev		*/
	(int32 (*)(struct iface *, int, int, int32)) 0,
	NULLFP ((struct iface *, int, int32)),	/* (*iostatus)  */
	NULLFP ((struct iface *)),	/* (*stop)      */
	NULLCHAR,		/* hwaddr	*/
	NULLCHAR,		/* ipcall	*/
	NULLCHAR,		/* rmtaddr	*/
#ifdef AX25
	NULL,			/* ax25 protocol data */
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
				/* ax25 counters */
#endif /* AX25 */
	&def_iftcp,		/* tcp protocol data */
	NULL,			/* extension	*/
	CL_NONE,		/* type		*/
	0,			/* xdev		*/
	0,			/* port		*/
	&Iftypes[0],		/* iftype	*/
	NULLFP ((struct mbuf *, struct iface *, uint32, int, int, int, int)),	/* (*send)      */
	NULLFP ((struct iface *, const char *, char *, int16, struct mbuf *)),	/* (*output)    */
	NULLFP ((struct iface *, struct mbuf *)),	/* (*raw)       */
	NULLVFP ((struct iface *)),	/* (*show)      */
	NULLFP ((struct iface *, struct mbuf *)),	/* (*discard)   */
	NULLFP ((struct iface *, struct mbuf *)),	/* (*echo)      */
	0,			/* ipsndcnt	*/
	0,			/* rawsndcnt	*/
	0,			/* iprecvcnt	*/
	0,			/* rawrcvcnt	*/
	0,			/* lastsent	*/
	0,			/* lastrecv	*/
};



#ifdef ENCAP
/* Encapsulation pseudo-interface */
struct iface Encap =
{
	NULLIF,
	"encap",		/* name		*/
	NULLCHAR,		/* description */
	INADDR_ANY,		/* addr		0.0.0.0 */
	0xffffffffUL,		/* broadcast	255.255.255.255 */
	0xffffffffUL,		/* netmask	255.255.255.255 */
	MAXINT16,		/* mtu		No limit */
	1,			/* metric */
	0,			/* flags    */
#ifdef NETROM
	0,			/* quality  */
#endif
	0,			/* trace	*/
	NULLCHAR,		/* trfile	*/
	NULLFILE,		/* trfp		*/
	-1,			/* trsock       */
	NULLIF,			/* forw		*/
#ifdef RXECHO
	NULLIF,			/* rxecho       */
#endif
	NULLPROC,		/* rxproc	*/
	NULLPROC,		/* txproc	*/
	NULLPROC,		/* supv		*/
	0,			/* dev		*/
	(int32 (*)(struct iface *, int, int, int32)) 0,	/* (*ioctl)     */
	NULLFP ((struct iface *, int, int32)),	/* (*iostatus)  */
	NULLFP ((struct iface *)),	/* (*stop)      */
	NULLCHAR,		/* hwaddr	*/
	NULLCHAR,		/* ipcall	*/
	NULLCHAR,		/* rmtaddr	*/
#ifdef AX25
	NULL,			/* ax25 protocol data */
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
				/* ax25 counters */
#endif /* AX25 */
	&def_iftcp,		/* tcp protocol data */
	NULL,			/* extension	*/
	CL_NONE,		/* type		*/
	0,			/* xdev		*/
	0,			/* port		*/
	&Iftypes[0],		/* iftype	*/
	ip_encap,		/* (*send)	*/
	NULLFP ((struct iface *, const char *, char *, int16, struct mbuf *)),	/* (*output)    */
	NULLFP ((struct iface *, struct mbuf *)),	/* (*raw)       */
	NULLVFP ((struct iface *)),	/* (*show)      */
	NULLFP ((struct iface *, struct mbuf *)),	/* (*discard)   */
	NULLFP ((struct iface *, struct mbuf *)),	/* (*echo)      */
	0,			/* ipsndcnt	*/
	0,			/* rawsndcnt	*/
	0,			/* iprecvcnt	*/
	0,			/* rawrcvcnt	*/
	0,			/* lastsent	*/
	0,			/* lastrecv	*/
};

#endif /*ENCAP*/



#if defined(DRSI) || defined(EAGLE) || defined(PC_EC) || defined(HAPN) || defined(PC100)
char Noipaddr[] = "IP address field missing, and ip address not set\n";
#endif

static struct cmds Ifcmds[] =
{
#ifdef AX25
	{ "ax25",		ifax25,		0, 0, NULLCHAR },
#endif
	{ "broadcast",		ifbroad,	0, 2, NULLCHAR },
	{ "description",	ifdescr,	0, 0, NULLCHAR },
	{ "encapsulation",	ifencap,	0, 2, NULLCHAR },
	{ "forward",		ifforw,		0, 2, NULLCHAR },
	{ "ipaddress",		ifipaddr,	0, 2, NULLCHAR },
	{ "ipcall",		ifipcall,	0, 2, NULLCHAR },
	{ "linkaddress",	iflinkadr,	0, 2, NULLCHAR },
	{ "metric",		ifmetric,	0, 2, NULLCHAR },
	{ "mtu",		ifmtu,		0, 2, NULLCHAR },
	{ "netmask",		ifnetmsk,	0, 2, NULLCHAR },
#ifdef RXECHO	
	{ "rxecho",		ifrxecho,	0, 2, NULLCHAR },
#endif
	{ "tcp",		doiftcp,	0, 0, NULLCHAR },
	{ NULLCHAR,		NULL,		0, 0, NULLCHAR }
};



/* Set interface parameters */
int
doifconfig (int argc, char *argv[], void *p OPTIONAL)
{
struct iface *ifp;
int i, step = 2, newargc = argc;

	if (argc < 2) {
		for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next)
			showiface (ifp);
		return 0;
	}
	if ((ifp = if_lookup (argv[1])) == NULLIF) {
		tprintf (Badinterface, argv[1]);
		return 1;
	}
	if (argc == 2) {
		showiface (ifp);
		if (ifp->show != NULLVFP ((struct iface *)))
			(*ifp->show) (ifp);
		return 0;
	}
	if (argc == 3) {
		dohelper (subcommands, Ifcmds, NULLCHAR, NULLCHAR, NULLCHAR);
		return 1;
	}
	for (i = 2; i < argc - 1; i += step) {
		step = (tolower (argv[i][0]) == 't') ? 3 : 2;
		(void) subcmd (Ifcmds, newargc - 1, &argv[i - 1], ifp);
		newargc -= step;
	}
	return 0;
}



/* Remove iface tracing to the current output socket */
void 
removetrace ()
{
struct iface *ifp;

	for (ifp = Ifaces; ifp; ifp = ifp->next)
		if (ifp->trsock == Curproc->output) {
			ifp->trace = 0;
			/* We have to close the socket, because usesock() was called !*/
			close_s (ifp->trsock);
			ifp->trsock = -1;
		}
}



static int
ishexaddr (char *str)
{
int k;
int l = (int) strlen (str);

	if (l < 8 || l > 10)
		return 0;
	if (!strncasecmp (str, "0x", 2))
		return 1;
	for (k = 0; k < 8; k++)	{
		if (!isxdigit (str[k]))
			return 0;
	}
	return 1;
}


/* Set interface IP address */
static int
ifipaddr (int argc OPTIONAL, char *argv[], void *p)
{
struct iface *ifp = p;

	/* Do not allow loopback iface to be changed ! - WG7J */
	if (ifp == &Loopback) {
		tputs (nochangeIP);
		return 0;
	}
	ifp->addr = (ishexaddr (argv[1])) ? (uint32) htol (argv[1]) : resolve (argv[1]);
	return 0;
}



/* Set IP call sign */
static int
ifipcall (int argc OPTIONAL, char *argv[], void *p)
{
struct iface *ifp = p;

	if (ifp->iftype == NULLIFT || ifp->iftype->scan == NULL) {
		tputs (setIPcall);
		return 1;
	}
	if (ifp->ipcall != NULLCHAR)
		free (ifp->ipcall);
	ifp->ipcall = mallocw ((unsigned) ifp->iftype->hwalen);
	(void) (*ifp->iftype->scan) (ifp->ipcall, argv[1]);
	return 0;
}



/* Set link (hardware) address */
static int
iflinkadr (int argc OPTIONAL, char *argv[], void *p)
{
struct iface *ifp = p;

	if (ifp->iftype == NULLIFT || ifp->iftype->scan == NULL) {
		tputs (setlinkaddr);
		return 1;
	}
	if (ifp->hwaddr != NULLCHAR)
		free (ifp->hwaddr);
	ifp->hwaddr = mallocw ((unsigned) ifp->iftype->hwalen);
	(void) (*ifp->iftype->scan) (ifp->hwaddr, argv[1]);
#if defined(MAILBOX) && defined(NETROM)
	if (ifp == Nr_iface)	/*the netrom call just got changed! - WG7J*/
		setmbnrid ();
#endif
	return 0;
}



/* Set interface broadcast address. This is actually done
 * by installing a private entry in the routing table.
 */
static int
ifbroad (int argc OPTIONAL, char *argv[], void *p)
{
struct iface *ifp = p;
struct route *rp;

	rp = rt_blookup (ifp->broadcast, 32);
	if (rp != NULLROUTE && rp->iface == ifp)
		(void) rt_drop (ifp->broadcast, 32);

	ifp->broadcast = (ishexaddr (argv[1])) ? (uint32) htol (argv[1]): resolve (argv[1]);
	(void) rt_add (ifp->broadcast, 32, 0L, ifp, 1L, 0L, 1);
	return 0;
}



/* Set the network mask. This is actually done by installing
 * a routing entry.
 */
static int
ifnetmsk (int argc OPTIONAL, char *argv[], void *p)
{
struct iface *ifp = p;
struct route *rp;

	/* Remove old entry if it exists */
	rp = rt_blookup (ifp->addr & ifp->netmask, (unsigned) mask2width (ifp->netmask));
	if (rp != NULLROUTE)
		(void) rt_drop (rp->target, rp->bits);

	ifp->netmask = (ishexaddr (argv[1])) ? (uint32) htol (argv[1]) : resolve (argv[1]);
	(void) rt_add (ifp->addr, (unsigned) mask2width (ifp->netmask), 0L, ifp, 0L, 0L, 0);
	return 0;
}



/* Command to set interface encapsulation mode */
static int
ifencap (int argc OPTIONAL, char *argv[], void *p)
{
struct iface *ifp = p;

	if (setencap (ifp, argv[1]) != 0) {
		tprintf (encaperr, argv[1]);
		return 1;
	}
	return 0;
}



/* Function to set encapsulation mode */
int
setencap (struct iface *ifp, const char *mode)
{
struct iftype *ift = (struct iftype *) 0;

	if (mode != NULL) {
		/* Configure the whole interface */
		for (ift = &Iftypes[0]; ift->name != NULLCHAR; ift++)
			if (strnicmp (ift->name, mode, strlen (mode)) == 0)
				break;
		if (ift->name == NULLCHAR)
			return -1;

		ifp->iftype = ift;
		ifp->send = ift->send;
		ifp->output = ift->output;
		ifp->type = ift->type;
	}
	/* Set the tcp and ax25 interface parameters */
	if (!ifp->tcp)
		ifp->tcp = callocw (1, sizeof (struct iftcp));

	init_iftcp (ifp->tcp);
#ifdef AX25
	if (ift && ift->type == CL_AX25) {
		if (!ifp->ax25)
			ifp->ax25 = callocw (1, sizeof (struct ifax25));

		init_ifax25 (ifp->ax25);
		ifp->flags |= AX25_BEACON + MAIL_BEACON + AX25_DIGI + LOG_AXHEARD + LOG_IPHEARD;
	}
#endif
	return 0;
}



#ifdef RXECHO
/* Set interface IP address */
static int
ifrxecho (int argc OPTIONAL, char *argv[], void *p)
{
struct iface *ifp = p;
struct iface *rxecho;

	if (!stricmp ("off", argv[1])) {
		ifp->rxecho = NULLIF;
		return 0;
	};
	if ((rxecho = if_lookup (argv[1])) == NULL) {
		tprintf (Badinterface, argv[1]);
		return 0;
	};
	if (ifp->type != rxecho->type) {
		tprintf (notsametype, argv[1]);
		return 0;
	};
	ifp->rxecho = rxecho;
	return 0;
}
#endif /* RXECHO */



/* Set interface Maximum Transmission Unit */
static int
ifmtu (int argc OPTIONAL, char *argv[], void *p)
{
struct iface *ifp = p;

	ifp->mtu = (int16) atoi (argv[1]);
#ifdef NETROM
	/* Make sure NETROM mtu <= 236 ! - WG7J */
	if (ifp == Nr_iface)
		if (Nr_iface->mtu > NR4MAXINFO)
			Nr_iface->mtu = NR4MAXINFO;
#endif
	return 0;
}



/* Set interface metric for RIP -  */
static int
ifmetric (int argc OPTIONAL, char *argv[], void *p)
{
struct iface *ifp = p;

	ifp->iface_metric = atoi (argv[1]);
	return 0;
}



/* Set interface forwarding */
static int
ifforw (int argc OPTIONAL, char *argv[], void *p)
{
struct iface *ifp = p;

	ifp->forw = if_lookup (argv[1]);
	if (ifp->forw == ifp)
		ifp->forw = NULLIF;
	return 0;
}



/*give a little description for each interface - WG7J*/
static int
ifdescr (int argc OPTIONAL, char *argv[], void *p)
{
struct iface *ifp = p;

#ifdef NETROM
#ifdef ENCAP
	if ((ifp == &Loopback) || (ifp == &Encap) || (ifp == Nr_iface))
#else
	if ((ifp == &Loopback) || (ifp == Nr_iface))
#endif /*ENCAP*/
#else /*NETROM*/
#ifdef ENCAP
	if ((ifp == &Loopback) || (ifp == &Encap))
#else
	if (ifp == &Loopback)
#endif /*ENCAP*/
#endif /*NETROM*/
		return 0;

	if (ifp->descr != NULLCHAR) {
		free (ifp->descr);
		ifp->descr = NULLCHAR;	/* reset the pointer */
	}
	if (!strlen (argv[1]))
		return 0;	/* clearing the buffer */

	ifp->descr = mallocw (strlen (argv[1]) + 2);	/* allow for the EOL char etc */
	strcpy (ifp->descr, argv[1]);
	strcat (ifp->descr, "\n");	/* add the EOL char */

	return 0;
}



/* Display the parameters for a specified interface */
static void
showiface (register struct iface *ifp)
{
char tmp[25];

	tprintf (showfmt, ifp->name, inet_ntoa (ifp->addr), (int) ifp->mtu, ifp->iface_metric);
	if (ifp->iftype == NULLIFT)
		tputs (notset);
	else {
		tprintf ("%s%s\n", ifp->iftype->name, (ifp->rmtaddr != NULLCHAR) ? " (AXIP)" : "");
		if (ifp->iftype->format != NULL && ifp->hwaddr != NULLCHAR) {
			tprintf (showlink, (*ifp->iftype->format) (tmp, ifp->hwaddr));
#ifdef AX25
			if (ifp->iftype->type == CL_AX25) {
				if (ifp->ipcall != NULLCHAR)
					tprintf (showIPcall, (*ifp->iftype->format) (tmp, ifp->ipcall));
				tprintf (showlenirtt, (int) ifp->ax25->paclen, ifp->ax25->irtt);
				if (ifp->ax25->bctext)
					tprintf (showbctext, ifp->ax25->bctext);
				if (ifp->rmtaddr != NULLCHAR) {
					tprintf (showremote, (*ifp->iftype->format) (tmp, ifp->rmtaddr));
#ifdef AXIP
					tprintf (showremoteIP, inet_ntoa (axipaddr[ifp->dev]));
#endif
				}
			}
#ifdef NETROM
			else if (ifp == Nr_iface)
				tprintf ("   Alias %s\n", Nralias);
#endif
			else
#endif
				tputc ('\n');
		}
	}
	tprintf (showflags, ifp->flags, ifp->trace, ifp->netmask, inet_ntoa (ifp->broadcast));
	if (ifp->forw != NULLIF)
		tprintf (showforw, ifp->forw->name);
#ifdef RXECHO
	if (ifp->rxecho != NULLIF)
		tprintf (showrxecho, ifp->rxecho->name);
#endif
	tprintf (showsent, ifp->ipsndcnt, ifp->rawsndcnt, tformat (secclock () - ifp->lastsent));
	tprintf (showrecv, ifp->iprecvcnt, ifp->rawrecvcnt, tformat (secclock () - ifp->lastrecv));
	if (ifp->descr != NULLCHAR)
		tprintf (showdescr, ifp->descr);
}



/* Command to detach an interface */
int
dodetach (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
register struct iface *ifp;

	if ((ifp = if_lookup (argv[1])) == NULLIF) {
		tprintf (Badinterface, argv[1]);
		return 1;
	}
	if (if_detach (ifp) == -1)
		tputs (detnope);
	return 0;
}



/* Detach a specified interface */
int
if_detach (register struct iface *ifp)
{
struct iface *iftmp;
struct route *rp, *rptmp;
int i, j;
struct ax_route *axr, *axr1;
struct arp_tab *ap, *ap1;

#ifdef ENCAP
	if (ifp == &Loopback || ifp == &Encap)
#else
	if (ifp == &Loopback)
#endif
		return -1;

#ifdef AX25
	/* Drop all ax25 routes that points to this interface */
	for (axr = Ax_routes; axr != NULLAXR; axr = axr1) {
		axr1 = axr->next;	/* Save the next pointer */
		if (axr->iface == ifp)
			(void) ax_drop (axr->target, ifp, AX_NONSETUP);
		/* axr will be undefined after ax_drop() */
	}
#endif

	/* Drop all ARP's that point to this interface */
	for (i = 0; i < HASHMOD; ++i)
		for (ap = Arp_tab[i]; ap != NULLARP; ap = ap1) {
			ap1 = ap->next;	/* Save the next pointer */
			if (ap->iface == ifp)
				arp_drop (ap);
			/* ap will be undefined after arp_drop() */
		}


	/* Drop all routes that point to this interface */
	if (R_default.iface == ifp)
		(void) rt_drop (0L, 0);/* Drop default route */

	for (i = 0; i < HASHMOD; i++) {
		for (j = 0; j < 32; j++) {
			for (rp = Routes[j][i]; rp != NULLROUTE; rp = rptmp) {
				/* Save next pointer in case we delete this entry */
				rptmp = rp->next;
				if (rp->iface == ifp)
					(void) rt_drop (rp->target, rp->bits);
			}
		}
	}
	/* Unforward any other interfaces forwarding to this one */
	for (iftmp = Ifaces; iftmp != NULLIF; iftmp = iftmp->next) {
		if (iftmp->forw == ifp)
			iftmp->forw = NULLIF;
#ifdef RXECHO
		if (iftmp->rxecho == ifp)
			iftmp->rxecho = NULLIF;
#endif
	}

	/* Call device shutdown routine, if any */
	if (ifp->stop != NULLFP ((struct iface *)))
		(void) (*ifp->stop) (ifp);

	killproc (ifp->rxproc);
	killproc (ifp->txproc);
	killproc (ifp->supv);

#ifdef NETROM
	/*make sure that the netrom interface is properly detached
	 *fixed 11/15/91, Johan. K. Reinalda, WG7J/PA3DIS
	 */
	if (strcmp (ifp->name, "netrom") == 0) {
		for (iftmp = Ifaces; iftmp; iftmp = iftmp->next)
			iftmp->flags &= ~IS_NR_IFACE;	/* this 'resets' active interfaces */
		Nr_iface = NULLIF;
	}
#endif

	/* Free allocated memory associated with this interface */
	if (ifp->name != NULLCHAR)
		free (ifp->name);
	if (ifp->hwaddr != NULLCHAR)
		free (ifp->hwaddr);
	if (ifp->ipcall != NULLCHAR)
		free (ifp->ipcall);
	free (ifp->tcp);
#ifdef AX25
	if (ifp->ax25) {
		if (ifp->ax25->bctext)
			free (ifp->ax25->bctext);
		free (ifp->ax25);
	}
#endif
	free (ifp->descr);

	/* Remove from interface list */
	if (ifp == Ifaces)
		Ifaces = ifp->next;
	else {
		/* Search for entry just before this one
		 * (necessary because list is only singly-linked.)
		 */
		for (iftmp = Ifaces; iftmp != NULLIF; iftmp = iftmp->next)
			if (iftmp->next == ifp)
				break;
		if (iftmp != NULLIF && iftmp->next == ifp)
			iftmp->next = ifp->next;
	}
	/* Finally free the structure itself */
	free ((char *) ifp);
	return 0;
}



/* Given the ascii name of an interface, return a pointer to the structure,
 * or NULLIF if it doesn't exist
 */
struct iface *
if_lookup (const char *name)
{
register struct iface *ifp;

	for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next)
		if (stricmp (ifp->name, name) == 0)
			break;
	return ifp;
}



/* Return iface pointer if 'addr' belongs to one of our interfaces,
 * NULLIF otherwise.
 * This is used to tell if an incoming IP datagram is for us, or if it
 * has to be routed.
 */
struct iface *
ismyaddr (uint32 addr)
{
register struct iface *ifp;

	for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next)
		if (addr == ifp->addr)
			break;
	return ifp;
}



/* Given a network mask, return the number of contiguous 1-bits starting
 * from the most significant bit.
 */
int
mask2width (uint32 mask)
{
int width, i;

	width = 0;
	for (i = 31; i >= 0; i--) {
		if (!(mask & (1L << i)))
			break;
		width++;
	}
	return width;
}



/* return buffer with name + comment */
char *
if_name (struct iface *ifp, const char *comment)
{
char *result = mallocw (strlen (ifp->name) + strlen (comment) + 1);

	strcpy (result, ifp->name);
	return strcat (result, comment);
}



/* Raw output routine that tosses all packets. Used by dialer, tip, etc */
int
bitbucket (struct iface *ifp OPTIONAL, struct mbuf *bp)
{
	free_p (bp);
	return 0;
}



/* Set interface (or AX25) flags on 1 or all interfaces */
int
dosetflag (int argc, char *argv[], void *p OPTIONAL, int flagtoset, int AX25only)
{
struct iface *ifp;

	if (argc < 2) {
		for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next)
			if (ifp->flags & flagtoset)
				tprintf ("%s\n", ifp->name);
	} else {
		if ((argc == 3) && (strcmp (argv[1], "all") == 0)) {
			for (ifp = Ifaces; ifp != NULLIF; ifp = ifp->next)
				if (!AX25only || ifp->type == CL_AX25) {
					if (strcmp (argv[2], "on") == 0)
						ifp->flags |= flagtoset;
					else if (strcmp (argv[2], "off") == 0)
						ifp->flags &= ~flagtoset;	/*lint !e502 */
					else {
						tputs ("Please use on or off.\n");
						return 0;
					}
				}
			return 0;
		} else if ((ifp = if_lookup (argv[1])) == NULLIF) {
			tprintf (Badinterface, argv[1]);
			return 1;
		}
		if (AX25only && ifp->type != CL_AX25) {
			tputs ("not an AX.25 interface\n");
			return -1;
		}
		if (argc != 3)
			ifp->flags ^= flagtoset;
		else {
			if (strcmp (argv[2], "on") == 0)
				ifp->flags |= flagtoset;
			else if (strcmp (argv[2], "off") == 0)
				ifp->flags &= ~flagtoset;	/*lint !e502 */
			else
				ifp->flags ^= flagtoset;
		}
	}
	return 0;
}


/* attach a dummy interface.  no parms for now. */
int
dummy_attach (argc, argv, p)
int argc OPTIONAL;
char *argv[] OPTIONAL;
void *p OPTIONAL;
{
struct iface *dummy;
uint32 n;

	if ((n = resolve (argv[2])) == 0) {
		tprintf (Badhost, argv[2]);
		return 1;
	}

	dummy = (struct iface *) callocw (1, sizeof (struct iface));

	dummy->addr = n;
	dummy->iface_metric = 1;

	/* The strdup is needed to keep the detach routine happy (it'll
	 * free the allocated memory)
	 */
	dummy->name = strdup (argv[1]);
	dummy->hwaddr = mallocw (AXALEN);
	memcpy (dummy->hwaddr, Mycall, AXALEN);

	dummy->mtu = MAXINT16;
	(void) setencap (dummy, "None");
	dummy->next = Ifaces;
	Ifaces = dummy;

	return 0;
}



