From @nic.funet.fi:ham-bsd-relay@UCSD.EDU Sat Jun 18 00:00:19 1994
Received: from ucsd.edu ([132.239.254.201]) by nic.funet.fi with SMTP id <92228-3>; Sat, 18 Jun 1994 00:00:16 +0300
Received: by ucsd.edu; id NAA20506
	sendmail 8.6.9/UCSD-2.2-sun
	Fri, 17 Jun 1994 13:30:50 -0700 for ham-bsd-list
Received: from nothing.ucsd.edu by ucsd.edu; id NAA20502
	sendmail 8.6.9/UCSD-2.2-sun via ESMTP
	Fri, 17 Jun 1994 13:30:48 -0700 for <ham-bsd@ucsd.edu>
Received: from localhost by nothing.ucsd.edu (8.6.3/UCSDGENERIC.4)
	id NAA06577 to ham-bsd@ucsd.edu; Fri, 17 Jun 1994 13:30:48 -0700
Date:	Fri, 17 Jun 1994 23:30:48 +0300
From:	brian@nothing.UCSD.EDU (Brian Kantor)
Message-Id: <199406172030.NAA06577@nothing.ucsd.edu>
To:	ham-bsd@UCSD.EDU
Subject: kissmon.c
Status: RO

/*
 * a simple program that expects to find a KISS TNC at 9600 bps serial
 * speed on /dev/tty01 (COM2) of your BSDI 1.1 system.  Displays common
 * packet formats on the screen.  Does not transmit.
 *
 * Brian Kantor June 1994
 */
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>

#define DEBUG 1

#define	FR_END		0xc0
#define FR_ESC		0xdb
#define T_FR_END	0xdc
#define T_FR_ESC	0xdd

int trace = 0xff;

int tnc;
char tncdev[32];

unsigned char tncbuf[1024];
int plen;
int errcnt;

extern int errno;

main()
	{
	int c;
	int escaped, framed;

	escaped = 0;
	framed = 0;

	plen = 0;

	strcpy(tncdev, "/dev/tty01");

	opendev();

	while ( (c = gettncchar()) != -1 )
		{
		if (c == FR_END)
			{
			if ( (trace & 1) && (plen > 0) )
				{
				printf("\nKISS len=%d\n", plen);
				}
		
			/* protocol upcall */
			if (plen > 0 && tncbuf[0] == 0x00)
				ax25in(tncbuf+1, plen-1);

			framed = !framed;
			plen = 0;
			errcnt = 0;
			continue;
			}

		if (!framed)
			continue;

		if (c == FR_ESC)
			{
			escaped = 1;
			continue;
			}

		/* escaped chars */
		if (escaped)
			{
			escaped = 0;
			if (c == T_FR_END)
				{
				tncbuf[plen++] = FR_END;
				continue;
				}
			if (c == T_FR_ESC)
				{
				tncbuf[plen++] = FR_ESC;
				continue;
				}

			/* bad frame, flush it */
			plen = 0;
			continue;
			}
		tncbuf[plen++] = c;
		}
	}

/*
 * read a character from the tnc.  If there is an I/O error,
 * return -1.  If it times out, return 0.  Else return the char
 * timeout is in seconds; 0 = poll
 */
int
gettncchar()
	{
	unsigned char c[2];

	/* so get the char already */
	if (read(tnc, c, 1) != 1)
		{
		perror("tnc read");
		return(-1);
		}

	c[0] &= 0x00FF;		/* trim to 8 bits */

	return((int) c[0]);
	}

