/* @(#) $Header: nrdump.c,v 1.2 91/02/24 20:17:28 deyke Exp $ */

/* NET/ROM header tracing routines
 * Copyright 1991 Phil Karn, KA9Q
 */
#include <stdio.h>
#include "global.h"

#define	AXLEN		7
#define	ALEN		6

#define	NRPROTO_IP	0x0C

#define	NR4OPCODE	0x0F
#define	NR4OPPID	0
#define	NR4OPCONRQ	1
#define	NR4OPCONAK	2
#define	NR4OPDISRQ	3
#define	NR4OPDISAK	4
#define	NR4OPINFO	5
#define	NR4OPACK	6
#define	NR4MORE		0x20
#define	NR4NAK		0x40
#define	NR4CHOKE	0x80

#define	NRDESTPERPACK	11
#define	NR3NODESIG	0xFF

static void netrom_flags(int);

/* Display NET/ROM network and transport headers */
void netrom_dump(unsigned char *data, int length)
{
	char tmp[15];
	register int i;

	/* See if it is a routing broadcast */
	if (data[0] == NR3NODESIG)
	{
		memcpy(tmp, data + 1, ALEN);
		tmp[ALEN] = '\0';
		fprintf(stdout, "NET/ROM Routing: %s\n", tmp);
		
		data   += (ALEN + 1);
		length -= (ALEN + 1);

		for(i = 0;i < NRDESTPERPACK;i++) {
			if (length < AXLEN) break;
			
			fprintf(stdout,"        %12s", pax25(tmp, data));

			memcpy(tmp, data + AXLEN, ALEN);
			tmp[ALEN] = '\0';
			fprintf(stdout, "%8s", tmp);

			fprintf(stdout, "    %12s", pax25(tmp, data + AXLEN + ALEN));
			fprintf(stdout, "    %3u\n", data[AXLEN + ALEN + AXLEN]);

			data   += (AXLEN + ALEN + AXLEN + 1);
			length -= (AXLEN + ALEN + AXLEN + 1);
		}

		return;
	}

	/* Decode network layer */
	fprintf(stdout, "NET/ROM: %s", pax25(tmp, data));
	fprintf(stdout, "->%s", pax25(tmp, data + AXLEN));
	fprintf(stdout," ttl %d\n", data[AXLEN + AXLEN]);

	data   += (AXLEN + AXLEN + 1);
	length -= (AXLEN + AXLEN + 1);

	switch (data[4] & NR4OPCODE)
	{
	case NR4OPPID:  /* network PID extension */
		if (data[0] == NRPROTO_IP && data[1] == NRPROTO_IP)
		{
			ip_dump(data + 5, length - 5);
			return;
		}
		else
		{
			fprintf(stdout, "         protocol family %x, proto %x",
						data[0], data[1]);
		}
		break;

	case NR4OPCONRQ:        /* Connect request */
		fprintf(stdout, "         conn rqst: ckt %d/%d", data[0], data[1]);
		fprintf(stdout, " wnd %d", data[5]);
		fprintf(stdout, " %s", pax25(tmp, data + 6));
		fprintf(stdout, "@%s", pax25(tmp, data + 6 + AXLEN));
		data   += AXLEN + AXLEN + 6;
		length -= AXLEN + AXLEN + 6;
		if (length > 0)
			fprintf(stdout, " timeout %d", data[1] * 256 + data[0]);
		fprintf(stdout, "\n");
		break;

	case NR4OPCONAK:        /* Connect acknowledgement */
		fprintf(stdout,"         conn ack: ur ckt %d/%d my ckt %d/%d", data[0], data[1], data[2], data[3]);
		fprintf(stdout, " wnd %d", data[5]);
		netrom_flags(data[4]);
		break;

	case NR4OPDISRQ:        /* Disconnect request */
		fprintf(stdout, "         disc: ckt %d/%d\n", data[0], data[1]);
		break;

	case NR4OPDISAK:        /* Disconnect acknowledgement */
		fprintf(stdout, "         disc ack: ckt %d/%d\n", data[0], data[1]);
		break;

	case NR4OPINFO: /* Information (data) */
		fprintf(stdout, "         info: ckt %d/%d", data[0], data[1]);
		fprintf(stdout, " txseq %d rxseq %d", data[2], data[3]);
		netrom_flags(data[4]);
		data_dump(data + 5, length - 5);
		break;

	case NR4OPACK:  /* Information acknowledgement */
		fprintf(stdout, "         info ack: ckt %d/%d", data[0], data[1]);
		fprintf(stdout, " rxseq %d", data[3]);
		netrom_flags(data[4]);
		break;

	default:
		fprintf(stdout, "         unknown transport type %d\n", data[4] & 0x0f) ;
		break;
	}
}


static void netrom_flags(int flags)
{
	if (flags & NR4CHOKE)
		fprintf(stdout," CHOKE");

	if (flags & NR4NAK)
		fprintf(stdout," NAK");

	if (flags & NR4MORE)
		fprintf(stdout," MORE");

	putc('\n', stdout);
}


