/* AX25 header tracing
 * Copyright 1991 Phil Karn, KA9Q
 */
/* Mods by PA0GRI */
#include "global.h"
#ifdef AX25
#include "mbuf.h"
#include "ax25.h"
#include "trace.h"

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: ax25dump.c,v 1.13 2000/05/09 16:48:24 brian Exp $";
#endif

static const char *decode_the_type (int16 type);


/* Dump an AX.25 packet header */
void
ax25_dump (fp, bpp, check)
FILE *fp;
struct mbuf **bpp;
int check OPTIONAL;		/* Not used */
{
char tmp[AXBUF];
char frmr[3];
int control, pid, seg;
int16 type;
int unsegmented;
struct ax25 hdr;
char *hp;

#ifdef CTRACE
	if (use_ctrace)
		traceprintf (fp, Acyan);
#endif
	traceprintf (fp, "AX25: ");
	/* Extract the address header */
	if (ntohax25 (&hdr, bpp) < 0) {
		/* Something wrong with the header */
#ifdef CTRACE
		if (use_ctrace)
        		traceprintf (fp, " %sbad header!%s%s\n", Aalert, Acyan, Aboldoff);
		else
#endif
		traceprintf (fp, " bad header!\n");
		return;
	}
#ifdef CTRACE
	if (use_ctrace) {
		traceprintf (fp, "%s%s%s", Abold, pax25 (tmp, hdr.source), Aboldoff);
		traceprintf (fp, "->%s%s%s", Abold, pax25 (tmp, hdr.dest), Aboldoff);
	} else {
#endif
	traceprintf (fp, "%s", pax25 (tmp, hdr.source));
	traceprintf (fp, "->%s", pax25 (tmp, hdr.dest));
#ifdef CTRACE
	}
#endif
	if (hdr.ndigis > 0) {
		traceprintf (fp, " v");
		for (hp = hdr.digis[0]; hp < &hdr.digis[hdr.ndigis][0];
		     hp += AXALEN) {
			/* Print digi string */
#ifdef CTRACE
			if (use_ctrace)
				traceprintf (fp, " %s%s%s%s", Abold, pax25 (tmp, hp),
				     (hp[ALEN] & REPEATED) ? "*" : "", Aboldoff);
			else
#endif
			traceprintf (fp, " %s%s", pax25 (tmp, hp),
				     (hp[ALEN] & REPEATED) ? "*" : "");
		}
	}
	if ((control = PULLCHAR (bpp)) == -1)
		return;

	traceprintf (fp, " ");
	type = ftype (control);
#ifdef CTRACE
	if (use_ctrace)
		traceprintf (fp, "%s%s%s", Abold, decode_the_type (type), Aboldoff);
	else
#endif	
	traceprintf (fp, "%s", decode_the_type (type));
	/* Dump poll/final bit */
	if (control & PF) {
		switch (hdr.cmdrsp) {
			case LAPB_COMMAND:
#ifdef CTRACE
				if (use_ctrace)
					traceprintf (fp, "(%sP%s)", Abold, Aboldoff);
				else
#endif				
				traceprintf (fp, "(P)");
				break;
			case LAPB_RESPONSE:
#ifdef CTRACE
				if (use_ctrace)
					traceprintf (fp, "(%sF%s)", Abold, Aboldoff);
				else
#endif				
				traceprintf (fp, "(F)");
				break;
			default:
#ifdef CTRACE
				if (use_ctrace)
					traceprintf (fp, "(%sP/F%s)", Abold, Aboldoff);
				else
#endif				
				traceprintf (fp, "(P/F)");
				break;
		}
	}
	/* Dump sequence numbers */
	if ((type & 0x3) != U)	/* I or S frame? */
		traceprintf (fp, " NR=%d", (control >> 5) & 7);	/*lint !e702 */
	if (type == I || type == UI) {
		if (type == I)
			traceprintf (fp, " NS=%d", (control >> 1) & 7);	/*lint !e702 */
		/* Decode I field */
		if ((pid = PULLCHAR (bpp)) != -1) {	/* Get pid */
			if (pid == PID_SEGMENT) {
				unsegmented = 0;
				seg = PULLCHAR (bpp);
				traceprintf (fp, "%s remain %u", seg & SEG_FIRST ?
					 " First seg;" : "", seg & SEG_REM);
				if (seg & SEG_FIRST)
					pid = PULLCHAR (bpp);
			} else
				unsegmented = 1;

			switch (pid) {
				case PID_SEGMENT:
					traceprintf (fp, "\n");
					break;	/* Already displayed */
				case PID_ARP:
#ifdef CTRACE
					if (use_ctrace)
						traceprintf (fp, " pid=%sARP%s (0x%x)\n", Abold, Aboldoff, pid);
					else
#endif
					traceprintf (fp, " pid=ARP (0x%x)\n", pid);
					arp_dump (fp, bpp);
					break;
				case PID_RARP:
#ifdef CTRACE
					if (use_ctrace)
						traceprintf (fp, " pid=%sRARP%s (0x%x)\n", Abold, Aboldoff, pid);
					else
#endif					
					traceprintf (fp, " pid=RARP (0x%x)\n", pid);
					arp_dump (fp, bpp);
					break;
				case PID_NETROM:
					traceprintf (fp, " pid=NET/ROM (0x%x)\n", pid);
					/* Don't verify checksums unless unsegmented */
#ifdef NETROM
					netrom_dump (fp, bpp, unsegmented);
#endif
					break;
				case PID_IP:
#ifdef CTRACE
					if (use_ctrace)
						traceprintf (fp, " pid=%sIP%s (0x%x)\n", Abold, Aboldoff, pid);
					else
#endif					
					traceprintf (fp, " pid=IP (0x%x)\n", pid);
					/* Don't verify checksums unless unsegmented */
					ip_dump (fp, bpp, unsegmented);
					break;
				case PID_X25:
					traceprintf (fp, " pid=X.25 (0x%x)\n", pid);
					break;
				case PID_TEXNET:
					traceprintf (fp, " pid=TEXNET (0x%x)\n", pid);
					break;
				case PID_NO_L3:
					traceprintf (fp, " pid=Text (0x%x)\n", pid);
					break;
				default:
					traceprintf (fp, " pid=0x%x\n", pid);
			}
		}
	} else if (type == FRMR && pullup (bpp, (unsigned char *) frmr, 3) == 3) {
		traceprintf (fp, ": %s", decode_the_type (ftype (frmr[0])));
		traceprintf (fp, " Vr = %d Vs = %d", (frmr[1] >> 5) & MMASK, (frmr[1] >> 1) & MMASK);	/*lint !e702 */
		if (frmr[2] & W)
			traceprintf (fp, " Invalid control field");
		if (frmr[2] & X)
			traceprintf (fp, " Illegal I-field");
		if (frmr[2] & Y)
			traceprintf (fp, " Too-long I-field");
		if (frmr[2] & Z)
			traceprintf (fp, " Invalid seq number");
		traceprintf (fp, "\n");
	} else
		traceprintf (fp, "\n");

}


static const char *
decode_the_type (type)
int16 type;
{
	switch (type) {
		case I:		return "I";
		case SABM:	return "SABM";
		case DISC:	return "DISC";
		case DM:	return "DM";
		case UA:	return "UA";
		case RR:	return "RR";
		case RNR:	return "RNR";
		case REJ:	return "REJ";
		case FRMR:	return "FRMR";
		case UI:	return "UI";
		default:	return "[invalid]";
	}
}


/* Return 1 if this packet is directed to us, 0 otherwise. Note that
 * this checks only the ultimate destination, not the digipeater field
 */
int
ax_forus (iface, bp)
struct iface *iface;
struct mbuf *bp;
{
	struct mbuf *bpp;
	char dest[AXALEN];

	/* Duplicate the destination address */
	if (dup_p (&bpp, bp, 0, AXALEN) != AXALEN) {
		free_p (bpp);
		return 0;
	}
	if (pullup (&bpp, (unsigned char *) dest, AXALEN) < AXALEN)
		return 0;
	if (addreq (dest, iface->hwaddr))
		return 1;
	else
		return 0;
}

#endif /* AX25 */
