/* TCP header tracing routines
 * Copyright 1991 Phil Karn, KA9Q
 */
#include "global.h"
#include "mbuf.h"
#include "netuser.h"
#include "internet.h"
#include "tcp.h"
#include "trace.h"

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

/* TCP segment header flags */
static const char *Tcpflags[] = {
	"FIN",	/* 0x01 */
	"SYN",	/* 0x02 */
	"RST",	/* 0x04 */
	"PSH",	/* 0x08 */
	"ACK",	/* 0x10 */
	"URG",	/* 0x20 */
	"CE"	/* 0x40 */
};


/* Dump a TCP segment header. Assumed to be in network byte order */
void
tcp_dump (fp, bpp, source, dest, check)
FILE *fp;
struct mbuf **bpp;
uint32 source,dest;	/* IP source and dest addresses */
int check;		/* 0 if checksum test is to be bypassed */
{
struct tcp seg;
struct pseudo_header ph;
int16 csum;
int16 dlen;

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

	/* Verify checksum */
	ph.source = source;
	ph.dest = dest;
	ph.protocol = TCP_PTCL;
	ph.length = len_p (*bpp);
	csum = cksum (&ph, *bpp, ph.length);

	(void) ntohtcp (&seg, bpp);

#ifdef CTRACE
	if (use_ctrace)
		traceprintf (fp, "%sTCP: %s%u%s->%s%u%s Seq x%lx",
	    	    Agreen, Abold, seg.source, Aboldoff, Abold, seg.dest, Aboldoff, seg.seq);
	else
#endif
	traceprintf (fp, "TCP: %u->%u Seq x%lx", seg.source, seg.dest, seg.seq);
	if (seg.flags.ack)
		traceprintf (fp, " Ack x%lx", seg.ack);
	if (seg.flags.congest) {
#ifdef CTRACE
		if (use_ctrace)
			traceprintf (fp, " %s%s%s", Abold, Tcpflags[6], Aboldoff);
		else
#endif
		traceprintf (fp, " %s", Tcpflags[6]);
	}
	if (seg.flags.urg) {
#ifdef CTRACE
		if (use_ctrace)
			traceprintf (fp, " %s%s%s", Abold, Tcpflags[5], Aboldoff);
		else
#endif
		traceprintf (fp, " %s", Tcpflags[5]);
	}
	if (seg.flags.ack) {
#ifdef CTRACE
		if (use_ctrace)
			traceprintf (fp, " %s%s%s", Abold, Tcpflags[4], Aboldoff);
		else
#endif
		traceprintf (fp, " %s", Tcpflags[4]);
	}
	if (seg.flags.psh) {
#ifdef CTRACE
		if (use_ctrace)
			traceprintf (fp, " %s%s%s", Abold, Tcpflags[3], Aboldoff);
		else
#endif
		traceprintf (fp, " %s", Tcpflags[3]);
	}
	if (seg.flags.rst) {
#ifdef CTRACE
		if (use_ctrace)
			traceprintf (fp, " %s%s%s", Abold, Tcpflags[2], Aboldoff);
		else
#endif
		traceprintf (fp, " %s", Tcpflags[2]);
	}
	if (seg.flags.syn) {
#ifdef CTRACE
		if (use_ctrace)
			traceprintf (fp, " %s%s%s", Abold, Tcpflags[1], Aboldoff);
		else
#endif
		traceprintf (fp, " %s", Tcpflags[1]);
	}
	if (seg.flags.fin) {
#ifdef CTRACE
		if (use_ctrace)
			traceprintf (fp, " %s%s%s", Abold, Tcpflags[0], Aboldoff);
		else
#endif
		traceprintf (fp, " %s", Tcpflags[0]);
	}

	traceprintf (fp, " Wnd %u", seg.wnd);
	if (seg.flags.urg)
		traceprintf (fp, " UP x%x", seg.up);
	/* Print options, if any */
	if (seg.mss != 0)
		traceprintf (fp, " MSS %u", seg.mss);
	if ((dlen = len_p (*bpp)) != 0)
		traceprintf (fp, " Data %u", dlen);
	if (check && csum != 0)
		traceprintf (fp, " CHECKSUM ERROR (%u)", csum);
	traceprintf (fp, "\n");
}

