122014Sdist /* 233663Sbostic * Copyright (c) 1983, 1988 Regents of the University of California. 334939Sbostic * All rights reserved. 434939Sbostic * 534939Sbostic * Redistribution and use in source and binary forms are permitted 634939Sbostic * provided that the above copyright notice and this paragraph are 734939Sbostic * duplicated in all such forms and that any documentation, 834939Sbostic * advertising materials, and other materials related to such 934939Sbostic * distribution and use acknowledge that the software was developed 1034939Sbostic * by the University of California, Berkeley. The name of the 1134939Sbostic * University may not be used to endorse or promote products derived 1234939Sbostic * from this software without specific prior written permission. 1334939Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434939Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534939Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1622014Sdist */ 1722014Sdist 186463Swnj #ifndef lint 1922014Sdist char copyright[] = 2033663Sbostic "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ 2122014Sdist All rights reserved.\n"; 2233663Sbostic #endif /* not lint */ 236463Swnj 2422014Sdist #ifndef lint 25*38432Ssam static char sccsid[] = "@(#)trpt.c 5.9 (Berkeley) 07/09/89"; 2633663Sbostic #endif /* not lint */ 2722014Sdist 2833663Sbostic #include <machine/pte.h> 2933663Sbostic 306463Swnj #include <sys/param.h> 3133663Sbostic #include <sys/vmmac.h> 326463Swnj #include <sys/socket.h> 336463Swnj #include <sys/socketvar.h> 346463Swnj #define PRUREQUESTS 356463Swnj #include <sys/protosw.h> 3633663Sbostic #include <sys/file.h> 379202Ssam 386463Swnj #include <net/route.h> 396463Swnj #include <net/if.h> 409202Ssam 419202Ssam #include <netinet/in.h> 429202Ssam #include <netinet/in_pcb.h> 439202Ssam #include <netinet/in_systm.h> 449202Ssam #include <netinet/ip.h> 459202Ssam #include <netinet/ip_var.h> 469202Ssam #include <netinet/tcp.h> 476463Swnj #define TCPSTATES 489202Ssam #include <netinet/tcp_fsm.h> 499202Ssam #include <netinet/tcp_seq.h> 506463Swnj #define TCPTIMERS 519202Ssam #include <netinet/tcp_timer.h> 529202Ssam #include <netinet/tcp_var.h> 539202Ssam #include <netinet/tcpip.h> 546463Swnj #define TANAMES 559202Ssam #include <netinet/tcp_debug.h> 569202Ssam 5715252Ssam #include <arpa/inet.h> 5815252Ssam 5910272Ssam #include <stdio.h> 606463Swnj #include <errno.h> 616463Swnj #include <nlist.h> 6237984Sbostic #include <paths.h> 636463Swnj 6433663Sbostic struct nlist nl[] = { 6533663Sbostic #define N_TCP_DEBUG 0 666463Swnj { "_tcp_debug" }, 6733663Sbostic #define N_TCP_DEBX 1 686463Swnj { "_tcp_debx" }, 6933663Sbostic #define N_SYSMAP 2 7033663Sbostic { "_Sysmap" }, 7133663Sbostic #define N_SYSSIZE 3 7233663Sbostic { "_Syssize" }, 7333663Sbostic { "" }, 746463Swnj }; 756463Swnj 7635690Sbostic static struct pte *Sysmap; 7735690Sbostic static caddr_t tcp_pcbs[TCP_NDEBUG]; 7835690Sbostic static n_time ntime; 7935690Sbostic static int aflag, kflag, memf, follow, sflag, tflag; 8033663Sbostic 816463Swnj main(argc, argv) 826463Swnj int argc; 836463Swnj char **argv; 846463Swnj { 8533663Sbostic extern char *optarg; 8633663Sbostic extern int optind; 8733663Sbostic int ch, i, jflag, npcbs, numeric(); 8833663Sbostic char *system, *core, *malloc(); 8933663Sbostic off_t lseek(); 906463Swnj 9133663Sbostic jflag = npcbs = 0; 9233663Sbostic while ((ch = getopt(argc, argv, "afjp:st")) != EOF) 9333663Sbostic switch((char)ch) { 9433663Sbostic case 'a': 9533663Sbostic ++aflag; 9633663Sbostic break; 9733663Sbostic case 'f': 9833663Sbostic ++follow; 9933663Sbostic setlinebuf(stdout); 10033663Sbostic break; 10133663Sbostic case 'j': 10233663Sbostic ++jflag; 10333663Sbostic break; 10433663Sbostic case 'p': 10533663Sbostic if (npcbs >= TCP_NDEBUG) { 10633663Sbostic fputs("trpt: too many pcb's specified\n", 10733663Sbostic stderr); 10833663Sbostic exit(1); 10933663Sbostic } 11033663Sbostic (void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]); 11133663Sbostic break; 11233663Sbostic case 's': 11333663Sbostic ++sflag; 11433663Sbostic break; 11533663Sbostic case 't': 11633663Sbostic ++tflag; 11733663Sbostic break; 11833663Sbostic case '?': 11933663Sbostic default: 12037308Sbostic (void)fprintf(stderr, 12137308Sbostic "usage: trpt [-afjst] [-p hex-address] [system [core]]\n"); 12210272Ssam exit(1); 12310272Ssam } 12433663Sbostic argc -= optind; 12533663Sbostic argv += optind; 12633663Sbostic 12737308Sbostic core = _PATH_KMEM; 12810272Ssam if (argc > 0) { 12910272Ssam system = *argv; 13010272Ssam argc--, argv++; 13133663Sbostic if (argc > 0) { 13233663Sbostic core = *argv; 13333663Sbostic argc--, argv++; 13433663Sbostic ++kflag; 13533663Sbostic } 13610272Ssam } 13733663Sbostic else 13837308Sbostic system = _PATH_UNIX; 13933663Sbostic 14033663Sbostic if (nlist(system, nl) < 0 || !nl[0].n_value) { 14110272Ssam fprintf(stderr, "trpt: %s: no namelist\n", system); 1426463Swnj exit(1); 1436463Swnj } 14433663Sbostic if ((memf = open(core, O_RDONLY)) < 0) { 14533663Sbostic perror(core); 14610272Ssam exit(2); 14710272Ssam } 14833663Sbostic if (kflag) { 14933663Sbostic off_t off; 15033663Sbostic 15133663Sbostic Sysmap = (struct pte *) 15233663Sbostic malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 15333663Sbostic if (!Sysmap) { 15433663Sbostic fputs("arp: can't get memory for Sysmap.\n", stderr); 15533663Sbostic exit(1); 15633663Sbostic } 15733663Sbostic off = nl[N_SYSMAP].n_value & ~KERNBASE; 15833663Sbostic (void)lseek(memf, off, L_SET); 15933663Sbostic (void)read(memf, (char *)Sysmap, 16033663Sbostic (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 1616463Swnj } 16233663Sbostic (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 16333663Sbostic if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 16433663Sbostic sizeof(tcp_debx)) { 16533663Sbostic perror("trpt: tcp_debx"); 16610272Ssam exit(3); 16710272Ssam } 16833663Sbostic (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 16933663Sbostic if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 17033663Sbostic sizeof(tcp_debug)) { 17133663Sbostic perror("trpt: tcp_debug"); 17210272Ssam exit(3); 17310272Ssam } 17410425Ssam /* 17510425Ssam * If no control blocks have been specified, figure 17610425Ssam * out how many distinct one we have and summarize 17710425Ssam * them in tcp_pcbs for sorting the trace records 17810425Ssam * below. 17910425Ssam */ 18033663Sbostic if (!npcbs) { 18110425Ssam for (i = 0; i < TCP_NDEBUG; i++) { 18233663Sbostic register struct tcp_debug *td = &tcp_debug[i]; 18310425Ssam register int j; 1848382Ssam 18510425Ssam if (td->td_tcb == 0) 18610425Ssam continue; 18710425Ssam for (j = 0; j < npcbs; j++) 18810425Ssam if (tcp_pcbs[j] == td->td_tcb) 18910425Ssam break; 19010425Ssam if (j >= npcbs) 19110425Ssam tcp_pcbs[npcbs++] = td->td_tcb; 19210425Ssam } 19333663Sbostic if (!npcbs) 19433663Sbostic exit(0); 19510425Ssam } 19633663Sbostic qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric); 19710425Ssam if (jflag) { 19833663Sbostic for (i = 0;;) { 19933663Sbostic printf("%x", (int)tcp_pcbs[i]); 20033663Sbostic if (++i == npcbs) 20133663Sbostic break; 20233663Sbostic fputs(", ", stdout); 20310425Ssam } 20433663Sbostic putchar('\n'); 20510425Ssam } 20633663Sbostic else for (i = 0; i < npcbs; i++) { 20733663Sbostic printf("\n%x:\n", (int)tcp_pcbs[i]); 20810425Ssam dotrace(tcp_pcbs[i]); 20910425Ssam } 21010425Ssam exit(0); 21110425Ssam } 21210425Ssam 21310425Ssam dotrace(tcpcb) 21410425Ssam register caddr_t tcpcb; 21510425Ssam { 21633663Sbostic register struct tcp_debug *td; 21710425Ssam register int i; 21824910Skarels int prev_debx = tcp_debx; 21910425Ssam 22033663Sbostic again: if (--tcp_debx < 0) 22124910Skarels tcp_debx = TCP_NDEBUG - 1; 22224910Skarels for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) { 22310425Ssam td = &tcp_debug[i]; 22410272Ssam if (tcpcb && td->td_tcb != tcpcb) 22510272Ssam continue; 2268382Ssam ntime = ntohl(td->td_time); 2276463Swnj tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb, 2286463Swnj &td->td_ti, td->td_req); 22924910Skarels if (i == tcp_debx) 23024910Skarels goto done; 2316463Swnj } 23224910Skarels for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) { 23310425Ssam td = &tcp_debug[i]; 23410272Ssam if (tcpcb && td->td_tcb != tcpcb) 23510272Ssam continue; 2368382Ssam ntime = ntohl(td->td_time); 2376463Swnj tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb, 2386463Swnj &td->td_ti, td->td_req); 2396463Swnj } 24033663Sbostic done: if (follow) { 24133663Sbostic prev_debx = tcp_debx + 1; 24233663Sbostic if (prev_debx >= TCP_NDEBUG) 24333663Sbostic prev_debx = 0; 24433663Sbostic do { 24533663Sbostic sleep(1); 24633663Sbostic (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 24733663Sbostic if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 24833663Sbostic sizeof(tcp_debx)) { 24933663Sbostic perror("trpt: tcp_debx"); 25033663Sbostic exit(3); 25133663Sbostic } 25233663Sbostic } while (tcp_debx == prev_debx); 25333663Sbostic (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 25433663Sbostic if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 25533663Sbostic sizeof(tcp_debug)) { 25633663Sbostic perror("trpt: tcp_debug"); 25724910Skarels exit(3); 25824910Skarels } 25933663Sbostic goto again; 26024910Skarels } 2616463Swnj } 2626463Swnj 2636463Swnj /* 2646463Swnj * Tcp debug routines 2656463Swnj */ 26633663Sbostic /*ARGSUSED*/ 2676463Swnj tcp_trace(act, ostate, atp, tp, ti, req) 2686463Swnj short act, ostate; 2696463Swnj struct tcpcb *atp, *tp; 2706463Swnj struct tcpiphdr *ti; 2716463Swnj int req; 2726463Swnj { 2736463Swnj tcp_seq seq, ack; 27433663Sbostic int flags, len, win, timer; 2756463Swnj 27633663Sbostic printf("%03ld %s:%s ",(ntime/10) % 1000, tcpstates[ostate], 27733663Sbostic tanames[act]); 2786463Swnj switch (act) { 2796463Swnj case TA_INPUT: 2806463Swnj case TA_OUTPUT: 28114004Shelge case TA_DROP: 282*38432Ssam if (aflag) { 283*38432Ssam printf("(src=%s,%u, ", 284*38432Ssam inet_ntoa(ti->ti_src), ntohs(ti->ti_sport)); 285*38432Ssam printf("dst=%s,%u)", 286*38432Ssam inet_ntoa(ti->ti_dst), ntohs(ti->ti_dport)); 287*38432Ssam } 2886463Swnj seq = ti->ti_seq; 2896463Swnj ack = ti->ti_ack; 2906463Swnj len = ti->ti_len; 2916463Swnj win = ti->ti_win; 2926463Swnj if (act == TA_OUTPUT) { 2936463Swnj seq = ntohl(seq); 2946463Swnj ack = ntohl(ack); 2956463Swnj len = ntohs(len); 2966463Swnj win = ntohs(win); 2976463Swnj } 2986463Swnj if (act == TA_OUTPUT) 29933663Sbostic len -= sizeof(struct tcphdr); 3006463Swnj if (len) 30133663Sbostic printf("[%lx..%lx)", seq, seq + len); 3026463Swnj else 30333663Sbostic printf("%lx", seq); 30433663Sbostic printf("@%lx", ack); 3056463Swnj if (win) 30614282Shelge printf("(win=%x)", win); 3076463Swnj flags = ti->ti_flags; 3086463Swnj if (flags) { 30933663Sbostic register char *cp = "<"; 31033663Sbostic #define pf(flag) { \ 31133663Sbostic if (ti->ti_flags&flag) \ 31233663Sbostic printf("%s%s", cp, "f"); \ 31333663Sbostic cp = ","; \ 31433663Sbostic } 31533663Sbostic pf(TH_SYN); 31633663Sbostic pf(TH_ACK); 31733663Sbostic pf(TH_FIN); 31833663Sbostic pf(TH_RST); 31933663Sbostic pf(TH_PUSH); 32033663Sbostic pf(TH_URG); 3216463Swnj printf(">"); 3226463Swnj } 3236463Swnj break; 3246463Swnj case TA_USER: 3258382Ssam timer = req >> 8; 3268382Ssam req &= 0xff; 3278382Ssam printf("%s", prurequests[req]); 3288382Ssam if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO) 3298382Ssam printf("<%s>", tcptimers[timer]); 3306463Swnj break; 3316463Swnj } 3326463Swnj printf(" -> %s", tcpstates[tp->t_state]); 3336463Swnj /* print out internal state of tp !?! */ 3346463Swnj printf("\n"); 3356463Swnj if (sflag) { 33633663Sbostic printf("\trcv_nxt %lx rcv_wnd %x snd_una %lx snd_nxt %lx snd_max %lx\n", 33710272Ssam tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt, 33810272Ssam tp->snd_max); 33933663Sbostic printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %x\n", tp->snd_wl1, 34010272Ssam tp->snd_wl2, tp->snd_wnd); 3416463Swnj } 34210425Ssam /* print out timers? */ 34310425Ssam if (tflag) { 34433663Sbostic register char *cp = "\t"; 34510425Ssam register int i; 34610425Ssam 34710425Ssam for (i = 0; i < TCPT_NTIMERS; i++) { 34810425Ssam if (tp->t_timer[i] == 0) 34910425Ssam continue; 35010425Ssam printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]); 35110425Ssam if (i == TCPT_REXMT) 35210425Ssam printf(" (t_rxtshft=%d)", tp->t_rxtshift); 35310425Ssam cp = ", "; 35410425Ssam } 35510425Ssam if (*cp != '\t') 35610425Ssam putchar('\n'); 35710425Ssam } 3586463Swnj } 3596463Swnj 36033663Sbostic numeric(c1, c2) 36133663Sbostic caddr_t *c1, *c2; 3626463Swnj { 36333663Sbostic return(*c1 - *c2); 3646463Swnj } 36510425Ssam 36633663Sbostic klseek(fd, base, off) 36733663Sbostic int fd, off; 36833663Sbostic off_t base; 36910425Ssam { 37033663Sbostic off_t lseek(); 37133663Sbostic 37233663Sbostic if (kflag) { /* get kernel pte */ 37333663Sbostic base &= ~KERNBASE; 37433663Sbostic base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET); 37533663Sbostic } 37633663Sbostic (void)lseek(fd, base, off); 37710425Ssam } 378