/* open the tnc */
int
opendev()
	{
	struct termios  ti;
	int err;

	tnc = open(tncdev, (O_RDWR|O_EXCL), 0);
	if (tnc < 0)
		{
		perror(tncdev);
		return(errno);
		}
	
	if (DEBUG)
		printf("%s is open on fd %d\n", tncdev, tnc);

	/* get current port settings */
	err = tcgetattr(tnc, &ti);
	if (err < 0)
		{
		perror(tncdev);
		return(errno);
		}
	/*
	 * set tty params to 9600 no parity
	 * this is for BSDI 1.1  God help you on other systems.
	 */
	cfmakeraw(&ti);

	cfsetspeed(&ti, 9600);

	ti.c_iflag |= IGNBRK;   /* ignore breaks */

	ti.c_cflag &= ~CSIZE;   /* 8-bit bytes */
	ti.c_cflag |= CS8;
	ti.c_cflag &= ~CSTOPB;  /* one stop bit */
	ti.c_cflag &= ~PARENB;  /* no parity */

	ti.c_cc[VMIN] = 1;	/* read() can return 1 byte */
	ti.c_cc[VTIME] = 0;     /* no time out */

	errno = 0;
	err = tcsetattr(tnc, TCSANOW, &ti);
	if (err < 0)
		{
		perror(tncdev);
		return(errno);
		}
	return 0;
	}

ax25in(p,l)
unsigned char *p;
int l;
	{
	int i;
	int addrend;
	char v;
	unsigned char op;
	unsigned char pid;
	char ps[16];

	/* long enough to be meaningful? */
	if (l < 15)
		return;

	if (trace & 2)
		{
		v = '1';
		if ( (*(p+6) & 0x80 == 1) && (*(p+12) & 0x80 == 0) )
			v = 'C';
		if ( (*(p+6) & 0x80 == 0) && (*(p+12) & 0x80 == 1) )
			v = 'R';
		printf("AX.25 %c len=%d: ", v, l);
		addrend = printaxaddr(p+7, 0);	/* source addr */
		printf("-> ");
		printaxaddr(p, 0);	/* dest addr */

		if (!addrend)
			printf("via ");

		p += 14;
		l -= 14;

		/* print variable number of digipeater addresses */
		while (!addrend)
			{
			addrend = printaxaddr(p, 1);
			p += 7;
			l -= 7;
			}

		op = *p++ & 0x00FF;
		l -= 2;

		switch (pid = *p++ & 0x00FF)
			{
	default:	sprintf(ps, "%02x", pid); break;
	case 0xCC:	strcpy(ps, "IP"); break;
	case 0xCD:	strcpy(ps, "ARP"); break;
	case 0xCF:	strcpy(ps, "NR"); break;
	case 0xF0:	strcpy(ps, "text"); break;
			}

		/* interpret the opcode */
		if ((op & 1) == 0)
			{
			printf("<I> R=%d S=%d P=%d dlen=%d pid=%s\n",
				(op & 0xE0) >> 5, (op & 0x0E) >> 1,
				(op & 0x10) >> 4, l, ps);
			}
		else if ((op & 0xEF) == 0x03)
			{
			printf("<UI> P=%d dlen=%d pid=%s\n",
				(op & 0x10) >> 4, l, ps);
			}
		else if ((op & 0xEF) == 0x2F)
			{
			printf("<SABM> P=%d\n", (op & 0x10) >> 4);
			}
		else if ((op & 0xEF) == 0x43)
			{
			printf("<DISC> P=%d\n", (op & 0x10) >> 4);
			}
		else if ((op & 0xEF) == 0x0F)
			{
			printf("<DM> P=%d\n", (op & 0x10) >> 4);
			}
		else if ((op & 0xEF) == 0x63)
			{
			printf("<UA> P=%d\n", (op & 0x10) >> 4);
			}
		else if ((op & 0xEF) == 0x87)
			{
			printf("<FRMR> P=%d\n", (op & 0x10) >> 4);
			hexout(p+2, 3);
			}
		else if ((op & 0x0F) == 0x01)
			{
			printf("<RR> R=%d PF=%d\n",
				(op & 0xE0) >> 5, (op & 0x10) >> 4);
			}
		else if ((op & 0x0F) == 0x05)
			{
			printf("<RNR> R=%d PF=%d\n",
				(op & 0xE0) >> 5, (op & 0x10) >> 4);
			}
		else if ((op & 0x0F) == 0x09)
			{
			printf("<REJ> R=%d PF=%d\n",
				(op & 0xE0) >> 5, (op & 0x10) >> 4);
			}
		else
			{
			printf("unknown %02x\n", *p);
			}
		fflush(stdout);
		}

	/* I or UI, call the appropriate embedded protocol handler */
	if ((op & 1) == 0 || (op & 0xEF) == 0x03)
		{
		switch(pid)
			{
	default:	break;

	case 0xCC:	ipin(p, l);
			break;

	case 0xCD:	arpin(p, l);
			break;

	case 0xCF:	nrin(p, l);
			break;

	case 0xF0: 	if (trace & 3)
				hexout(p, l);
			break;
			}
		}
	}

