chris@umcp-cs.UUCP (Chris Torek) (05/28/85)
If you decide to do some TCP hacking on your 4.2BSD system (considering that 4.2 needs a lot of TCP hacking) this program can be invaluable. (It's pointed out a retransmit timing bug, for example; look closely at tcp_output.c ...) Sorry, no manual page; but it's only useful for tcp hackers, who ought to be able to figure out how to use it anyway. Without further ado, here it is: : Run this shell script with "sh" not "csh" PATH=:/bin:/usr/bin:/usr/ucb export PATH all=FALSE if [ $1x = -ax ]; then all=TRUE fi /bin/echo 'Extracting tcpdbug.c' sed 's/^X//' <<'//go.sysin dd *' >tcpdbug.c #ifndef lint static char rcsid[] = "$Header$"; #endif X/* * tcpdbug * * snapshot tcpcbs */ #include <stdio.h> #include <sys/types.h> #include <sys/time.h> #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/protosw.h> #include <net/route.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/in_pcb.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_var.h> #include <netinet/ip_icmp.h> #include <netinet/tcp.h> #define TCPSTATES #include <netinet/tcp_fsm.h> #include <netinet/tcp_seq.h> #include <netinet/tcp_timer.h> #include <netinet/tcp_var.h> #include <netinet/tcpip.h> #include <nlist.h> #include <netdb.h> struct nlist nl[] = { {"_tcb"}, #define X_TCB 0 {0} }; int kmem; struct inpcb tcb, inpcb; struct tcpcb tcpcb; int AFlag, FFlag, LFlag; struct in_addr FAddr; u_short FPort; ReadKernelItem (kaddr, caddr, size) caddr_t kaddr, caddr; int size; { (void) lseek (kmem, (long) kaddr, 0); if (read (kmem, caddr, size) != size) { perror ("kmem read"); exit (1); } } OpenKmem () { if ((kmem = open ("/dev/kmem", 0)) < 0) { perror ("/dev/kmem"); exit (1); } } GetNames () { nlist ("/vmunix", nl); if (nl[0].n_type == 0) { fprintf (stderr, "/vmunix: no namelist\n"); exit (1); } } LoopThrough () { register struct inpcb *inp, *endp; register struct tcpcb *tp; endp = (struct inpcb *) nl[X_TCB].n_value; ReadKernelItem ((caddr_t) endp, (caddr_t) &tcb, sizeof tcb); for (inp = tcb.inp_next; inp != endp; inp = inpcb.inp_next) { ReadKernelItem ((caddr_t) inp, (caddr_t) &inpcb, sizeof inpcb); tp = (struct tcpcb *) inpcb.inp_ppcb; if (tp == 0) continue; ReadKernelItem ((caddr_t) tp, (caddr_t) &tcpcb, sizeof tcpcb); DumpTCP (tp, &tcpcb); } } DumpTCP (ktp, tp) register struct tcpcb *ktp, *tp; { #define flag(x) ((x) ? "true" : "false") struct timeval tv; struct timezone tz; if (FFlag) { /* ignore mismatches */ if (inpcb.inp_faddr.s_addr != FAddr.s_addr) return; if (FPort && inpcb.inp_fport != FPort) return; } else { if (tp -> t_state == TCPS_LISTEN && !AFlag) return; /* ignore LISTENers */ } (void) gettimeofday (&tv, &tz); printf ("time = %d.%03d\n", tv.tv_sec, tv.tv_usec); printf ("\ tcpcb:\n\ \tlocal addr = %d.%d.%d.%d.%d\tforeign addr = %d.%d.%d.%d.%d\n\ \taddr = 0x%x\tstate = %s\n\ \ttimers: rexmt = %d, persist = %d, keep = %d, 2msl = %d\n\ \trxtshift = %d\tmaxseg = %d\tforce %s\n\ \tflags: ack now %s, del ack %s, don't keep %s, no opt %s\n\ \tsend seq: unack = 0x%x, next = 0x%x, urg = 0x%x,\n\ \t\twl1 = 0x%x, wl2 = 0x%x,\n\ \t\tiss= 0x%x, window = 0x%x\n\ \trecv seq: window = 0x%x, next = 0x%x, urg = 0x%x, irs = 0x%x\n\ \tadvertised window = 0x%x, highest seq sent = 0x%x\n\ \tidle = %d, rtt = %d, rttseq = 0x%x, srtt = %12.6f\n\ \toobflag %s, iobc = 0x%x\n\n", #define xpand(x) (x).S_un.S_un_b.s_b1, (x).S_un.S_un_b.s_b2, \ (x).S_un.S_un_b.s_b3, (x).S_un.S_un_b.s_b4 xpand (inpcb.inp_laddr), ntohs (inpcb.inp_lport), xpand (inpcb.inp_faddr), ntohs (inpcb.inp_fport), #undef xpand ktp, tcpstates[tp -> t_state], tp -> t_timer[TCPT_REXMT], tp -> t_timer[TCPT_PERSIST], tp -> t_timer[TCPT_KEEP], tp -> t_timer[TCPT_2MSL], tp -> t_rxtshift, tp -> t_maxseg, flag (tp -> t_force), flag (tp -> t_flags & TF_ACKNOW), flag (tp -> t_flags & TF_DELACK), flag (tp -> t_flags & TF_DONTKEEP), flag (tp -> t_flags & TF_NOOPT), tp -> snd_una, tp -> snd_nxt, tp -> snd_up, tp -> snd_wl1, tp -> snd_wl2, tp -> iss, tp -> snd_wnd, tp -> rcv_wnd, tp -> rcv_nxt, tp -> rcv_up, tp -> irs, tp -> rcv_adv, tp -> snd_max, tp -> t_idle, tp -> t_rtt, tp -> t_rtseq, tp -> t_srtt, flag (tp -> t_oobflags), tp -> t_iobc & 0xff); } GetAddr (s) register char *s; { register char *dotp; register struct hostent *hp; char *rindex (); dotp = rindex (s, '.'); if (!dotp) { fprintf (stderr, "%s: bad address format (should be host.port)\n", s); exit (1); } *dotp++ = 0; hp = gethostbyname (s); if (hp == 0) { fprintf (stderr, "%s: unknown host\n", s); exit (1); } FAddr.s_addr = *(n_long *) hp -> h_addr; FPort = htons (atoi (dotp)); } Options (argc, argv) register int argc; register char **argv; { register char *s; argc--, argv++; while (--argc >= 0) { s = *argv++; if (*s++ != '-') return; switch (*s) { case 'a': AFlag++; break; case 'f': if (*++s == 0) { if (--argc >= 0) s = *argv++; else return; } FFlag++; GetAddr (s); break; case 'l': LFlag++; break; } } } main (argc, argv) char **argv; { Options (argc, argv); if (argc > 1 && strcmp (argv[1], "-a", 0) == 0) AFlag++; OpenKmem (); GetNames (); if (LFlag) { for (;;) { LoopThrough (); fflush (stdout); nap (500); } } else LoopThrough (); exit (0); } nap (ms) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = ms * 1000; (void) select (0, (int *) 0, (int *) 0, (int *) 0, &tv); } //go.sysin dd * made=TRUE if [ $made = TRUE ]; then /bin/chmod 644 tcpdbug.c /bin/echo -n ' '; /bin/ls -ld tcpdbug.c fi -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@maryland
steveh@hammer.UUCP (Stephen Hemminger) (05/31/85)
Chris, I already had one of these based on your Window library.... I didn't write any documentation for it but it should be pretty obvious.. 8-) ---- cut here --- /* * Tcp Debug - visual picture of Tcp connections * * Simple menu driven display of information about Tcp based connections. * This combines the information of netstat + trpt. */ #ifndef lint static char _rcsid[] = "$Header: tcpic.c,v 1.1 85/04/09 15:25:00 steveh Exp $$Locker: $"; #endif #include <stdio.h> #include <netdb.h> #include <nlist.h> #include <local/window.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/socketvar.h> #define PRUREQUESTS #include <sys/protosw.h> #include <sys/ioctl.h> #include <sys/mbuf.h> #include <net/route.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/in_pcb.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_var.h> #include <netinet/tcp.h> #define TCPSTATES #include <netinet/tcp_fsm.h> #include <netinet/tcp_seq.h> #define TCPTIMERS #include <netinet/tcp_timer.h> #include <netinet/tcp_var.h> #include <netinet/tcpip.h> #define TANAMES #include <netinet/tcp_debug.h> struct nlist nml[] = { #define N_TCB 0 { "_tcb" }, #define N_TCP_DEBUG 1 { "_tcp_debug" }, #define N_TCP_DEBX 2 { "_tcp_debx" }, #define N_MBSTAT 3 { "_mbstat" }, #define N_TCPSTAT 4 { "_tcpstat" }, 0 }; char Tf_flags[] = "\1ACKNOW\2DELACK\3DONTKEEP\4NOOPT"; char Th_flags[] = "\1FIN\2SYN\3RST\4PUSH\5ACK\6URG"; int kmem; int aflag = 0; int iflag = 0; int mflag = 0; int dflag = 0; int interval = 10; /* This determines what windows to display */ /* The 4 ints specify the position & size; the two strings are optional, and are the label and initial contents for the window */ struct initscreen { int i_x, i_y, i_xe, i_ye; char *i_lbl, *i_str; } InitScreen[] = { #define W_NETSTAT (wins[0]) /*0*/ 0, 0, 80, 23, 0, 0, #define W_SOCK (wins[1]) /*1*/ 0, 0, 16, 4, "Socket", "SendQ\nRecvQ", #define W_BYTES (wins[2]) /*2*/ 0, 4, 16, 4, "Data Xfer", "Sent\nRcvd", #define W_RECV (wins[3]) /*3*/ 0, 9, 16, 6, "Recv Seq", "Wind\nNext\nUrg\nAdv", #define W_TIMER (wins[4]) /*4*/ 17, 0, 16, 6, "Tcp Timers", 0, #define W_SEND (wins[5]) /*5*/ 17, 6, 16, 9, "Send Seq", "Wind\nNext\nUrg\nMax\nUna\nSeq#\nAck#", #define W_RETRY (wins[6]) /*6*/ 35, 0, 16, 7, "Retransmit", "Shift\nIdle\nRtt\nRtseq\nSrtt", #define W_PARAM (wins[7]) /*7*/ 34, 9, 20, 6, "Parameters", "State\nMax seg size\nForce\nFlags", #define W_IFNET (wins[8]) /*8*/ 56, 0, 20, 7, "", "In packets\nIn error\nOut packets\nOut errors\nCollisions", #define W_MBSTAT (wins[9]) /*9*/ 56, 8, 20, 6, "Mbuf stat", "In use\nFree\nPages\nFree Pages", #define W_TCPSTAT (wins[10]) /*10*/ 56, 8, 20, 7, "Tcp stat", "Bad Sum\nBad Off\nHdr Drop\nBad Segs\nUnack", #define W_DEBUG (wins[11]) /*11*/ 0, 15, 80, 8, 0, 0, #define W_HELP (wins[12]) /*12*/ 0, 23, 80, 1, 0, 0 }; #define NWINS (sizeof InitScreen/sizeof *InitScreen) static char buf[BUFSIZ]; #define WPR(w,y,x,fmt,n) WAcursor (w, y, x), \ (void) sprintf (buf, fmt, n), \ Wputs (buf, w) Win *wins[NWINS]; int Maxrows, Maxcols; struct inpcb *GetInpcb(); char *strsave(); extern char *strcpy(), *malloc(), *calloc(), *index(), *inet_ntoa(); extern long lseek(); /* * Main program * Parse arguments, choose connection and display it. */ main(argc, argv) int argc; char *argv[]; { register struct inpcb *inp; while(--argc && **++argv == '-') { switch(argv[0][1]) { case 'a': ++aflag; break; case 'd': ++dflag; break; case 'i': ++iflag; break; case 'm': ++mflag; break; default: fprintf(stderr, "tcpic: unknown arg %s\n", argv[1]); fprintf(stderr,"Usage: tcpic [flags] [ interval ]\n"); fprintf(stderr,"flags: %s\n%s\n%s\n%s\n", "\t-a\tall (include) servers", "\t-d\tshow debug trace (trpt)", "\t-i\tshow interfaces", "\t-m\tshow mbuf stats"); exit(1); } } if(argc) interval = atoi(*++argv); nlist("/vmunix", nml); if(nml[0].n_value == 0) { fprintf(stderr,"tcpic: can't read kernel symbol table\n"); exit(1); } if( (kmem = open("/dev/kmem", 0)) < 0) { perror("/dev/kmem"); exit(1); } SetupWindows(); Wfront(W_NETSTAT); Wsetmode(W_HELP, WBOLD); Wnewline(W_HELP, 0); Wlabel( W_NETSTAT, "# Local Address Foreign Address State", 0, 0); if(!iflag) Whide(W_IFNET); if(!mflag) Whide(W_MBSTAT); else Whide(W_TCPSTAT); BuildPortTable(); sethostent(1); while( (inp = GetInpcb()) != NULL) { Whide(W_NETSTAT); Display(inp); Wunhide(W_NETSTAT); } Wexit(0); } /* * Set up the initial window display. */ SetupWindows() { register struct initscreen *ip; register char *str; register Win *w; register int n; if(Winit(0,0)) { fprintf(stderr, "This terminal doesn't support windows\n"); exit(1); } Wscreensize(&Maxrows, &Maxcols); /* initialize windows */ for(n = 0, ip = InitScreen; n < NWINS; n++, ip++) { /* adjust size of some windows to fit screen */ if(n == &W_NETSTAT - wins) { ip->i_ye = Maxrows-1; /* netstat takes full screen */ ip->i_xe = Maxcols; } else if(n == &W_HELP - wins) { ip->i_y = Maxrows-1; /* help at bottom */ ip->i_xe = Maxcols; } else if(n == &W_DEBUG - wins) {/* debug takes what is left on screen */ ip->i_ye = Maxrows - ip->i_y - 2; ip->i_xe = Maxcols; } w = Wopen(0, ip->i_x, ip->i_y, ip->i_xe, ip->i_ye, 0, 0); if (w == 0) { Wcleanup(); fprintf(stderr, "can't fit window '%s' at %d,%d of %d,%d\n", ip->i_lbl, ip->i_x, ip->i_y, ip->i_xe, ip->i_ye); fprintf(stderr, "Screen is too small\n"); exit(1); } wins[ip - InitScreen] = w; Woncursor(w, 0); Wnewline(w, 1); Wwrap(w, 0); if(ip->i_lbl) { Wframe(w); Wlabel(w, ip->i_lbl, 0, 1); } if(str = ip ->i_str) { if(*str == '$') { Wsetmode(w, WINVERSE); str++; } Wputs(str, w); Wsetmode(w,0); } } } /* * Read the port names out of /etc/services and store in memory * for faster access. */ char *PortTable[IPPORT_RESERVED]; BuildPortTable() { register struct servent *sp; u_short port; setservent(); while( (sp = getservent()) != NULL) { if(strcmp(sp->s_proto, "tcp") != 0) continue; port = ntohs((u_short) sp->s_port); if(port < IPPORT_RESERVED) PortTable[port] = strsave(sp->s_name); } endservent(); } /* * Lookup a port name */ char *inetport(port) u_short port; { u_short p = ntohs(port); static char portbuf[10]; if(p == 0) return "*"; else if(p >= IPPORT_RESERVED || PortTable[p] == NULL) { (void) sprintf(portbuf, "%d", p); return portbuf; } else return PortTable[p]; } /* * Host address to name translation * keep already looked up entries around to speed things up. */ struct hosts { struct hosts *ho_next; char *ho_name; u_long ho_addr; } *headhost = NULL; char *inethost(in) struct in_addr in; { register struct hosts *ho; register struct hostent *hp; if (inet_lnaof(in) == INADDR_ANY) return "*"; /* look in save list */ for(ho = headhost; ho != NULL; ho = ho->ho_next) if(ho->ho_addr == in.s_addr) return ho->ho_name; hp = gethostbyaddr(&in, sizeof (struct in_addr), AF_INET); if (hp == NULL) return inet_ntoa(in); /* add to save list */ ho = (struct hosts *) malloc(sizeof(struct hosts)); ho->ho_addr = in.s_addr; ho->ho_name = strsave(hp->h_name); ho->ho_next = headhost; headhost = ho; return hp->h_name; } /* * Pretty print an Internet address (net address + port). */ char * inetprint(in, port) struct in_addr in; u_short port; { static char line[80]; (void) sprintf(line, "%s.%s", inethost(in), inetport(port)); return line; } /* * Print a value a la the %b format of the kernel's printf */ char * flagprint(v, bits) register char *bits; u_short v; { register char *cp; register int i, any = 0; static char obuf[128]; (void) sprintf(obuf,"%x", v); cp = obuf + strlen(obuf); if (v) { *cp++ = '<'; while (i = *bits++) { if (v & (1 << (i-1))) { if (any) *cp++ = ','; any = 1; for (; *bits > 32; bits++) *cp++ = *bits; } else for (; *bits > 32; bits++) ; } *cp++ = '>'; *cp = '\0'; } return obuf; } /* * Print out tcp state */ char * inetstate(off) long off; { static char line[40]; struct tcpcb tcpcb; (void) lseek(kmem, off, 0); (void) read(kmem, (char *) &tcpcb, sizeof (tcpcb)); if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES) (void) sprintf(line, "%d", tcpcb.t_state); else (void) strcpy(line, tcpstates[tcpcb.t_state]); return line; } ReadChar() { char c; if(read(0, &c, 1) != 1) Wexit(0); c &= 0x7f; ioctl(0, FIONREAD, (char *) &InputPending); return c; } struct inpcb * GetInpcb() { register struct inpcb *next, *prev; register int n; char c, *cp; struct inpcb inpcb; long off = nml[N_TCB].n_value; static int npcbs = 0; static struct inpcb **inpcbs; static char keys[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; if(npcbs == 0) { npcbs = Maxrows - 2; inpcbs = (struct inpcb **) calloc(npcbs, sizeof (struct inpcb *)); } reread: WAcursor(W_NETSTAT, 0, 0); Wclear(W_NETSTAT, 2); (void) lseek(kmem, off, 0); (void) read(kmem, (char *) &inpcb, sizeof (struct inpcb)); prev = (struct inpcb *) off; n = 0; /* follow around circular list */ while(inpcb.inp_next != (struct inpcb *)off && n < npcbs) { next = inpcb.inp_next; (void) lseek(kmem, (long) next, 0); (void) read(kmem, (char *) &inpcb, sizeof(struct inpcb)); if(inpcb.inp_prev != prev) { Wputs("??? (lost sync)\n", W_NETSTAT); break; } if(!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) { prev = next; continue; } WAcursor(W_NETSTAT, n, 0); Wsetmode(W_NETSTAT, WBOLD); Wputc( keys[n], W_NETSTAT); Wsetmode(W_NETSTAT, 0); (void) sprintf(buf, " %-18.18s", inetprint(inpcb.inp_laddr,inpcb.inp_lport)); Wputs(buf, W_NETSTAT); (void) sprintf(buf, " %-18.18s %s", inetprint(inpcb.inp_faddr,inpcb.inp_fport), inetstate((long)inpcb.inp_ppcb)); Wputs(buf, W_NETSTAT); prev = next; if(inpcbs[n] == 0) inpcbs[n] = (struct inpcb *) malloc(sizeof(inpcb)); *inpcbs[n] = inpcb; ++n; } Wclearline(W_HELP, 2); Wputs("<letter> => show conn, <SPACE> => reread, <ESC> => quit, '^L' => redraw\r", W_HELP); Wrefresh(0); for(;;) { switch(c = ReadChar()) { case CTRL(l): ++ScreenGarbaged; /* fall into */ case ' ': goto reread; case CTRL([): return NULL; default: cp = index(keys, c); } if(cp == NULL || cp >= &keys[n]) Ding(); else break; } return inpcbs[cp - keys]; } struct socket sockstr; struct rtentry rtentry; struct ifnet iflast; struct tcpstat tcplast; struct mbuf mtcpcb; /* mbuf containing tcpcb */ char ifname[10]; Display(inp) register struct inpcb *inp; { register struct mbuf *mptr; register int i; Wclearline(W_HELP,2); Wputs("<ESC> => quit back to menu, '^L' => redraw\r", W_HELP); for(i = 0; i < TCPT_NTIMERS; ++i) { WPR(W_TIMER, i, 0, "%s", tcptimers[i]); } if(iflag) { (void) lseek(kmem, (long) inp->inp_route.ro_rt, 0); (void) read(kmem, (char *) &rtentry, sizeof(rtentry)); (void) lseek(kmem, (long) rtentry.rt_ifp, 0); (void) read(kmem, (char *) &iflast, sizeof(struct ifnet)); (void) lseek(kmem, (long) iflast.if_name, 0); (void) read(kmem, ifname, sizeof(ifname)); (void) sprintf(buf, "If %s%d", ifname, iflast.if_unit); Wlabel(W_IFNET, buf, 0, 1); } if(!mflag) { (void) lseek(kmem, nml[N_TCPSTAT].n_value, 0); (void) read(kmem, (caddr_t) &tcplast, sizeof tcplast); } Whide(W_DEBUG); mptr = dtom(inp->inp_ppcb); for(;;) { (void) lseek(kmem, (long) mptr, 0); (void) read(kmem, (char *) &mtcpcb, sizeof(mtcpcb)); if(mtcpcb.m_type != MT_PCB ) { Wclearline(W_HELP, 2); Wputs("Connection closed\r", W_HELP); Wrefresh(0); sleep(1); break; } (void) lseek(kmem, (long) inp->inp_socket, 0); (void) read(kmem, (char *) &sockstr, sizeof(sockstr)); DisplayTcp(mtod(&mtcpcb,struct tcpcb *)); if(iflag) DisplayIf(); if(mflag) DisplayMbuf(); else DisplayStat(); Wrefresh (0); if(dflag && sockstr.so_options & SO_DEBUG) { Wunhide(W_DEBUG); DoDebug(inp->inp_ppcb); } /* Refresh and redisplay */ while (InputPending) { switch( ReadChar() ) { case CTRL(l): ScreenGarbaged++; break; case 'q': case 'Q': case CTRL([): return; } } if(interval) sleep(interval); } } DisplayStat() { struct tcpstat tcpcur; (void) lseek(kmem, nml[N_TCPSTAT].n_value, 0); (void) read(kmem, (char *) &tcpcur, sizeof tcpcur); WPR(W_TCPSTAT, 0, 10, "%8d", tcpcur.tcps_badsum-tcplast.tcps_badsum); WPR(W_TCPSTAT, 1, 10, "%8d", tcpcur.tcps_badoff-tcplast.tcps_badoff); WPR(W_TCPSTAT, 2, 10, "%8d", tcpcur.tcps_hdrops-tcplast.tcps_hdrops); WPR(W_TCPSTAT, 3, 10, "%8d", tcpcur.tcps_badsegs-tcplast.tcps_badsegs); WPR(W_TCPSTAT, 4, 10, "%8d", tcpcur.tcps_unack-tcplast.tcps_unack); tcplast = tcpcur; } DisplayMbuf() { struct mbstat mbstat; if(nml[N_MBSTAT].n_type == 0) return; (void) lseek(kmem, nml[N_MBSTAT].n_value, 0); (void) read(kmem, (char *) &mbstat, sizeof mbstat); WPR(W_MBSTAT, 0, 10, "%8d", mbstat.m_mbufs - mbstat.m_mbfree); WPR(W_MBSTAT, 1, 10, "%8d", mbstat.m_mbfree); WPR(W_MBSTAT, 2, 10, "%8d", mbstat.m_clusters - mbstat.m_clfree); WPR(W_MBSTAT, 3, 10, "%8d", mbstat.m_clfree); } DisplayIf() { struct ifnet ifcur; (void) lseek(kmem, (long) rtentry.rt_ifp, 0); (void) read(kmem, (char *) &ifcur, sizeof(struct ifnet)); WPR(W_IFNET, 0, 11, "%8d", ifcur.if_ipackets - iflast.if_ipackets); WPR(W_IFNET, 1, 11, "%8d", ifcur.if_ierrors - iflast.if_ierrors); WPR(W_IFNET, 2, 11, "%8d", ifcur.if_opackets - iflast.if_opackets); WPR(W_IFNET, 3, 11, "%8d", ifcur.if_ierrors - iflast.if_ierrors); WPR(W_IFNET, 4, 11, "%8d", ifcur.if_collisions - iflast.if_collisions); iflast = ifcur; } DisplayTcp(tcp) register struct tcpcb *tcp; { register int i; for(i = 0; i < TCPT_NTIMERS; i++) { WPR(W_TIMER, i, 8, "%6d", tcp->t_timer[i]); } WPR(W_RETRY, 0, 6, "%8d", tcp->t_rxtshift); WPR(W_RETRY, 1, 6, "%8d", tcp->t_idle); WPR(W_RETRY, 2, 6, "%8d", tcp->t_rtt); WPR(W_RETRY, 3, 6, "%8x", tcp->t_rtseq); #ifdef NOFLOAT WPR(W_RETRY, 4, 6, "%8.2f", (double) tcp->t_srtt/((double) TCPT_SCALE)); #else WPR(W_RETRY, 4, 6, "%8.2f", tcp->t_srtt); #endif WAcursor(W_PARAM, 0, 6); if (tcp->t_state < 0 || tcp->t_state >= TCP_NSTATES) (void) sprintf(buf, "%12d" , tcp->t_state); else (void) sprintf(buf, "%12s", tcpstates[tcp->t_state]); Wputs(buf, W_PARAM); WPR(W_PARAM, 1, 13, "%5d", tcp->t_maxseg); WPR(W_PARAM, 2, 14, "%4d", tcp->t_force); WPR(W_PARAM, 3, 6, "%12s", flagprint((u_short)tcp->t_flags, Tf_flags)); WPR(W_SEND, 0, 6, "%8d", tcp->snd_wnd); WPR(W_SEND, 1, 6, "%8x", tcp->snd_nxt); WPR(W_SEND, 2, 6, "%8x", tcp->snd_up); WPR(W_SEND, 3, 6, "%8x", tcp->snd_max); WPR(W_SEND, 4, 6, "%8x", tcp->snd_una); WPR(W_SEND, 5, 6, "%8x", tcp->snd_wl1); WPR(W_SEND, 6, 6, "%8x", tcp->snd_wl2); WPR(W_RECV, 0, 6, "%8d", tcp->rcv_wnd); WPR(W_RECV, 1, 6, "%8x", tcp->rcv_nxt); WPR(W_RECV, 2, 6, "%8x", tcp->rcv_up); WPR(W_RECV, 3, 6, "%8x", tcp->rcv_adv); WPR(W_BYTES, 0, 5, "%10d", (u_long)tcp->snd_nxt - (u_long)tcp->iss); WPR(W_BYTES, 1, 5, "%10d", (u_long)tcp->rcv_nxt - (u_long)tcp->irs); WPR(W_SOCK, 0, 5, "%10d", sockstr.so_snd.sb_cc); WPR(W_SOCK, 1, 5, "%10d", sockstr.so_rcv.sb_cc); } char *strsave(str) register char *str; { register int len = strlen(str); register char *new; extern char *malloc(); new = malloc(++len); (void) strcpy(new, str); return new; } /* * Tcp debug routines */ DoDebug(tcp) caddr_t tcp; { static int last_debx = -1; register int debx; if(nml[N_TCP_DEBUG].n_type == 0) return; (void) lseek(kmem, nml[N_TCP_DEBX].n_value, 0); (void) read(kmem, (char *) &tcp_debx, sizeof(tcp_debx)); (void) lseek(kmem, nml[N_TCP_DEBUG].n_value, 0); (void) read(kmem, (char *) tcp_debug, sizeof(tcp_debug)); Wunhide(W_DEBUG); if(last_debx == -1) { last_debx = tcp_debx; return; } for(debx = last_debx; debx != tcp_debx; debx = ++debx % TCP_NDEBUG) { if(tcp != tcp_debug[debx].td_tcb) continue; tcp_trace(&tcp_debug[debx]); Wrefresh(0); if(InputPending) break; } last_debx = debx; } /* * Print out a Tcp debug record */ tcp_trace(td) register struct tcp_debug *td; { register struct tcpiphdr *ti = &td->td_ti; tcp_seq seq, ack; short act = td->td_act; short req = td->td_req; int len, flags, win, timer; (void) sprintf(buf,"%03d %s:%s ", (ntohl(td->td_time)/10) % 1000, tcpstates[td->td_ostate], tanames[act]); Wputs(buf, W_DEBUG); switch (act) { case TA_INPUT: case TA_OUTPUT: case TA_DROP: (void) sprintf(buf,"(src=%s,%d, dst=%s,%d)\n\t", inet_ntoa(ti->ti_src), ntohs(ti->ti_sport), inet_ntoa(ti->ti_dst), ntohs(ti->ti_dport)); Wputs(buf, W_DEBUG); seq = ti->ti_seq; ack = ti->ti_ack; len = ti->ti_len; win = ti->ti_win; if (act == TA_OUTPUT) { seq = ntohl(seq); ack = ntohl(ack); len = ntohs(len); win = ntohs(win); } if (act == TA_OUTPUT) len -= sizeof (struct tcphdr); if (len) (void) sprintf(buf,"[%x..%x)@%x", seq, seq+len, ack); else (void) sprintf(buf,"%x@%x", seq, ack); Wputs(buf, W_DEBUG); if (win) { (void) sprintf(buf,"(win=%x)", win); Wputs(buf, W_DEBUG); } if (flags = ti->ti_flags) { Wputs(" flags=",W_DEBUG); Wputs(flagprint((u_short)flags, Th_flags), W_DEBUG); } break; case TA_USER: timer = req >> 8; req &= 0xff; (void) sprintf(buf,"%s", prurequests[req]); Wputs(buf, W_DEBUG); if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO) { (void) sprintf(buf,"<%s>", tcptimers[timer]); Wputs(buf, W_DEBUG); } break; } (void) sprintf(buf," -> %s\n", tcpstates[td->td_cb.t_state]); Wputs(buf,W_DEBUG); }