/* Serial line tracing routines
 *   Katie Stevens, UC Davis (original code)
 *   Phil Karn, KA9Q
 */
#include <stdio.h>
#include "global.h"
#include "mbuf.h"
#include "internet.h"
#include "ip.h"
#include "slcomp.h"
#include "trace.h"

static int16 decodeint __ARGS((struct mbuf **bpp));

/* dump serial line IP packet; may have Van Jacobson TCP header compression */
void
sl_dump(fp,bpp,unused)
FILE *fp;
struct mbuf **bpp;
int unused;
{
	struct mbuf *bp, *tbp;
	unsigned char c;
	int len;

	bp = *bpp;
	c = bp->data[0];
	if ((c & 0xf0) == (IPVERSION << 4)) {
		fprintf(fp,"serial line IP: len: %3u\n",len_p(*bpp));
		ip_dump(fp,bpp,1);
	} else if (c & 0x80) {
		fprintf(fp,"serial line VJ Compressed TCP: len %3u\n",len_p(*bpp));
		vjcomp_dump(fp,bpp,0);
	} else {
		len = len_p(bp);
		fprintf(fp,"serial line VJ Uncompressed TCP: len %3u connection ID: %3u\n",
			len, uchar(bp->data[9]));	/* FIX THIS! */
		/* Get our own copy so we can mess with the data */
		tbp = copy_p(bp, len);
		free_p(bp);
		*bpp = NULLBUF;
		/* Restore the bytes used with Uncompressed TCP */
		tbp->data[0] &= 0x4f;		/* FIX THIS! */
		tbp->data[9] = TCP_PTCL;	/* FIX THIS! */	
		/* Dump contents as a regular IP packet */
		ip_dump(fp,&tbp,1);
	}
}

static int16
decodeint(bpp)
struct mbuf **bpp;
{
	char tmpbuf[2];

	pullup(bpp,tmpbuf,1);
	if (tmpbuf[0] == 0)
		pullup(bpp,tmpbuf,2);
	else {
	 	tmpbuf[1] = tmpbuf[0];
		tmpbuf[0] = 0;
	}
	return(get16(tmpbuf));
}

void
vjcomp_dump(fp,bpp,unused)
FILE *fp;
struct mbuf **bpp;
int unused;
{
	char changes;
	char tmpbuf[2];

	if(bpp == NULLBUFP || *bpp == NULLBUF)
		return;	

	/* Dump compressed TCP/IP header */
	fprintf(fp,"VJ Compr TCP/IP: ");
	pullup(bpp,&changes,1);
	fprintf(fp,"changes: 0x%02x   ",uchar(changes));
	if (changes & NEW_C) {
		pullup(bpp,tmpbuf,1);
		fprintf(fp,"connection: 0x%02x   ",uchar(tmpbuf[0]));
	}
	pullup(bpp,tmpbuf,2);
	fprintf(fp,"TCP checksum: 0x%04x   ",get16(tmpbuf));

	if (changes & TCP_PUSH_BIT)
		fprintf(fp,"PUSH\n");
	else
		fprintf(fp,"\n");

	switch (changes & SPECIALS_MASK) {
	case SPECIAL_I:
		fprintf(fp,"\t\t delta ACK and delta SEQ implied by length of data\n");
		break;

	case SPECIAL_D:
		fprintf(fp,"\t\t delta SEQ implied by length of data\n");
		break;

	default:
		fprintf(fp,"\t\t ");
		if (changes & NEW_U) {
			fprintf(fp,"Urgent pointer: 0x%02x   ",decodeint(bpp));
		}
		if (changes & NEW_W)
			fprintf(fp,"delta WINDOW: 0x%02x   ",decodeint(bpp));
		if (changes & NEW_A)
			fprintf(fp,"delta ACK: 0x%02x   ",decodeint(bpp));
		if (changes & NEW_S)
			fprintf(fp,"delta SEQ: 0x%02x   ",decodeint(bpp));
		break;
	}
	if (changes & NEW_I) {
		fprintf(fp,"new ID: %02x   ",decodeint(bpp));
	} else
		fprintf(fp,"increment ID   ");
	fprintf(fp,"\n");
}
