xref: /csrg-svn/usr.sbin/trpt/trpt.c (revision 42829)
1 /*
2  * Copyright (c) 1983, 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)trpt.c	5.13 (Berkeley) 06/01/90";
16 #endif /* not lint */
17 
18 #include <machine/pte.h>
19 
20 #include <sys/param.h>
21 #include <sys/vmmac.h>
22 #include <sys/socket.h>
23 #include <sys/socketvar.h>
24 #define PRUREQUESTS
25 #include <sys/protosw.h>
26 #include <sys/file.h>
27 
28 #include <net/route.h>
29 #include <net/if.h>
30 
31 #include <netinet/in.h>
32 #include <netinet/in_systm.h>
33 #include <netinet/ip.h>
34 #include <netinet/in_pcb.h>
35 #include <netinet/ip_var.h>
36 #include <netinet/tcp.h>
37 #define TCPSTATES
38 #include <netinet/tcp_fsm.h>
39 #include <netinet/tcp_seq.h>
40 #define	TCPTIMERS
41 #include <netinet/tcp_timer.h>
42 #include <netinet/tcp_var.h>
43 #include <netinet/tcpip.h>
44 #define	TANAMES
45 #include <netinet/tcp_debug.h>
46 
47 #include <arpa/inet.h>
48 
49 #include <stdio.h>
50 #include <errno.h>
51 #include <nlist.h>
52 #include <paths.h>
53 
54 struct nlist nl[] = {
55 #define	N_TCP_DEBUG	0
56 	{ "_tcp_debug" },
57 #define	N_TCP_DEBX	1
58 	{ "_tcp_debx" },
59 #define	N_SYSMAP	2
60 	{ "_Sysmap" },
61 #define	N_SYSSIZE	3
62 	{ "_Syssize" },
63 	{ "" },
64 };
65 
66 static struct pte *Sysmap;
67 static caddr_t tcp_pcbs[TCP_NDEBUG];
68 static n_time ntime;
69 static int aflag, kflag, memf, follow, sflag, tflag;
70 
71 main(argc, argv)
72 	int argc;
73 	char **argv;
74 {
75 	extern char *optarg;
76 	extern int optind;
77 	int ch, i, jflag, npcbs, numeric();
78 	char *system, *core, *malloc();
79 	off_t lseek();
80 
81 	jflag = npcbs = 0;
82 	while ((ch = getopt(argc, argv, "afjp:st")) != EOF)
83 		switch((char)ch) {
84 		case 'a':
85 			++aflag;
86 			break;
87 		case 'f':
88 			++follow;
89 			setlinebuf(stdout);
90 			break;
91 		case 'j':
92 			++jflag;
93 			break;
94 		case 'p':
95 			if (npcbs >= TCP_NDEBUG) {
96 				fputs("trpt: too many pcb's specified\n",
97 				    stderr);
98 				exit(1);
99 			}
100 			(void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]);
101 			break;
102 		case 's':
103 			++sflag;
104 			break;
105 		case 't':
106 			++tflag;
107 			break;
108 		case '?':
109 		default:
110 			(void)fprintf(stderr,
111 "usage: trpt [-afjst] [-p hex-address] [system [core]]\n");
112 			exit(1);
113 		}
114 	argc -= optind;
115 	argv += optind;
116 
117 	core = _PATH_KMEM;
118 	if (argc > 0) {
119 		system = *argv;
120 		argc--, argv++;
121 		if (argc > 0) {
122 			core = *argv;
123 			argc--, argv++;
124 			++kflag;
125 		}
126 	}
127 	else
128 		system = _PATH_UNIX;
129 
130 	if (nlist(system, nl) < 0 || !nl[0].n_value) {
131 		fprintf(stderr, "trpt: %s: no namelist\n", system);
132 		exit(1);
133 	}
134 	if ((memf = open(core, O_RDONLY)) < 0) {
135 		perror(core);
136 		exit(2);
137 	}
138 	if (kflag) {
139 		off_t off;
140 
141 		Sysmap = (struct pte *)
142 		   malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
143 		if (!Sysmap) {
144 			fputs("arp: can't get memory for Sysmap.\n", stderr);
145 			exit(1);
146 		}
147 		off = nl[N_SYSMAP].n_value & ~KERNBASE;
148 		(void)lseek(memf, off, L_SET);
149 		(void)read(memf, (char *)Sysmap,
150 		    (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
151 	}
152 	(void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
153 	if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
154 	    sizeof(tcp_debx)) {
155 		perror("trpt: tcp_debx");
156 		exit(3);
157 	}
158 	(void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
159 	if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
160 	    sizeof(tcp_debug)) {
161 		perror("trpt: tcp_debug");
162 		exit(3);
163 	}
164 	/*
165 	 * If no control blocks have been specified, figure
166 	 * out how many distinct one we have and summarize
167 	 * them in tcp_pcbs for sorting the trace records
168 	 * below.
169 	 */
170 	if (!npcbs) {
171 		for (i = 0; i < TCP_NDEBUG; i++) {
172 			register struct tcp_debug *td = &tcp_debug[i];
173 			register int j;
174 
175 			if (td->td_tcb == 0)
176 				continue;
177 			for (j = 0; j < npcbs; j++)
178 				if (tcp_pcbs[j] == td->td_tcb)
179 					break;
180 			if (j >= npcbs)
181 				tcp_pcbs[npcbs++] = td->td_tcb;
182 		}
183 		if (!npcbs)
184 			exit(0);
185 	}
186 	qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric);
187 	if (jflag) {
188 		for (i = 0;;) {
189 			printf("%x", (int)tcp_pcbs[i]);
190 			if (++i == npcbs)
191 				break;
192 			fputs(", ", stdout);
193 		}
194 		putchar('\n');
195 	}
196 	else for (i = 0; i < npcbs; i++) {
197 		printf("\n%x:\n", (int)tcp_pcbs[i]);
198 		dotrace(tcp_pcbs[i]);
199 	}
200 	exit(0);
201 }
202 
203 dotrace(tcpcb)
204 	register caddr_t tcpcb;
205 {
206 	register struct tcp_debug *td;
207 	register int i;
208 	int prev_debx = tcp_debx;
209 
210 again:	if (--tcp_debx < 0)
211 		tcp_debx = TCP_NDEBUG - 1;
212 	for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) {
213 		td = &tcp_debug[i];
214 		if (tcpcb && td->td_tcb != tcpcb)
215 			continue;
216 		ntime = ntohl(td->td_time);
217 		tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb,
218 		    &td->td_ti, td->td_req);
219 		if (i == tcp_debx)
220 			goto done;
221 	}
222 	for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) {
223 		td = &tcp_debug[i];
224 		if (tcpcb && td->td_tcb != tcpcb)
225 			continue;
226 		ntime = ntohl(td->td_time);
227 		tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb,
228 		    &td->td_ti, td->td_req);
229 	}
230 done:	if (follow) {
231 		prev_debx = tcp_debx + 1;
232 		if (prev_debx >= TCP_NDEBUG)
233 			prev_debx = 0;
234 		do {
235 			sleep(1);
236 			(void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET);
237 			if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) !=
238 			    sizeof(tcp_debx)) {
239 				perror("trpt: tcp_debx");
240 				exit(3);
241 			}
242 		} while (tcp_debx == prev_debx);
243 		(void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET);
244 		if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) !=
245 		    sizeof(tcp_debug)) {
246 			perror("trpt: tcp_debug");
247 			exit(3);
248 		}
249 		goto again;
250 	}
251 }
252 
253 /*
254  * Tcp debug routines
255  */
256 /*ARGSUSED*/
257 tcp_trace(act, ostate, atp, tp, ti, req)
258 	short act, ostate;
259 	struct tcpcb *atp, *tp;
260 	struct tcpiphdr *ti;
261 	int req;
262 {
263 	tcp_seq seq, ack;
264 	int flags, len, win, timer;
265 
266 	printf("%03ld %s:%s ",(ntime/10) % 1000, tcpstates[ostate],
267 	    tanames[act]);
268 	switch (act) {
269 	case TA_INPUT:
270 	case TA_OUTPUT:
271 	case TA_DROP:
272 		if (aflag) {
273 			printf("(src=%s,%u, ",
274 			    inet_ntoa(ti->ti_src), ntohs(ti->ti_sport));
275 			printf("dst=%s,%u)",
276 			    inet_ntoa(ti->ti_dst), ntohs(ti->ti_dport));
277 		}
278 		seq = ti->ti_seq;
279 		ack = ti->ti_ack;
280 		len = ti->ti_len;
281 		win = ti->ti_win;
282 		if (act == TA_OUTPUT) {
283 			seq = ntohl(seq);
284 			ack = ntohl(ack);
285 			len = ntohs(len);
286 			win = ntohs(win);
287 		}
288 		if (act == TA_OUTPUT)
289 			len -= sizeof(struct tcphdr);
290 		if (len)
291 			printf("[%lx..%lx)", seq, seq + len);
292 		else
293 			printf("%lx", seq);
294 		printf("@%lx", ack);
295 		if (win)
296 			printf("(win=%x)", win);
297 		flags = ti->ti_flags;
298 		if (flags) {
299 			register char *cp = "<";
300 #define	pf(flag, string) { \
301 	if (ti->ti_flags&flag) { \
302 		(void)printf("%s%s", cp, string); \
303 		cp = ","; \
304 	} \
305 }
306 			pf(TH_SYN, "SYN");
307 			pf(TH_ACK, "ACK");
308 			pf(TH_FIN, "FIN");
309 			pf(TH_RST, "RST");
310 			pf(TH_PUSH, "PUSH");
311 			pf(TH_URG, "URG");
312 			printf(">");
313 		}
314 		break;
315 	case TA_USER:
316 		timer = req >> 8;
317 		req &= 0xff;
318 		printf("%s", prurequests[req]);
319 		if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO)
320 			printf("<%s>", tcptimers[timer]);
321 		break;
322 	}
323 	printf(" -> %s", tcpstates[tp->t_state]);
324 	/* print out internal state of tp !?! */
325 	printf("\n");
326 	if (sflag) {
327 		printf("\trcv_nxt %lx rcv_wnd %x snd_una %lx snd_nxt %lx snd_max %lx\n",
328 		    tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt,
329 		    tp->snd_max);
330 		printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %x\n", tp->snd_wl1,
331 		    tp->snd_wl2, tp->snd_wnd);
332 	}
333 	/* print out timers? */
334 	if (tflag) {
335 		register char *cp = "\t";
336 		register int i;
337 
338 		for (i = 0; i < TCPT_NTIMERS; i++) {
339 			if (tp->t_timer[i] == 0)
340 				continue;
341 			printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]);
342 			if (i == TCPT_REXMT)
343 				printf(" (t_rxtshft=%d)", tp->t_rxtshift);
344 			cp = ", ";
345 		}
346 		if (*cp != '\t')
347 			putchar('\n');
348 	}
349 }
350 
351 numeric(c1, c2)
352 	caddr_t *c1, *c2;
353 {
354 	return(*c1 - *c2);
355 }
356 
357 klseek(fd, base, off)
358 	int fd, off;
359 	off_t base;
360 {
361 	off_t lseek();
362 
363 	if (kflag) {	/* get kernel pte */
364 		base &= ~KERNBASE;
365 		base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
366 	}
367 	(void)lseek(fd, base, off);
368 }
369