/* returns 1 if the address printed was flagged as the last one */
int
printaxaddr(p, digi)
unsigned char *p;
int digi;
	{
	char c;
	c = (*p++) >> 1;  if (c > ' ') putchar(c);
	c = (*p++) >> 1;  if (c > ' ') putchar(c);
	c = (*p++) >> 1;  if (c > ' ') putchar(c);
	c = (*p++) >> 1;  if (c > ' ') putchar(c);
	c = (*p++) >> 1;  if (c > ' ') putchar(c);
	c = (*p++) >> 1;  if (c > ' ') putchar(c);
	printf("-%d%c ", ((*p >> 1) & 0x0f), ((digi && (*p&0x80)>>7)?'*':' '));
	return(*p & 1);
	}

/* pretty-print a string in hex */
hexout(s,l)
unsigned char *s;
int l;
	{
	int i, j;
	char buf[17];

	for (i=0; i < l; i++)
		{
		if ( (i % 16) == 0)
			{
			if (i > 0)
				printf("  %s\n", buf);
			printf("%04d", i);
			strcpy(buf, "                ");
			}

		if ( (i % 8) == 0)
			printf("- ");

		printf("%02x ", *s);
		buf[i%16] = (isprint(*s) ? *s : '_');
		s++;
		}

	j = (i % 16 == 0) ? 0 : (16 - (i % 16));
	if (j > 7)
		printf("  ");
	while (j--)
		printf("   ");
	printf("  %s\n", buf);
	fflush(stdout);
	}

ipin(p, l)
char *p;
int l;
	{
	printf("IP len=%d\n", l);
	hexout(p, l);
	}

arpin(p, l)
char *p;
int l;
	{
	printf("ARP len=%d\n", l);
	hexout(p, l);
	}

nrin(p, l)
unsigned char *p;
int l;
	{
	int op;

	printf("NETROM len=%d ", l);

	/* network header */
	printaxaddr(p, 0); p += 7;
	printf("-> ");
	printaxaddr(p, 0); p += 7;
	printf("ttl=%x ", *p++);

	/* transport header */
	printf("ckt=%x/%x ", *p++, *p++);
	printf("T=%x R=%x ", *p++, *p++);

	/* flags */
	if ((*p) & 0x80)
		printf("CHOKE ");
	if ((*p) & 0x40)
		printf("NAK ");
	if ((*p) & 0x20)
		printf("MORE ");
	if ((*p) & 0x10)
		printf("rsvd ");

	op = (*p++) & 0x0f;
	switch (op)
		{
case 0x01:	printf("ConReq winreq=%x from ", *p++);
		printaxaddr(p, 0); p += 7;
		printf("@ ");
		printaxaddr(p, 0); p += 7;
		puts("");
		break;
case 0x02:	printf("ConAck winack=%x\n", *p++);
		break;
case 0x03:	printf("DiscReq\n");
		break;
case 0x04:	printf("DiscAck\n");
		break;
case 0x05:	printf("Info\n");
		hexout(p, l);
		break;
case 0x06:	printf("InfoAck\n");
		break;
default:	printf("op=%02x ", op);
		break;
		}
	}


