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*35690Sbostic static char sccsid[] = "@(#)trpt.c 5.6 (Berkeley) 09/22/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 75*35690Sbostic static struct pte *Sysmap; 76*35690Sbostic static caddr_t tcp_pcbs[TCP_NDEBUG]; 77*35690Sbostic static n_time ntime; 78*35690Sbostic static int aflag, kflag, memf, follow, sflag, tflag; 7933663Sbostic 806463Swnj main(argc, argv) 816463Swnj int argc; 826463Swnj char **argv; 836463Swnj { 8433663Sbostic extern char *optarg; 8533663Sbostic extern int optind; 8633663Sbostic int ch, i, jflag, npcbs, numeric(); 8733663Sbostic char *system, *core, *malloc(); 8833663Sbostic off_t lseek(); 896463Swnj 9033663Sbostic jflag = npcbs = 0; 9133663Sbostic while ((ch = getopt(argc, argv, "afjp:st")) != EOF) 9233663Sbostic switch((char)ch) { 9333663Sbostic case 'a': 9433663Sbostic ++aflag; 9533663Sbostic break; 9633663Sbostic case 'f': 9733663Sbostic ++follow; 9833663Sbostic setlinebuf(stdout); 9933663Sbostic break; 10033663Sbostic case 'j': 10133663Sbostic ++jflag; 10233663Sbostic break; 10333663Sbostic case 'p': 10433663Sbostic if (npcbs >= TCP_NDEBUG) { 10533663Sbostic fputs("trpt: too many pcb's specified\n", 10633663Sbostic stderr); 10733663Sbostic exit(1); 10833663Sbostic } 10933663Sbostic (void)sscanf(optarg, "%x", (int *)&tcp_pcbs[npcbs++]); 11033663Sbostic break; 11133663Sbostic case 's': 11233663Sbostic ++sflag; 11333663Sbostic break; 11433663Sbostic case 't': 11533663Sbostic ++tflag; 11633663Sbostic break; 11733663Sbostic case '?': 11833663Sbostic default: 11933663Sbostic fputs("usage: trpt [-afjst] [-p hex-address] [system [core]]\n", stderr); 12010272Ssam exit(1); 12110272Ssam } 12233663Sbostic argc -= optind; 12333663Sbostic argv += optind; 12433663Sbostic 12533663Sbostic core = "/dev/kmem"; 12610272Ssam if (argc > 0) { 12710272Ssam system = *argv; 12810272Ssam argc--, argv++; 12933663Sbostic if (argc > 0) { 13033663Sbostic core = *argv; 13133663Sbostic argc--, argv++; 13233663Sbostic ++kflag; 13333663Sbostic } 13410272Ssam } 13533663Sbostic else 13633663Sbostic system = "/vmunix"; 13733663Sbostic 13833663Sbostic if (nlist(system, nl) < 0 || !nl[0].n_value) { 13910272Ssam fprintf(stderr, "trpt: %s: no namelist\n", system); 1406463Swnj exit(1); 1416463Swnj } 14233663Sbostic if ((memf = open(core, O_RDONLY)) < 0) { 14333663Sbostic perror(core); 14410272Ssam exit(2); 14510272Ssam } 14633663Sbostic if (kflag) { 14733663Sbostic off_t off; 14833663Sbostic 14933663Sbostic Sysmap = (struct pte *) 15033663Sbostic malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 15133663Sbostic if (!Sysmap) { 15233663Sbostic fputs("arp: can't get memory for Sysmap.\n", stderr); 15333663Sbostic exit(1); 15433663Sbostic } 15533663Sbostic off = nl[N_SYSMAP].n_value & ~KERNBASE; 15633663Sbostic (void)lseek(memf, off, L_SET); 15733663Sbostic (void)read(memf, (char *)Sysmap, 15833663Sbostic (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 1596463Swnj } 16033663Sbostic (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 16133663Sbostic if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 16233663Sbostic sizeof(tcp_debx)) { 16333663Sbostic perror("trpt: tcp_debx"); 16410272Ssam exit(3); 16510272Ssam } 16633663Sbostic (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 16733663Sbostic if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 16833663Sbostic sizeof(tcp_debug)) { 16933663Sbostic perror("trpt: tcp_debug"); 17010272Ssam exit(3); 17110272Ssam } 17210425Ssam /* 17310425Ssam * If no control blocks have been specified, figure 17410425Ssam * out how many distinct one we have and summarize 17510425Ssam * them in tcp_pcbs for sorting the trace records 17610425Ssam * below. 17710425Ssam */ 17833663Sbostic if (!npcbs) { 17910425Ssam for (i = 0; i < TCP_NDEBUG; i++) { 18033663Sbostic register struct tcp_debug *td = &tcp_debug[i]; 18110425Ssam register int j; 1828382Ssam 18310425Ssam if (td->td_tcb == 0) 18410425Ssam continue; 18510425Ssam for (j = 0; j < npcbs; j++) 18610425Ssam if (tcp_pcbs[j] == td->td_tcb) 18710425Ssam break; 18810425Ssam if (j >= npcbs) 18910425Ssam tcp_pcbs[npcbs++] = td->td_tcb; 19010425Ssam } 19133663Sbostic if (!npcbs) 19233663Sbostic exit(0); 19310425Ssam } 19433663Sbostic qsort(tcp_pcbs, npcbs, sizeof(caddr_t), numeric); 19510425Ssam if (jflag) { 19633663Sbostic for (i = 0;;) { 19733663Sbostic printf("%x", (int)tcp_pcbs[i]); 19833663Sbostic if (++i == npcbs) 19933663Sbostic break; 20033663Sbostic fputs(", ", stdout); 20110425Ssam } 20233663Sbostic putchar('\n'); 20310425Ssam } 20433663Sbostic else for (i = 0; i < npcbs; i++) { 20533663Sbostic printf("\n%x:\n", (int)tcp_pcbs[i]); 20610425Ssam dotrace(tcp_pcbs[i]); 20710425Ssam } 20810425Ssam exit(0); 20910425Ssam } 21010425Ssam 21110425Ssam dotrace(tcpcb) 21210425Ssam register caddr_t tcpcb; 21310425Ssam { 21433663Sbostic register struct tcp_debug *td; 21510425Ssam register int i; 21624910Skarels int prev_debx = tcp_debx; 21710425Ssam 21833663Sbostic again: if (--tcp_debx < 0) 21924910Skarels tcp_debx = TCP_NDEBUG - 1; 22024910Skarels for (i = prev_debx % TCP_NDEBUG; i < TCP_NDEBUG; i++) { 22110425Ssam td = &tcp_debug[i]; 22210272Ssam if (tcpcb && td->td_tcb != tcpcb) 22310272Ssam continue; 2248382Ssam ntime = ntohl(td->td_time); 2256463Swnj tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb, 2266463Swnj &td->td_ti, td->td_req); 22724910Skarels if (i == tcp_debx) 22824910Skarels goto done; 2296463Swnj } 23024910Skarels for (i = 0; i <= tcp_debx % TCP_NDEBUG; i++) { 23110425Ssam td = &tcp_debug[i]; 23210272Ssam if (tcpcb && td->td_tcb != tcpcb) 23310272Ssam continue; 2348382Ssam ntime = ntohl(td->td_time); 2356463Swnj tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb, 2366463Swnj &td->td_ti, td->td_req); 2376463Swnj } 23833663Sbostic done: if (follow) { 23933663Sbostic prev_debx = tcp_debx + 1; 24033663Sbostic if (prev_debx >= TCP_NDEBUG) 24133663Sbostic prev_debx = 0; 24233663Sbostic do { 24333663Sbostic sleep(1); 24433663Sbostic (void)klseek(memf, (off_t)nl[N_TCP_DEBX].n_value, L_SET); 24533663Sbostic if (read(memf, (char *)&tcp_debx, sizeof(tcp_debx)) != 24633663Sbostic sizeof(tcp_debx)) { 24733663Sbostic perror("trpt: tcp_debx"); 24833663Sbostic exit(3); 24933663Sbostic } 25033663Sbostic } while (tcp_debx == prev_debx); 25133663Sbostic (void)klseek(memf, (off_t)nl[N_TCP_DEBUG].n_value, L_SET); 25233663Sbostic if (read(memf, (char *)tcp_debug, sizeof(tcp_debug)) != 25333663Sbostic sizeof(tcp_debug)) { 25433663Sbostic perror("trpt: tcp_debug"); 25524910Skarels exit(3); 25624910Skarels } 25733663Sbostic goto again; 25824910Skarels } 2596463Swnj } 2606463Swnj 2616463Swnj /* 2626463Swnj * Tcp debug routines 2636463Swnj */ 26433663Sbostic /*ARGSUSED*/ 2656463Swnj tcp_trace(act, ostate, atp, tp, ti, req) 2666463Swnj short act, ostate; 2676463Swnj struct tcpcb *atp, *tp; 2686463Swnj struct tcpiphdr *ti; 2696463Swnj int req; 2706463Swnj { 2716463Swnj tcp_seq seq, ack; 27233663Sbostic int flags, len, win, timer; 2736463Swnj 27433663Sbostic printf("%03ld %s:%s ",(ntime/10) % 1000, tcpstates[ostate], 27533663Sbostic tanames[act]); 2766463Swnj switch (act) { 2776463Swnj case TA_INPUT: 2786463Swnj case TA_OUTPUT: 27914004Shelge case TA_DROP: 28033663Sbostic if (aflag) 28133663Sbostic printf("(src=%s,%u, dst=%s,%u)", inet_ntoa(ti->ti_src), 28233663Sbostic ntohs(ti->ti_sport), inet_ntoa(ti->ti_dst), 28333663Sbostic ntohs(ti->ti_dport)); 2846463Swnj seq = ti->ti_seq; 2856463Swnj ack = ti->ti_ack; 2866463Swnj len = ti->ti_len; 2876463Swnj win = ti->ti_win; 2886463Swnj if (act == TA_OUTPUT) { 2896463Swnj seq = ntohl(seq); 2906463Swnj ack = ntohl(ack); 2916463Swnj len = ntohs(len); 2926463Swnj win = ntohs(win); 2936463Swnj } 2946463Swnj if (act == TA_OUTPUT) 29533663Sbostic len -= sizeof(struct tcphdr); 2966463Swnj if (len) 29733663Sbostic printf("[%lx..%lx)", seq, seq + len); 2986463Swnj else 29933663Sbostic printf("%lx", seq); 30033663Sbostic printf("@%lx", ack); 3016463Swnj if (win) 30214282Shelge printf("(win=%x)", win); 3036463Swnj flags = ti->ti_flags; 3046463Swnj if (flags) { 30533663Sbostic register char *cp = "<"; 30633663Sbostic #define pf(flag) { \ 30733663Sbostic if (ti->ti_flags&flag) \ 30833663Sbostic printf("%s%s", cp, "f"); \ 30933663Sbostic cp = ","; \ 31033663Sbostic } 31133663Sbostic pf(TH_SYN); 31233663Sbostic pf(TH_ACK); 31333663Sbostic pf(TH_FIN); 31433663Sbostic pf(TH_RST); 31533663Sbostic pf(TH_PUSH); 31633663Sbostic pf(TH_URG); 3176463Swnj printf(">"); 3186463Swnj } 3196463Swnj break; 3206463Swnj case TA_USER: 3218382Ssam timer = req >> 8; 3228382Ssam req &= 0xff; 3238382Ssam printf("%s", prurequests[req]); 3248382Ssam if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO) 3258382Ssam printf("<%s>", tcptimers[timer]); 3266463Swnj break; 3276463Swnj } 3286463Swnj printf(" -> %s", tcpstates[tp->t_state]); 3296463Swnj /* print out internal state of tp !?! */ 3306463Swnj printf("\n"); 3316463Swnj if (sflag) { 33233663Sbostic printf("\trcv_nxt %lx rcv_wnd %x snd_una %lx snd_nxt %lx snd_max %lx\n", 33310272Ssam tp->rcv_nxt, tp->rcv_wnd, tp->snd_una, tp->snd_nxt, 33410272Ssam tp->snd_max); 33533663Sbostic printf("\tsnd_wl1 %lx snd_wl2 %lx snd_wnd %x\n", tp->snd_wl1, 33610272Ssam tp->snd_wl2, tp->snd_wnd); 3376463Swnj } 33810425Ssam /* print out timers? */ 33910425Ssam if (tflag) { 34033663Sbostic register char *cp = "\t"; 34110425Ssam register int i; 34210425Ssam 34310425Ssam for (i = 0; i < TCPT_NTIMERS; i++) { 34410425Ssam if (tp->t_timer[i] == 0) 34510425Ssam continue; 34610425Ssam printf("%s%s=%d", cp, tcptimers[i], tp->t_timer[i]); 34710425Ssam if (i == TCPT_REXMT) 34810425Ssam printf(" (t_rxtshft=%d)", tp->t_rxtshift); 34910425Ssam cp = ", "; 35010425Ssam } 35110425Ssam if (*cp != '\t') 35210425Ssam putchar('\n'); 35310425Ssam } 3546463Swnj } 3556463Swnj 35633663Sbostic numeric(c1, c2) 35733663Sbostic caddr_t *c1, *c2; 3586463Swnj { 35933663Sbostic return(*c1 - *c2); 3606463Swnj } 36110425Ssam 36233663Sbostic klseek(fd, base, off) 36333663Sbostic int fd, off; 36433663Sbostic off_t base; 36510425Ssam { 36633663Sbostic off_t lseek(); 36733663Sbostic 36833663Sbostic if (kflag) { /* get kernel pte */ 36933663Sbostic base &= ~KERNBASE; 37033663Sbostic base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET); 37133663Sbostic } 37233663Sbostic (void)lseek(fd, base, off); 37310425Ssam } 374