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

static char *decode_type __ARGS((int16 type));

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

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

	fprintf(fp, " ");
	type = ftype(control);
	fprintf(fp,"%s",decode_type(type));
	/* Dump poll/final bit */
	if(control & PF){
		switch(hdr.cmdrsp){
		case LAPB_COMMAND:
			fprintf(fp,"(P)");
			break;
		case LAPB_RESPONSE:
			fprintf(fp,"(F)");
			break;
		default:
			fprintf(fp,"(P/F)");
			break;
		}
	}
	/* Dump sequence numbers */
	if((type & 0x3) != U)	/* I or S frame? */
		fprintf(fp," NR=%d",(control>>5)&7);
	if(type == I || type == UI){	
		if(type == I)
			fprintf(fp," NS=%d",(control>>1)&7);
		/* Decode I field */
		if((pid = PULLCHAR(bpp)) != -1){	/* Get pid */
			if(pid == PID_SEGMENT){
				unsegmented = 0;
				seg = PULLCHAR(bpp);
				fprintf(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:
				fprintf (fp, "\n");
				break;	/* Already displayed */
			case PID_ARP:
				fprintf(fp," pid=ARP (0x%x)\n",pid);
				arp_dump(fp,bpp);
				break;
			case PID_RARP:
				fprintf(fp," pid=RARP (0x%x)\n",pid);
				arp_dump(fp,bpp);
				break;
			case PID_NETROM:
				fprintf(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:
				fprintf(fp," pid=IP (0x%x)\n",pid);
				/* Don't verify checksums unless unsegmented */
				ip_dump(fp,bpp,unsegmented);
				break;
			case PID_X25:
				fprintf(fp," pid=X.25 (0x%x)\n",pid);
				break;
			case PID_TEXNET:
				fprintf(fp," pid=TEXNET (0x%x)\n",pid);
				break;
			case PID_NO_L3:
				fprintf(fp," pid=Text (0x%x)\n",pid);
				break;
			default:
				fprintf(fp," pid=0x%x\n",pid);
			}
		}
	} else if(type == FRMR && pullup(bpp,frmr,3) == 3){
		fprintf(fp,": %s",decode_type(ftype(frmr[0])));
		fprintf(fp," Vr = %d Vs = %d",(frmr[1] >> 5) & MMASK,
			(frmr[1] >> 1) & MMASK);
		if(frmr[2] & W)
			fprintf(fp," Invalid control field");
		if(frmr[2] & X)
			fprintf(fp," Illegal I-field");
		if(frmr[2] & Y)
			fprintf(fp," Too-long I-field");
		if(frmr[2] & Z)
			fprintf(fp," Invalid seq number");
			fprintf (fp, "\n");
	} else
		fprintf (fp, "\n");

}
static char *
decode_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,dest,AXALEN) < AXALEN)
		return 0;
	if(addreq(dest,iface->hwaddr))
		return 1;
	else
		return 0;
}

#endif /* AX25 */

