122014Sdist /* 233663Sbostic * Copyright (c) 1983, 1988 Regents of the University of California. 3*34939Sbostic * All rights reserved. 4*34939Sbostic * 5*34939Sbostic * Redistribution and use in source and binary forms are permitted 6*34939Sbostic * provided that the above copyright notice and this paragraph are 7*34939Sbostic * duplicated in all such forms and that any documentation, 8*34939Sbostic * advertising materials, and other materials related to such 9*34939Sbostic * distribution and use acknowledge that the software was developed 10*34939Sbostic * by the University of California, Berkeley. The name of the 11*34939Sbostic * University may not be used to endorse or promote products derived 12*34939Sbostic * from this software without specific prior written permission. 13*34939Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34939Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34939Sbostic * 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*34939Sbostic static char sccsid[] = "@(#)trpt.c 5.5 (Berkeley) 07/01/88"; 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> 626463Swnj 6333663Sbostic struct nlist nl[] = { 6433663Sbostic #define N_TCP_DEBUG 0 656463Swnj { "_tcp_debug" }, 6633663Sbostic #define N_TCP_DEBX 1 676463Swnj { "_tcp_debx" }, 6833663Sbostic #define N_SYSMAP 2 6933663Sbostic { "_Sysmap" }, 7033663Sbostic #define N_SYSSIZE 3 7133663Sbostic { "_Syssize" }, 7233663Sbostic { "" }, 736463Swnj }; 746463Swnj 7533663Sbostic static struct pte *Sysmap; 7633663Sbostic static struct tcp_debug tcp_debug[TCP_NDEBUG]; 7733663Sbostic static caddr_t tcp_pcbs[TCP_NDEBUG]; 7833663Sbostic static n_time ntime; 7933663Sbostic static int aflag, kflag, memf, follow, sflag, tcp_debx, 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: 12033663Sbostic fputs("usage: trpt [-afjst] [-p hex-address] [system [core]]\n", stderr); 12110272Ssam exit(1); 12210272Ssam } 12333663Sbostic argc -= optind; 12433663Sbostic argv += optind; 12533663Sbostic 12633663Sbostic core = "/dev/kmem"; 12710272Ssam if (argc > 0) { 12810272Ssam system = *argv; 12910272Ssam argc--, argv++; 13033663Sbostic if (argc > 0) { 13133663Sbostic core = *argv; 13233663Sbostic argc--, argv++; 13333663Sbostic ++kflag; 13433663Sbostic } 13510272Ssam } 13633663Sbostic else 13733663Sbostic system = "/vmunix"; 13833663Sbostic 13933663Sbostic if (nlist(system, nl) < 0 || !nl[0].n_value) { 14010272Ssam fprintf(stderr, "trpt: %s: no namelist\n", system); 1416463Swnj exit(1); 1426463Swnj } 14333663Sbostic if ((memf = open(core, O_RDONLY)) < 0) { 14433663Sbostic perror(core); 14510272Ssam exit(2); 14610272Ssam } 14733663Sbostic if (kflag) { 14833663Sbostic off_t off; 14933663Sbostic 15033663Sbostic Sysmap = (struct pte *) 15133663Sbostic malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 15233663Sbostic if (!Sysmap) { 15333663Sbostic fputs("arp: can't get memory for Sysmap.\n", stderr); 15433663Sbostic exit(1); 15533663Sbostic } 15633663Sbostic off = nl[N_SYSMAP].n_value & ~KERNBASE; 15733663Sbostic (void)lseek(memf, off, L_SET); 15833663Sbostic (void)read(memf, (char *)Sysmap, 15933663Sbostic (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 1606463Swnj } 16133663Sbostic (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 16233663Sbostic if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 16333663Sbostic sizeof(tcp_debx)) { 16433663Sbostic perror("trpt: tcp_debx"); 16510272Ssam exit(3); 16610272Ssam } 16733663Sbostic (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 16833663Sbostic if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 16933663Sbostic sizeof(tcp_debug)) { 17033663Sbostic perror("trpt: tcp_debug"); 17110272Ssam exit(3); 17210272Ssam } 17310425Ssam /* 17410425Ssam * If no control blocks have been specified, figure 17510425Ssam * out how many distinct one we have and summarize 17610425Ssam * them in tcp_pcbs for sorting the trace records 17710425Ssam * below. 17810425Ssam */ 17933663Sbostic if (!npcbs) { 18010425Ssam for (i = 0; i < TCP_NDEBUG; i++) { 18133663Sbostic register struct tcp_debug *td = &tcp_debug[i]; 18210425Ssam register int j; 1838382Ssam 18410425Ssam if (td->td_tcb == 0) 18510425Ssam continue; 18610425Ssam for (j = 0; j < npcbs; j++) 18710425Ssam if (tcp_pcbs[j] == td->td_tcb) 18810425Ssam break; 18910425Ssam if (j >= npcbs) 19010425Ssam tcp_pcbs[npcbs++] = td->td_tcb; 19110425Ssam } 19233663Sbostic if (!npcbs) 19333663Sbostic exit(0); 19410425Ssam } 19533663Sbostic qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric); 19610425Ssam if (jflag) { 19733663Sbostic for (i = 0;;) { 19833663Sbostic printf("%x", (int)tcp_pcbs[i]); 19933663Sbostic if (++i == npcbs) 20033663Sbostic break; 20133663Sbostic fputs(", ", stdout); 20210425Ssam } 20333663Sbostic putchar('\n'); 20410425Ssam } 20533663Sbostic else for (i = 0; i < npcbs; i++) { 20633663Sbostic printf("\n%x:\n", (int)tcp_pcbs[i]); 20710425Ssam dotrace(tcp_pcbs[i]); 20810425Ssam } 20910425Ssam exit(0); 21010425Ssam } 21110425Ssam 21210425Ssam dotrace(tcpcb) 21310425Ssam register caddr_t tcpcb; 21410425Ssam { 21533663Sbostic register struct tcp_debug *td; 21610425Ssam register int i; 21724910Skarels int prev_debx = tcp_debx; 21810425Ssam 21933663Sbostic again: if (--tcp_debx < 0) 22024910Skarels tcp_debx = TCP_NDEBUG - 1; 22124910Skarels for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) { 22210425Ssam td = &tcp_debug[i]; 22310272Ssam if (tcpcb && td->td_tcb != tcpcb) 22410272Ssam continue; 2258382Ssam ntime = ntohl(td->td_time); 2266463Swnj tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb, 2276463Swnj &td->td_ti, td->td_req); 22824910Skarels if (i == tcp_debx) 22924910Skarels goto done; 2306463Swnj } 23124910Skarels for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) { 23210425Ssam td = &tcp_debug[i]; 23310272Ssam if (tcpcb && td->td_tcb != tcpcb) 23410272Ssam continue; 2358382Ssam ntime = ntohl(td->td_time); 2366463Swnj tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb, 2376463Swnj &td->td_ti, td->td_req); 2386463Swnj } 23933663Sbostic done: if (follow) { 24033663Sbostic prev_debx = tcp_debx + 1; 24133663Sbostic if (prev_debx >= TCP_NDEBUG) 24233663Sbostic prev_debx = 0; 24333663Sbostic do { 24433663Sbostic sleep(1); 24533663Sbostic (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 24633663Sbostic if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 24733663Sbostic sizeof(tcp_debx)) { 24833663Sbostic perror("trpt: tcp_debx"); 24933663Sbostic exit(3); 25033663Sbostic } 25133663Sbostic } while (tcp_debx == prev_debx); 25233663Sbostic (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 25333663Sbostic if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 25433663Sbostic sizeof(tcp_debug)) { 25533663Sbostic perror("trpt: tcp_debug"); 25624910Skarels exit(3); 25724910Skarels } 25833663Sbostic goto again; 25924910Skarels } 2606463Swnj } 2616463Swnj 2626463Swnj /* 2636463Swnj * Tcp debug routines 2646463Swnj */ 26533663Sbostic /*ARGSUSED*/ 2666463Swnj tcp_trace(act, ostate, atp, tp, ti, req) 2676463Swnj short act, ostate; 2686463Swnj struct tcpcb *atp, *tp; 2696463Swnj struct tcpiphdr *ti; 2706463Swnj int req; 2716463Swnj { 2726463Swnj tcp_seq seq, ack; 27333663Sbostic int flags, len, win, timer; 2746463Swnj 27533663Sbostic printf("%03ld %s:%s ",(ntime/10) % 1000, tcpstates[ostate], 27633663Sbostic tanames[act]); 2776463Swnj switch (act) { 2786463Swnj case TA_INPUT: 2796463Swnj case TA_OUTPUT: 28014004Shelge case TA_DROP: 28133663Sbostic if (aflag) 28233663Sbostic printf("(src=%s,%u, dst=%s,%u)", inet_ntoa(ti->ti_src), 28333663Sbostic ntohs(ti->ti_sport), inet_ntoa(ti->ti_dst), 28433663Sbostic ntohs(ti->ti_dport)); 2856463Swnj seq = ti->ti_seq; 2866463Swnj ack = ti->ti_ack; 2876463Swnj len = ti->ti_len; 2886463Swnj win = ti->ti_win; 2896463Swnj if (act == TA_OUTPUT) { 2906463Swnj seq = ntohl(seq); 2916463Swnj ack = ntohl(ack); 2926463Swnj len = ntohs(len); 2936463Swnj win = ntohs(win); 2946463Swnj } 2956463Swnj if (act == TA_OUTPUT) 29633663Sbostic len -= sizeof(struct tcphdr); 2976463Swnj if (len) 29833663Sbostic printf("[%lx..%lx)", seq, seq + len); 2996463Swnj else 30033663Sbostic printf("%lx", seq); 30133663Sbostic printf("@%lx", ack); 3026463Swnj if (win) 30314282Shelge printf("(win=%x)", win); 3046463Swnj flags = ti->ti_flags; 3056463Swnj if (flags) { 30633663Sbostic register char *cp = "<"; 30733663Sbostic #define pf(flag) { \ 30833663Sbostic if (ti->ti_flags&flag) \ 30933663Sbostic printf("%s%s", cp, "f"); \ 31033663Sbostic cp = ","; \ 31133663Sbostic } 31233663Sbostic pf(TH_SYN); 31333663Sbostic pf(TH_ACK); 31433663Sbostic pf(TH_FIN); 31533663Sbostic pf(TH_RST); 31633663Sbostic pf(TH_PUSH); 31733663Sbostic pf(TH_URG); 3186463Swnj printf(">"); 3196463Swnj } 3206463Swnj break; 3216463Swnj case TA_USER: 3228382Ssam timer = req >> 8; 3238382Ssam req &= 0xff; 3248382Ssam printf("%s", prurequests[req]); 3258382Ssam if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO) 3268382Ssam printf("<%s>", tcptimers[timer]); 3276463Swnj break; 3286463Swnj } 3296463Swnj printf(" -> %s", tcpstates[tp->t_state]); 3306463Swnj /* print out internal state of tp !?! */ 3316463Swnj printf("\n"); 3326463Swnj if (sflag) { 33333663Sbostic printf("\trcv_nxt %lx rcv_wnd %x snd_una %lx snd_nxt %lx snd_max %lx\n", 33410272Ssam tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt, 33510272Ssam tp->snd_max); 33633663Sbostic printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %x\n", tp->snd_wl1, 33710272Ssam tp->snd_wl2, tp->snd_wnd); 3386463Swnj } 33910425Ssam /* print out timers? */ 34010425Ssam if (tflag) { 34133663Sbostic register char *cp = "\t"; 34210425Ssam register int i; 34310425Ssam 34410425Ssam for (i = 0; i < TCPT_NTIMERS; i++) { 34510425Ssam if (tp->t_timer[i] == 0) 34610425Ssam continue; 34710425Ssam printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]); 34810425Ssam if (i == TCPT_REXMT) 34910425Ssam printf(" (t_rxtshft=%d)", tp->t_rxtshift); 35010425Ssam cp = ", "; 35110425Ssam } 35210425Ssam if (*cp != '\t') 35310425Ssam putchar('\n'); 35410425Ssam } 3556463Swnj } 3566463Swnj 35733663Sbostic numeric(c1, c2) 35833663Sbostic caddr_t *c1, *c2; 3596463Swnj { 36033663Sbostic return(*c1 - *c2); 3616463Swnj } 36210425Ssam 36333663Sbostic klseek(fd, base, off) 36433663Sbostic int fd, off; 36533663Sbostic off_t base; 36610425Ssam { 36733663Sbostic off_t lseek(); 36833663Sbostic 36933663Sbostic if (kflag) { /* get kernel pte */ 37033663Sbostic base &= ~KERNBASE; 37133663Sbostic base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET); 37233663Sbostic } 37333663Sbostic (void)lseek(fd, base, off); 37410425Ssam } 375