trpt.c revision 14544
11553Srgrimes/*
21553Srgrimes * Copyright (c) 1983, 1988, 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
131553Srgrimes * 3. All advertising materials mentioning features or use of this software
141553Srgrimes *    must display the following acknowledgement:
151553Srgrimes *	This product includes software developed by the University of
161553Srgrimes *	California, Berkeley and its contributors.
171553Srgrimes * 4. Neither the name of the University nor the names of its contributors
181553Srgrimes *    may be used to endorse or promote products derived from this software
191553Srgrimes *    without specific prior written permission.
201553Srgrimes *
211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311553Srgrimes * SUCH DAMAGE.
321553Srgrimes */
331553Srgrimes
341553Srgrimes#ifndef lint
351553Srgrimesstatic char copyright[] =
361553Srgrimes"@(#) Copyright (c) 1983, 1988, 1993\n\
371553Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381553Srgrimes#endif /* not lint */
391553Srgrimes
401553Srgrimes#ifndef lint
411553Srgrimesstatic char sccsid[] = "@(#)trpt.c	8.1 (Berkeley) 6/6/93";
421553Srgrimes#endif /* not lint */
431553Srgrimes
441553Srgrimes#include <sys/param.h>
4514544Sdg#include <sys/queue.h>
461553Srgrimes#if BSD >= 199103
471553Srgrimes#define NEWVM
481553Srgrimes#endif
491553Srgrimes#ifndef NEWVM
501553Srgrimes#include <machine/pte.h>
511553Srgrimes#include <sys/vmmac.h>
521553Srgrimes#endif
531553Srgrimes#include <sys/socket.h>
541553Srgrimes#include <sys/socketvar.h>
551553Srgrimes#define PRUREQUESTS
561553Srgrimes#include <sys/protosw.h>
571553Srgrimes#include <sys/file.h>
581553Srgrimes
591553Srgrimes#include <net/route.h>
601553Srgrimes#include <net/if.h>
611553Srgrimes
621553Srgrimes#include <netinet/in.h>
631553Srgrimes#include <netinet/in_systm.h>
641553Srgrimes#include <netinet/ip.h>
651553Srgrimes#include <netinet/ip_var.h>
661553Srgrimes#include <netinet/tcp.h>
671553Srgrimes#define TCPSTATES
681553Srgrimes#include <netinet/tcp_fsm.h>
691553Srgrimes#include <netinet/tcp_seq.h>
701553Srgrimes#define	TCPTIMERS
711553Srgrimes#include <netinet/tcp_timer.h>
721553Srgrimes#include <netinet/tcp_var.h>
731553Srgrimes#include <netinet/tcpip.h>
741553Srgrimes#define	TANAMES
751553Srgrimes#include <netinet/tcp_debug.h>
761553Srgrimes
771553Srgrimes#include <arpa/inet.h>
781553Srgrimes
791553Srgrimes#include <stdio.h>
801553Srgrimes#include <errno.h>
811553Srgrimes#include <nlist.h>
821553Srgrimes#include <paths.h>
831553Srgrimes
841553Srgrimesstruct nlist nl[] = {
851553Srgrimes#define	N_TCP_DEBUG	0
861553Srgrimes	{ "_tcp_debug" },
871553Srgrimes#define	N_TCP_DEBX	1
881553Srgrimes	{ "_tcp_debx" },
891553Srgrimes#ifndef NEWVM
901553Srgrimes#define	N_SYSMAP	2
911553Srgrimes	{ "_Sysmap" },
921553Srgrimes#define	N_SYSSIZE	3
931553Srgrimes	{ "_Syssize" },
941553Srgrimes#endif
951553Srgrimes	{ "" },
961553Srgrimes};
971553Srgrimes
981553Srgrimes#ifndef NEWVM
991553Srgrimesstatic struct pte *Sysmap;
1001553Srgrimes#endif
1011553Srgrimesstatic caddr_t tcp_pcbs[TCP_NDEBUG];
1021553Srgrimesstatic n_time ntime;
1031553Srgrimesstatic int aflag, kflag, memf, follow, sflag, tflag;
1041553Srgrimes
1051553Srgrimesmain(argc, argv)
1061553Srgrimes	int argc;
1071553Srgrimes	char **argv;
1081553Srgrimes{
1091553Srgrimes	extern char *optarg;
1101553Srgrimes	extern int optind;
1111553Srgrimes	int ch, i, jflag, npcbs, numeric();
1121553Srgrimes	char *system, *core, *malloc();
1131553Srgrimes	off_t lseek();
1141553Srgrimes
1151553Srgrimes	jflag = npcbs = 0;
1161553Srgrimes	while ((ch = getopt(argc, argv, "afjp:st")) != EOF)
1171553Srgrimes		switch (ch) {
1181553Srgrimes		case 'a':
1191553Srgrimes			++aflag;
1201553Srgrimes			break;
1211553Srgrimes		case 'f':
1221553Srgrimes			++follow;
1231553Srgrimes			setlinebuf(stdout);
1241553Srgrimes			break;
1251553Srgrimes		case 'j':
1261553Srgrimes			++jflag;
1271553Srgrimes			break;
1281553Srgrimes		case 'p':
1291553Srgrimes			if (npcbs >= TCP_NDEBUG) {
1301553Srgrimes				fputs("trpt: too many pcb's specified\n",
1311553Srgrimes				    stderr);
1321553Srgrimes				exit(1);
1331553Srgrimes			}
1341553Srgrimes			(void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]);
1351553Srgrimes			break;
1361553Srgrimes		case 's':
1371553Srgrimes			++sflag;
1381553Srgrimes			break;
1391553Srgrimes		case 't':
1401553Srgrimes			++tflag;
1411553Srgrimes			break;
1421553Srgrimes		case '?':
1431553Srgrimes		default:
1441553Srgrimes			(void)fprintf(stderr,
1451553Srgrimes"usage: trpt [-afjst] [-p hex-address] [system [core]]\n");
1461553Srgrimes			exit(1);
1471553Srgrimes		}
1481553Srgrimes	argc -= optind;
1491553Srgrimes	argv += optind;
1501553Srgrimes
1511553Srgrimes	core = _PATH_KMEM;
1521553Srgrimes	if (argc > 0) {
1531553Srgrimes		system = *argv;
1541553Srgrimes		argc--, argv++;
1551553Srgrimes		if (argc > 0) {
1561553Srgrimes			core = *argv;
1571553Srgrimes			argc--, argv++;
1581553Srgrimes			++kflag;
1591553Srgrimes		}
1601553Srgrimes		/*
1611553Srgrimes		 * Discard setgid privileges if not the running kernel so that
1621553Srgrimes		 * bad guys can't print interesting stuff from kernel memory.
1631553Srgrimes		 */
1641553Srgrimes		setgid(getgid());
1651553Srgrimes	}
1661553Srgrimes	else
1673041Swollman		system = (char *)getbootfile();
1681553Srgrimes
1691553Srgrimes	if (nlist(system, nl) < 0 || !nl[0].n_value) {
1701553Srgrimes		fprintf(stderr, "trpt: %s: no namelist\n", system);
1711553Srgrimes		exit(1);
1721553Srgrimes	}
1731553Srgrimes	if ((memf = open(core, O_RDONLY)) < 0) {
1741553Srgrimes		perror(core);
1751553Srgrimes		exit(2);
1761553Srgrimes	}
1771553Srgrimes	if (kflag) {
1781553Srgrimes#ifdef NEWVM
1791553Srgrimes		fputs("trpt: can't do core files yet\n", stderr);
1801553Srgrimes		exit(1);
1811553Srgrimes#else
1821553Srgrimes		off_t off;
1831553Srgrimes
1841553Srgrimes		Sysmap = (struct pte *)
1851553Srgrimes		   malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
1861553Srgrimes		if (!Sysmap) {
1871553Srgrimes			fputs("trpt: can't get memory for Sysmap.\n", stderr);
1881553Srgrimes			exit(1);
1891553Srgrimes		}
1901553Srgrimes		off = nl[N_SYSMAP].n_value & ~KERNBASE;
1911553Srgrimes		(void)lseek(memf, off, L_SET);
1921553Srgrimes		(void)read(memf, (char *)Sysmap,
1931553Srgrimes		    (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
1941553Srgrimes#endif
1951553Srgrimes	}
1961553Srgrimes	(void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
1971553Srgrimes	if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
1981553Srgrimes	    sizeof(tcp_debx)) {
1991553Srgrimes		perror("trpt: tcp_debx");
2001553Srgrimes		exit(3);
2011553Srgrimes	}
2021553Srgrimes	(void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
2031553Srgrimes	if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
2041553Srgrimes	    sizeof(tcp_debug)) {
2051553Srgrimes		perror("trpt: tcp_debug");
2061553Srgrimes		exit(3);
2071553Srgrimes	}
2081553Srgrimes	/*
2091553Srgrimes	 * If no control blocks have been specified, figure
2101553Srgrimes	 * out how many distinct one we have and summarize
2111553Srgrimes	 * them in tcp_pcbs for sorting the trace records
2121553Srgrimes	 * below.
2131553Srgrimes	 */
2141553Srgrimes	if (!npcbs) {
2151553Srgrimes		for (i = 0; i < TCP_NDEBUG; i++) {
2161553Srgrimes			register struct tcp_debug *td = &tcp_debug[i];
2171553Srgrimes			register int j;
2181553Srgrimes
2191553Srgrimes			if (td->td_tcb == 0)
2201553Srgrimes				continue;
2211553Srgrimes			for (j = 0; j < npcbs; j++)
2221553Srgrimes				if (tcp_pcbs[j] == td->td_tcb)
2231553Srgrimes					break;
2241553Srgrimes			if (j >= npcbs)
2251553Srgrimes				tcp_pcbs[npcbs++] = td->td_tcb;
2261553Srgrimes		}
2271553Srgrimes		if (!npcbs)
2281553Srgrimes			exit(0);
2291553Srgrimes	}
2301553Srgrimes	qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric);
2311553Srgrimes	if (jflag) {
2321553Srgrimes		for (i = 0;;) {
2331553Srgrimes			printf("%x", (int)tcp_pcbs[i]);
2341553Srgrimes			if (++i == npcbs)
2351553Srgrimes				break;
2361553Srgrimes			fputs(", ", stdout);
2371553Srgrimes		}
2381553Srgrimes		putchar('\n');
2391553Srgrimes	}
2401553Srgrimes	else for (i = 0; i < npcbs; i++) {
2411553Srgrimes		printf("\n%x:\n", (int)tcp_pcbs[i]);
2421553Srgrimes		dotrace(tcp_pcbs[i]);
2431553Srgrimes	}
2441553Srgrimes	exit(0);
2451553Srgrimes}
2461553Srgrimes
2471553Srgrimesdotrace(tcpcb)
2481553Srgrimes	register caddr_t tcpcb;
2491553Srgrimes{
2501553Srgrimes	register struct tcp_debug *td;
2511553Srgrimes	register int i;
2521553Srgrimes	int prev_debx = tcp_debx;
2531553Srgrimes
2541553Srgrimesagain:	if (--tcp_debx < 0)
2551553Srgrimes		tcp_debx = TCP_NDEBUG - 1;
2561553Srgrimes	for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) {
2571553Srgrimes		td = &tcp_debug[i];
2581553Srgrimes		if (tcpcb && td->td_tcb != tcpcb)
2591553Srgrimes			continue;
2601553Srgrimes		ntime = ntohl(td->td_time);
2611553Srgrimes		tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb,
2621553Srgrimes		    &td->td_ti, td->td_req);
2631553Srgrimes		if (i == tcp_debx)
2641553Srgrimes			goto done;
2651553Srgrimes	}
2661553Srgrimes	for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) {
2671553Srgrimes		td = &tcp_debug[i];
2681553Srgrimes		if (tcpcb && td->td_tcb != tcpcb)
2691553Srgrimes			continue;
2701553Srgrimes		ntime = ntohl(td->td_time);
2711553Srgrimes		tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb,
2721553Srgrimes		    &td->td_ti, td->td_req);
2731553Srgrimes	}
2741553Srgrimesdone:	if (follow) {
2751553Srgrimes		prev_debx = tcp_debx + 1;
2761553Srgrimes		if (prev_debx >= TCP_NDEBUG)
2771553Srgrimes			prev_debx = 0;
2781553Srgrimes		do {
2791553Srgrimes			sleep(1);
2801553Srgrimes			(void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
2811553Srgrimes			if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
2821553Srgrimes			    sizeof(tcp_debx)) {
2831553Srgrimes				perror("trpt: tcp_debx");
2841553Srgrimes				exit(3);
2851553Srgrimes			}
2861553Srgrimes		} while (tcp_debx == prev_debx);
2871553Srgrimes		(void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
2881553Srgrimes		if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
2891553Srgrimes		    sizeof(tcp_debug)) {
2901553Srgrimes			perror("trpt: tcp_debug");
2911553Srgrimes			exit(3);
2921553Srgrimes		}
2931553Srgrimes		goto again;
2941553Srgrimes	}
2951553Srgrimes}
2961553Srgrimes
2971553Srgrimes/*
2981553Srgrimes * Tcp debug routines
2991553Srgrimes */
3001553Srgrimes/*ARGSUSED*/
3011553Srgrimestcp_trace(act, ostate, atp, tp, ti, req)
3021553Srgrimes	short act, ostate;
3031553Srgrimes	struct tcpcb *atp, *tp;
3041553Srgrimes	struct tcpiphdr *ti;
3051553Srgrimes	int req;
3061553Srgrimes{
3071553Srgrimes	tcp_seq seq, ack;
3081553Srgrimes	int flags, len, win, timer;
3091553Srgrimes
3101553Srgrimes	printf("%03ld %s:%s ",(ntime/10) % 1000, tcpstates[ostate],
3111553Srgrimes	    tanames[act]);
3121553Srgrimes	switch (act) {
3131553Srgrimes	case TA_INPUT:
3141553Srgrimes	case TA_OUTPUT:
3151553Srgrimes	case TA_DROP:
3161553Srgrimes		if (aflag) {
3171553Srgrimes			printf("(src=%s,%u, ",
3181553Srgrimes			    inet_ntoa(ti->ti_src), ntohs(ti->ti_sport));
3191553Srgrimes			printf("dst=%s,%u)",
3201553Srgrimes			    inet_ntoa(ti->ti_dst), ntohs(ti->ti_dport));
3211553Srgrimes		}
3221553Srgrimes		seq = ti->ti_seq;
3231553Srgrimes		ack = ti->ti_ack;
3241553Srgrimes		len = ti->ti_len;
3251553Srgrimes		win = ti->ti_win;
3261553Srgrimes		if (act == TA_OUTPUT) {
3271553Srgrimes			seq = ntohl(seq);
3281553Srgrimes			ack = ntohl(ack);
3291553Srgrimes			len = ntohs(len);
3301553Srgrimes			win = ntohs(win);
3311553Srgrimes		}
3321553Srgrimes		if (act == TA_OUTPUT)
3331553Srgrimes			len -= sizeof(struct tcphdr);
3341553Srgrimes		if (len)
3351553Srgrimes			printf("[%lx..%lx)", seq, seq + len);
3361553Srgrimes		else
3371553Srgrimes			printf("%lx", seq);
3381553Srgrimes		printf("@%lx", ack);
3391553Srgrimes		if (win)
3401553Srgrimes			printf("(win=%x)", win);
3411553Srgrimes		flags = ti->ti_flags;
3421553Srgrimes		if (flags) {
3431553Srgrimes			register char *cp = "<";
3441553Srgrimes#define	pf(flag, string) { \
3451553Srgrimes	if (ti->ti_flags&flag) { \
3461553Srgrimes		(void)printf("%s%s", cp, string); \
3471553Srgrimes		cp = ","; \
3481553Srgrimes	} \
3491553Srgrimes}
3501553Srgrimes			pf(TH_SYN, "SYN");
3511553Srgrimes			pf(TH_ACK, "ACK");
3521553Srgrimes			pf(TH_FIN, "FIN");
3531553Srgrimes			pf(TH_RST, "RST");
3541553Srgrimes			pf(TH_PUSH, "PUSH");
3551553Srgrimes			pf(TH_URG, "URG");
3561553Srgrimes			printf(">");
3571553Srgrimes		}
3581553Srgrimes		break;
3591553Srgrimes	case TA_USER:
3601553Srgrimes		timer = req >> 8;
3611553Srgrimes		req &= 0xff;
3621553Srgrimes		printf("%s", prurequests[req]);
3631553Srgrimes		if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO)
3641553Srgrimes			printf("<%s>", tcptimers[timer]);
3651553Srgrimes		break;
3661553Srgrimes	}
3671553Srgrimes	printf(" -> %s", tcpstates[tp->t_state]);
3681553Srgrimes	/* print out internal state of tp !?! */
3691553Srgrimes	printf("\n");
3701553Srgrimes	if (sflag) {
3711553Srgrimes		printf("\trcv_nxt %lx rcv_wnd %x snd_una %lx snd_nxt %lx snd_max %lx\n",
3721553Srgrimes		    tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt,
3731553Srgrimes		    tp->snd_max);
3741553Srgrimes		printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %x\n", tp->snd_wl1,
3751553Srgrimes		    tp->snd_wl2, tp->snd_wnd);
3761553Srgrimes	}
3771553Srgrimes	/* print out timers? */
3781553Srgrimes	if (tflag) {
3791553Srgrimes		register char *cp = "\t";
3801553Srgrimes		register int i;
3811553Srgrimes
3821553Srgrimes		for (i = 0; i < TCPT_NTIMERS; i++) {
3831553Srgrimes			if (tp->t_timer[i] == 0)
3841553Srgrimes				continue;
3851553Srgrimes			printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]);
3861553Srgrimes			if (i == TCPT_REXMT)
3871553Srgrimes				printf(" (t_rxtshft=%d)", tp->t_rxtshift);
3881553Srgrimes			cp = ", ";
3891553Srgrimes		}
3901553Srgrimes		if (*cp != '\t')
3911553Srgrimes			putchar('\n');
3921553Srgrimes	}
3931553Srgrimes}
3941553Srgrimes
3951553Srgrimesnumeric(c1, c2)
3961553Srgrimes	caddr_t *c1, *c2;
3971553Srgrimes{
3981553Srgrimes	return(*c1 - *c2);
3991553Srgrimes}
4001553Srgrimes
4011553Srgrimesklseek(fd, base, off)
4021553Srgrimes	int fd, off;
4031553Srgrimes	off_t base;
4041553Srgrimes{
4051553Srgrimes	off_t lseek();
4061553Srgrimes
4071553Srgrimes#ifndef NEWVM
4081553Srgrimes	if (kflag) {	/* get kernel pte */
4091553Srgrimes		base &= ~KERNBASE;
4101553Srgrimes		base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
4111553Srgrimes	}
4121553Srgrimes#endif
4131553Srgrimes	(void)lseek(fd, base, off);
4141553Srgrimes}
415