home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / unix_c / networks / tcpdebug.c < prev    next >
Internet Message Format  |  1989-03-21  |  18KB

  1. From: Stephen Hemminger <tektronix!orca!hammer!steveh@Ucb-Vax.ARPA>
  2. Newsgroups: net.sources
  3. Subject: Re: TCP debugging aid for 4.2BSD
  4. Date: 31 May 85 18:26:27 GMT
  5.  
  6. Chris, I already had one of these based on your Window library....
  7.  
  8. I didn't write any documentation for it but it should be pretty obvious.. 8-)
  9.  
  10. ---- cut here ---
  11. /*
  12.  * Tcp Debug - visual picture of Tcp connections
  13.  *
  14.  * Simple menu driven display of information about Tcp based connections.
  15.  * This combines the information of netstat + trpt.
  16.  */
  17.  
  18. #ifndef lint
  19. static char _rcsid[] = "$Header: tcpic.c,v 1.1 85/04/09 15:25:00 steveh Exp $$Locker:  $";
  20. #endif
  21.  
  22. #include <stdio.h>
  23. #include <netdb.h>
  24. #include <nlist.h>
  25. #include <local/window.h>
  26.  
  27. #include <sys/types.h>
  28. #include <sys/socket.h>
  29. #include <sys/socketvar.h>
  30. #define PRUREQUESTS
  31. #include <sys/protosw.h>
  32. #include <sys/ioctl.h>
  33. #include <sys/mbuf.h>
  34.  
  35. #include <net/route.h>
  36. #include <net/if.h>
  37.  
  38. #include <netinet/in.h>
  39. #include <netinet/in_pcb.h>
  40. #include <netinet/in_systm.h>
  41. #include <netinet/ip.h>
  42. #include <netinet/ip_var.h>
  43. #include <netinet/tcp.h>
  44. #define TCPSTATES
  45. #include <netinet/tcp_fsm.h>
  46. #include <netinet/tcp_seq.h>
  47. #define TCPTIMERS
  48. #include <netinet/tcp_timer.h>
  49. #include <netinet/tcp_var.h>
  50. #include <netinet/tcpip.h>
  51. #define TANAMES
  52. #include <netinet/tcp_debug.h>
  53.  
  54.  
  55. struct nlist nml[] = {
  56. #define N_TCB        0
  57.     { "_tcb" },
  58. #define N_TCP_DEBUG    1
  59.     { "_tcp_debug" },
  60. #define N_TCP_DEBX    2
  61.     { "_tcp_debx" },
  62. #define N_MBSTAT    3
  63.     { "_mbstat" },
  64. #define N_TCPSTAT    4
  65.     { "_tcpstat" },
  66.     0
  67. };
  68.  
  69.  
  70. char    Tf_flags[] = "\1ACKNOW\2DELACK\3DONTKEEP\4NOOPT";
  71. char    Th_flags[] = "\1FIN\2SYN\3RST\4PUSH\5ACK\6URG";
  72.  
  73. int    kmem;
  74. int    aflag = 0;
  75. int    iflag = 0;
  76. int    mflag = 0;
  77. int    dflag = 0;
  78. int     interval = 10;
  79.  
  80. /* This determines what windows to display */
  81. /* The 4 ints specify the position & size;
  82.    the two strings are optional, and
  83.    are the label and initial contents for the window
  84.  */
  85. struct initscreen {
  86.     int    i_x, i_y, i_xe, i_ye;
  87.     char    *i_lbl, *i_str;
  88. } InitScreen[] = {
  89. #define W_NETSTAT (wins[0])    
  90. /*0*/    0, 0,    80, 23, 0,
  91.             0,
  92. #define    W_SOCK    (wins[1])
  93. /*1*/    0, 0,    16, 4,    "Socket",
  94.             "SendQ\nRecvQ",
  95. #define W_BYTES    (wins[2])
  96. /*2*/    0, 4,    16, 4,    "Data Xfer",
  97.             "Sent\nRcvd",
  98. #define W_RECV (wins[3])
  99. /*3*/    0, 9,    16, 6,    "Recv Seq",
  100.             "Wind\nNext\nUrg\nAdv",
  101. #define    W_TIMER    (wins[4])
  102. /*4*/    17, 0,    16, 6, "Tcp Timers",
  103.             0,
  104. #define    W_SEND    (wins[5])
  105. /*5*/    17, 6,    16, 9,    "Send Seq",
  106.             "Wind\nNext\nUrg\nMax\nUna\nSeq#\nAck#",
  107. #define W_RETRY (wins[6])
  108. /*6*/    35, 0,    16, 7,    "Retransmit",
  109.             "Shift\nIdle\nRtt\nRtseq\nSrtt",
  110. #define W_PARAM (wins[7])
  111. /*7*/    34, 9,    20,  6,    "Parameters",
  112.             "State\nMax seg size\nForce\nFlags",
  113. #define W_IFNET (wins[8])
  114. /*8*/    56, 0,    20, 7,    "",
  115.             "In packets\nIn error\nOut packets\nOut errors\nCollisions",
  116. #define W_MBSTAT (wins[9])
  117. /*9*/    56, 8,    20, 6,  "Mbuf stat",
  118.             "In use\nFree\nPages\nFree Pages",
  119. #define W_TCPSTAT (wins[10])
  120. /*10*/    56, 8,  20, 7,  "Tcp stat",
  121.             "Bad Sum\nBad Off\nHdr Drop\nBad Segs\nUnack",
  122. #define W_DEBUG    (wins[11])        
  123. /*11*/    0, 15,    80, 8,    0, 0,
  124. #define W_HELP  (wins[12])
  125. /*12*/    0, 23,    80, 1,    0, 0        
  126. };
  127.  
  128. #define    NWINS    (sizeof InitScreen/sizeof *InitScreen)
  129.  
  130. static char buf[BUFSIZ];
  131.  
  132. #define    WPR(w,y,x,fmt,n)    WAcursor (w, y, x),    \
  133.                 (void) sprintf (buf, fmt, n),    \
  134.                 Wputs (buf, w)
  135.  
  136. Win    *wins[NWINS];
  137. int    Maxrows, Maxcols;
  138.  
  139. struct inpcb    *GetInpcb();
  140. char        *strsave();
  141. extern char    *strcpy(), *malloc(), *calloc(), *index(),
  142.         *inet_ntoa();
  143. extern long    lseek();
  144.  
  145. /*
  146.  * Main program
  147.  *  Parse arguments, choose connection and display it.
  148.  */
  149. main(argc, argv)
  150.     int argc;
  151.     char *argv[];
  152. {
  153.     register struct inpcb *inp;
  154.  
  155.     while(--argc && **++argv == '-') {
  156.         switch(argv[0][1]) {
  157.         case 'a': ++aflag;        break;
  158.         case 'd': ++dflag;        break;
  159.         case 'i': ++iflag;        break;
  160.         case 'm': ++mflag;        break;
  161.         default:
  162.             fprintf(stderr, "tcpic: unknown arg %s\n", argv[1]);
  163.             fprintf(stderr,"Usage: tcpic  [flags] [ interval ]\n");
  164.             fprintf(stderr,"flags: %s\n%s\n%s\n%s\n",
  165.                 "\t-a\tall (include) servers",
  166.                 "\t-d\tshow debug trace (trpt)",
  167.                 "\t-i\tshow interfaces",
  168.                 "\t-m\tshow mbuf stats");
  169.             exit(1);
  170.         }
  171.     }
  172.  
  173.     if(argc)
  174.         interval = atoi(*++argv);        
  175.  
  176.  
  177.     nlist("/vmunix", nml);
  178.     
  179.     if(nml[0].n_value == 0) {
  180.         fprintf(stderr,"tcpic: can't read kernel symbol table\n");
  181.         exit(1);
  182.     }
  183.  
  184.     if( (kmem = open("/dev/kmem", 0)) < 0) {
  185.         perror("/dev/kmem");
  186.         exit(1);
  187.     }
  188.  
  189.     SetupWindows();
  190.     Wfront(W_NETSTAT);
  191.     Wsetmode(W_HELP, WBOLD);
  192.     Wnewline(W_HELP, 0);
  193.     Wlabel( W_NETSTAT,
  194.         "# Local Address        Foreign Address   State",
  195.         0, 0);
  196.  
  197.     if(!iflag)
  198.         Whide(W_IFNET);
  199.     if(!mflag)
  200.         Whide(W_MBSTAT);
  201.     else
  202.         Whide(W_TCPSTAT);
  203.     BuildPortTable();
  204.  
  205.     sethostent(1);
  206.  
  207.     while( (inp = GetInpcb()) != NULL) {
  208.         Whide(W_NETSTAT);
  209.         Display(inp);
  210.         Wunhide(W_NETSTAT);
  211.     }
  212.  
  213.     Wexit(0);
  214. }
  215.  
  216. /*
  217.  * Set up the initial window display.
  218.  */
  219. SetupWindows()
  220. {
  221.     register struct initscreen *ip;
  222.     register char *str;
  223.     register Win *w;
  224.     register int n;
  225.  
  226.     if(Winit(0,0))  {
  227.         fprintf(stderr, "This terminal doesn't support windows\n");
  228.         exit(1);
  229.     }
  230.     Wscreensize(&Maxrows, &Maxcols);
  231.  
  232.     /* initialize windows */
  233.     for(n = 0, ip = InitScreen; n < NWINS; n++, ip++) {
  234.          /*  adjust size of some windows to fit screen */
  235.         
  236.         if(n == &W_NETSTAT - wins) {
  237.             ip->i_ye = Maxrows-1;    /* netstat takes full screen */
  238.             ip->i_xe = Maxcols;
  239.         } else if(n == &W_HELP - wins) {
  240.             ip->i_y = Maxrows-1;    /* help at bottom */
  241.             ip->i_xe = Maxcols;
  242.         } else if(n == &W_DEBUG - wins) {/* debug takes what is left on screen */
  243.             ip->i_ye = Maxrows - ip->i_y - 2;
  244.             ip->i_xe = Maxcols;
  245.         }
  246.  
  247.         w = Wopen(0, ip->i_x, ip->i_y, ip->i_xe, ip->i_ye, 0, 0);
  248.         if (w == 0) {
  249.             Wcleanup();
  250.             fprintf(stderr, "can't fit window '%s' at %d,%d of %d,%d\n",
  251.                 ip->i_lbl, ip->i_x, ip->i_y, ip->i_xe, ip->i_ye);
  252.             fprintf(stderr, "Screen is too small\n");
  253.             exit(1);
  254.         }
  255.         wins[ip - InitScreen] = w;
  256.         Woncursor(w, 0);
  257.         Wnewline(w, 1);
  258.         Wwrap(w, 0);
  259.         if(ip->i_lbl) {
  260.             Wframe(w);
  261.             Wlabel(w, ip->i_lbl, 0, 1);
  262.         }
  263.         if(str = ip ->i_str) {
  264.             if(*str == '$') {
  265.                 Wsetmode(w, WINVERSE);
  266.                 str++;
  267.             }
  268.             Wputs(str, w);
  269.             Wsetmode(w,0);
  270.         }
  271.     }
  272. }
  273.  
  274. /*
  275.  * Read the port names out of /etc/services and store in memory
  276.  *  for faster access.
  277.  */
  278. char *PortTable[IPPORT_RESERVED];
  279.  
  280. BuildPortTable() {
  281.     register struct servent *sp;
  282.     u_short port;
  283.     
  284.     setservent();
  285.     while( (sp = getservent()) != NULL)  {
  286.         if(strcmp(sp->s_proto, "tcp") != 0)
  287.             continue;
  288.         port = ntohs((u_short) sp->s_port);
  289.         if(port < IPPORT_RESERVED)
  290.             PortTable[port] = strsave(sp->s_name);
  291.     }
  292.     endservent();
  293. }
  294.  
  295. /*
  296.  * Lookup a port name
  297.  */
  298. char *inetport(port)
  299.     u_short port;
  300. {
  301.     u_short p = ntohs(port);
  302.     static char portbuf[10];
  303.  
  304.     if(p == 0) 
  305.         return "*";
  306.     else if(p >= IPPORT_RESERVED || PortTable[p] == NULL) {
  307.         (void) sprintf(portbuf, "%d", p);
  308.         return portbuf;
  309.     } else
  310.         return PortTable[p];
  311. }
  312.  
  313. /*
  314.  * Host address to name translation
  315.  *   keep already looked up entries around to speed things up.
  316.  */
  317.  
  318. struct hosts {
  319.     struct hosts *ho_next;
  320.     char    *ho_name;
  321.     u_long    ho_addr;
  322. } *headhost = NULL;
  323.  
  324. char *inethost(in)
  325.     struct in_addr in;
  326. {
  327.     register struct hosts *ho;
  328.     register struct hostent *hp;
  329.  
  330.     if (inet_lnaof(in) == INADDR_ANY) 
  331.         return "*";
  332.  
  333.     /* look in save list */
  334.     for(ho = headhost; ho != NULL; ho = ho->ho_next) 
  335.         if(ho->ho_addr == in.s_addr)
  336.             return ho->ho_name;
  337.     hp = gethostbyaddr(&in, sizeof (struct in_addr), AF_INET);
  338.     if (hp == NULL)
  339.         return inet_ntoa(in);
  340.  
  341.     /* add to save list */
  342.     ho = (struct hosts *) malloc(sizeof(struct hosts));
  343.     ho->ho_addr = in.s_addr;
  344.     ho->ho_name = strsave(hp->h_name);
  345.     ho->ho_next = headhost;
  346.     headhost = ho;
  347.  
  348.     return hp->h_name;
  349. }
  350. /*
  351.  * Pretty print an Internet address (net address + port).
  352.  */
  353. char *
  354. inetprint(in, port)
  355.     struct in_addr in;
  356.     u_short port;
  357. {
  358.     static char line[80];
  359.  
  360.     (void) sprintf(line, "%s.%s", inethost(in), inetport(port));
  361.     return line;
  362. }
  363.  
  364. /*
  365.  * Print a value a la the %b format of the kernel's printf
  366.  */
  367. char *
  368. flagprint(v, bits)
  369.     register char *bits;
  370.     u_short v;
  371. {
  372.     register char *cp;
  373.     register int i, any = 0;
  374.     static char obuf[128];
  375.  
  376.     (void) sprintf(obuf,"%x", v);
  377.     cp = obuf + strlen(obuf);
  378.     if (v) {
  379.         *cp++ = '<';
  380.         while (i = *bits++) {
  381.         if (v & (1 << (i-1))) {
  382.                 if (any)
  383.                     *cp++ = ',';
  384.                 any = 1;
  385.                 for (; *bits > 32; bits++)
  386.                     *cp++ = *bits;
  387.             } else
  388.                 for (; *bits > 32; bits++)
  389.                     ;
  390.         }
  391.         *cp++ = '>';
  392.         *cp = '\0';
  393.     }
  394.     return obuf;
  395. }
  396.  
  397. /*
  398.  * Print out tcp state
  399.  */
  400. char *
  401. inetstate(off)
  402.     long off;
  403. {
  404.     static char line[40];
  405.     struct tcpcb tcpcb;
  406.  
  407.     (void) lseek(kmem, off, 0);
  408.     (void) read(kmem, (char *) &tcpcb, sizeof (tcpcb));
  409.  
  410.     if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
  411.         (void) sprintf(line, "%d", tcpcb.t_state);
  412.     else
  413.         (void) strcpy(line, tcpstates[tcpcb.t_state]);
  414.     return line;
  415. }
  416.  
  417. ReadChar() {
  418.     char c;
  419.  
  420.     if(read(0, &c, 1) != 1)
  421.         Wexit(0);
  422.     c &= 0x7f;
  423.     ioctl(0, FIONREAD, (char *) &InputPending);
  424.  
  425.     return c;
  426. }
  427.  
  428. struct inpcb *
  429. GetInpcb() {
  430.     register struct inpcb *next, *prev;
  431.     register int n;
  432.     char c, *cp;
  433.     struct inpcb inpcb;
  434.     long off = nml[N_TCB].n_value;
  435.     static int npcbs = 0;
  436.     static struct inpcb **inpcbs;
  437.     static char keys[] =
  438.         "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  439.  
  440.     if(npcbs == 0) {
  441.         npcbs = Maxrows - 2;
  442.         inpcbs = (struct inpcb **)
  443.              calloc(npcbs, sizeof (struct inpcb *));
  444.     }
  445.  
  446. reread:
  447.     WAcursor(W_NETSTAT, 0, 0);
  448.     Wclear(W_NETSTAT, 2);
  449.  
  450.     (void) lseek(kmem, off, 0);
  451.     (void) read(kmem, (char *) &inpcb, sizeof (struct inpcb));
  452.  
  453.     prev = (struct inpcb *) off;
  454.  
  455.     n = 0;
  456.     /* follow around circular list */
  457.     while(inpcb.inp_next != (struct inpcb *)off && n < npcbs) {
  458.         next = inpcb.inp_next;
  459.  
  460.         (void) lseek(kmem, (long) next, 0);
  461.         (void) read(kmem, (char *) &inpcb, sizeof(struct inpcb));
  462.         if(inpcb.inp_prev != prev) {
  463.             Wputs("??? (lost sync)\n", W_NETSTAT);
  464.             break;
  465.         }
  466.  
  467.         if(!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) {
  468.             prev = next;
  469.             continue;
  470.         }
  471.  
  472.         WAcursor(W_NETSTAT, n, 0);
  473.         Wsetmode(W_NETSTAT, WBOLD);
  474.         Wputc( keys[n], W_NETSTAT);
  475.         Wsetmode(W_NETSTAT, 0);
  476.         (void) sprintf(buf, " %-18.18s", 
  477.             inetprint(inpcb.inp_laddr,inpcb.inp_lport));
  478.         Wputs(buf, W_NETSTAT);
  479.         (void) sprintf(buf, " %-18.18s %s", 
  480.             inetprint(inpcb.inp_faddr,inpcb.inp_fport),
  481.             inetstate((long)inpcb.inp_ppcb));
  482.         Wputs(buf, W_NETSTAT);
  483.  
  484.         prev = next;
  485.         if(inpcbs[n] == 0) 
  486.             inpcbs[n] = (struct inpcb *) malloc(sizeof(inpcb));
  487.         *inpcbs[n] = inpcb;
  488.         ++n;
  489.     }
  490.  
  491.     Wclearline(W_HELP, 2);
  492.     Wputs("<letter> => show conn, <SPACE> => reread, <ESC> => quit, '^L' => redraw\r",
  493.          W_HELP);
  494.     Wrefresh(0);
  495.  
  496.     for(;;) {
  497.         switch(c = ReadChar()) {
  498.         case CTRL(l):
  499.             ++ScreenGarbaged;
  500.             /* fall into */
  501.         case ' ':
  502.             goto reread;
  503.         case CTRL([):
  504.             return NULL;
  505.         default:
  506.             cp = index(keys, c);
  507.         }
  508.         if(cp == NULL || cp >= &keys[n])
  509.             Ding();
  510.         else
  511.             break;
  512.     }
  513.  
  514.     return inpcbs[cp - keys];
  515. }
  516.  
  517. struct socket sockstr;
  518. struct rtentry rtentry;
  519. struct ifnet iflast;
  520. struct tcpstat tcplast;
  521. struct mbuf mtcpcb;        /* mbuf containing tcpcb */
  522. char    ifname[10];
  523.  
  524. Display(inp)
  525.     register struct inpcb *inp;
  526. {
  527.     register struct mbuf *mptr;
  528.     register int i;
  529.  
  530.     Wclearline(W_HELP,2);
  531.     Wputs("<ESC> => quit back to menu, '^L' => redraw\r", W_HELP);
  532.  
  533.     
  534.     for(i = 0; i < TCPT_NTIMERS; ++i) {
  535.         WPR(W_TIMER, i, 0, "%s", tcptimers[i]);
  536.     }
  537.  
  538.     if(iflag) {
  539.         (void) lseek(kmem, (long) inp->inp_route.ro_rt, 0);
  540.         (void) read(kmem, (char *) &rtentry, sizeof(rtentry));
  541.  
  542.         (void) lseek(kmem, (long) rtentry.rt_ifp, 0);
  543.         (void) read(kmem, (char *) &iflast, sizeof(struct ifnet));
  544.     
  545.         (void) lseek(kmem, (long) iflast.if_name, 0);
  546.         (void) read(kmem, ifname, sizeof(ifname));
  547.     
  548.         (void) sprintf(buf, "If %s%d", ifname, iflast.if_unit);
  549.         Wlabel(W_IFNET, buf, 0, 1);
  550.     }
  551.  
  552.     if(!mflag) {
  553.         (void) lseek(kmem, nml[N_TCPSTAT].n_value, 0);
  554.         (void) read(kmem, (caddr_t) &tcplast, sizeof tcplast);
  555.     }
  556.  
  557.     Whide(W_DEBUG);
  558.  
  559.     mptr = dtom(inp->inp_ppcb);
  560.  
  561.     for(;;) {
  562.         (void) lseek(kmem, (long) mptr, 0);
  563.         (void) read(kmem, (char *) &mtcpcb, sizeof(mtcpcb));
  564.  
  565.         if(mtcpcb.m_type != MT_PCB ) {
  566.             Wclearline(W_HELP, 2);
  567.              Wputs("Connection closed\r", W_HELP);
  568.              Wrefresh(0);
  569.              sleep(1);
  570.             break;
  571.         }
  572.  
  573.         (void) lseek(kmem, (long) inp->inp_socket, 0);
  574.         (void) read(kmem, (char *) &sockstr, sizeof(sockstr));
  575.  
  576.         DisplayTcp(mtod(&mtcpcb,struct tcpcb *));
  577.         if(iflag)
  578.             DisplayIf();
  579.         if(mflag)
  580.             DisplayMbuf();
  581.         else
  582.             DisplayStat();
  583.  
  584.         Wrefresh (0);
  585.         if(dflag && sockstr.so_options & SO_DEBUG) {
  586.             Wunhide(W_DEBUG);
  587.             DoDebug(inp->inp_ppcb);
  588.         }
  589.  
  590.         /* Refresh and redisplay */
  591.         while (InputPending) {
  592.             switch( ReadChar() ) {
  593.             case CTRL(l):
  594.                 ScreenGarbaged++;
  595.                 break;
  596.             case 'q':
  597.             case 'Q':
  598.             case CTRL([):
  599.                 return;
  600.             }
  601.         }
  602.     
  603.         if(interval)
  604.             sleep(interval);
  605.  
  606.     }
  607. }
  608.  
  609. DisplayStat()
  610. {
  611.     struct tcpstat tcpcur;
  612.  
  613.     (void) lseek(kmem, nml[N_TCPSTAT].n_value, 0);
  614.     (void) read(kmem, (char *) &tcpcur, sizeof tcpcur);
  615.  
  616.     WPR(W_TCPSTAT, 0, 10, "%8d", tcpcur.tcps_badsum-tcplast.tcps_badsum);
  617.     WPR(W_TCPSTAT, 1, 10, "%8d", tcpcur.tcps_badoff-tcplast.tcps_badoff);
  618.     WPR(W_TCPSTAT, 2, 10, "%8d", tcpcur.tcps_hdrops-tcplast.tcps_hdrops);
  619.     WPR(W_TCPSTAT, 3, 10, "%8d", tcpcur.tcps_badsegs-tcplast.tcps_badsegs);
  620.     WPR(W_TCPSTAT, 4, 10, "%8d", tcpcur.tcps_unack-tcplast.tcps_unack);
  621.     tcplast = tcpcur;
  622. }
  623.  
  624. DisplayMbuf()
  625. {
  626.     struct mbstat mbstat;
  627.  
  628.     if(nml[N_MBSTAT].n_type == 0)
  629.         return;
  630.  
  631.     (void) lseek(kmem, nml[N_MBSTAT].n_value, 0);
  632.     (void) read(kmem, (char *) &mbstat, sizeof mbstat);
  633.     
  634.     WPR(W_MBSTAT, 0, 10, "%8d", mbstat.m_mbufs - mbstat.m_mbfree);
  635.     WPR(W_MBSTAT, 1, 10, "%8d", mbstat.m_mbfree);
  636.     WPR(W_MBSTAT, 2, 10, "%8d", mbstat.m_clusters - mbstat.m_clfree);
  637.     WPR(W_MBSTAT, 3, 10, "%8d", mbstat.m_clfree);
  638. }
  639.  
  640. DisplayIf()
  641. {
  642.     struct ifnet ifcur;
  643.  
  644.     (void) lseek(kmem, (long) rtentry.rt_ifp, 0);
  645.     (void) read(kmem, (char *) &ifcur, sizeof(struct ifnet));
  646.     
  647.     WPR(W_IFNET, 0, 11, "%8d", ifcur.if_ipackets - iflast.if_ipackets);
  648.     WPR(W_IFNET, 1, 11, "%8d", ifcur.if_ierrors - iflast.if_ierrors);
  649.     WPR(W_IFNET, 2, 11, "%8d", ifcur.if_opackets - iflast.if_opackets);
  650.     WPR(W_IFNET, 3, 11, "%8d", ifcur.if_ierrors - iflast.if_ierrors);
  651.     WPR(W_IFNET, 4, 11, "%8d", ifcur.if_collisions - iflast.if_collisions);
  652.     iflast = ifcur;
  653. }
  654.  
  655. DisplayTcp(tcp)
  656.     register struct tcpcb *tcp;
  657. {
  658.     register int i;
  659.  
  660.     for(i = 0; i < TCPT_NTIMERS; i++) {
  661.         WPR(W_TIMER, i, 8, "%6d", tcp->t_timer[i]);
  662.     }
  663.  
  664.     WPR(W_RETRY, 0, 6, "%8d", tcp->t_rxtshift);
  665.     WPR(W_RETRY, 1, 6, "%8d", tcp->t_idle);
  666.     WPR(W_RETRY, 2, 6, "%8d", tcp->t_rtt);
  667.     WPR(W_RETRY, 3, 6, "%8x", tcp->t_rtseq);
  668. #ifdef NOFLOAT
  669.     WPR(W_RETRY, 4, 6, "%8.2f", (double) tcp->t_srtt/((double) TCPT_SCALE));
  670. #else
  671.     WPR(W_RETRY, 4, 6, "%8.2f", tcp->t_srtt);
  672. #endif
  673.  
  674.     WAcursor(W_PARAM, 0, 6);
  675.     if (tcp->t_state < 0 || tcp->t_state >= TCP_NSTATES)
  676.         (void) sprintf(buf, "%12d" , tcp->t_state);
  677.     else 
  678.         (void) sprintf(buf, "%12s", tcpstates[tcp->t_state]);
  679.     Wputs(buf, W_PARAM);
  680.     WPR(W_PARAM, 1, 13, "%5d", tcp->t_maxseg);
  681.     WPR(W_PARAM, 2, 14, "%4d", tcp->t_force);
  682.     WPR(W_PARAM, 3, 6, "%12s", flagprint((u_short)tcp->t_flags, Tf_flags));
  683.  
  684.     WPR(W_SEND, 0, 6, "%8d", tcp->snd_wnd);
  685.     WPR(W_SEND, 1, 6, "%8x", tcp->snd_nxt);
  686.     WPR(W_SEND, 2, 6, "%8x", tcp->snd_up);
  687.     WPR(W_SEND, 3, 6, "%8x", tcp->snd_max);
  688.     WPR(W_SEND, 4, 6, "%8x", tcp->snd_una);
  689.     WPR(W_SEND, 5, 6, "%8x", tcp->snd_wl1);
  690.     WPR(W_SEND, 6, 6, "%8x", tcp->snd_wl2);
  691.  
  692.     WPR(W_RECV, 0, 6, "%8d", tcp->rcv_wnd);
  693.     WPR(W_RECV, 1, 6, "%8x", tcp->rcv_nxt);
  694.     WPR(W_RECV, 2, 6, "%8x", tcp->rcv_up);
  695.     WPR(W_RECV, 3, 6, "%8x", tcp->rcv_adv);
  696.  
  697.     WPR(W_BYTES, 0, 5, "%10d", (u_long)tcp->snd_nxt - (u_long)tcp->iss);
  698.     WPR(W_BYTES, 1, 5, "%10d", (u_long)tcp->rcv_nxt - (u_long)tcp->irs);
  699.  
  700.     WPR(W_SOCK, 0, 5, "%10d", sockstr.so_snd.sb_cc);
  701.     WPR(W_SOCK, 1, 5, "%10d", sockstr.so_rcv.sb_cc);
  702.  
  703. }
  704.  
  705. char *strsave(str)
  706.     register char *str;
  707. {
  708.     register int len = strlen(str);
  709.     register char *new;
  710.     extern char *malloc();
  711.  
  712.     new = malloc(++len);
  713.     (void) strcpy(new, str);
  714.     return new;
  715. }
  716.  
  717. /*
  718.  * Tcp debug routines
  719.  */
  720.  
  721. DoDebug(tcp)
  722.     caddr_t tcp;
  723. {
  724.     static int last_debx = -1;
  725.     register int debx;
  726.     
  727.     if(nml[N_TCP_DEBUG].n_type == 0)
  728.         return;
  729.     (void) lseek(kmem, nml[N_TCP_DEBX].n_value, 0);
  730.     (void) read(kmem, (char *) &tcp_debx, sizeof(tcp_debx));
  731.  
  732.     (void) lseek(kmem, nml[N_TCP_DEBUG].n_value, 0);
  733.     (void) read(kmem, (char *) tcp_debug, sizeof(tcp_debug));
  734.  
  735.     Wunhide(W_DEBUG);
  736.     if(last_debx == -1) {
  737.         last_debx = tcp_debx;
  738.         return;
  739.     }
  740.  
  741.     for(debx = last_debx; debx != tcp_debx; debx = ++debx % TCP_NDEBUG) {
  742.         if(tcp != tcp_debug[debx].td_tcb)
  743.             continue;
  744.         tcp_trace(&tcp_debug[debx]);
  745.         Wrefresh(0);
  746.         if(InputPending)
  747.             break;
  748.     }
  749.     last_debx = debx;
  750. }
  751.  
  752. /*
  753.  * Print out a Tcp debug record
  754.  */
  755. tcp_trace(td)
  756.     register struct tcp_debug *td;
  757. {
  758.     register struct tcpiphdr *ti = &td->td_ti;
  759.     tcp_seq seq, ack;
  760.     short act = td->td_act;
  761.     short req = td->td_req;
  762.     int len, flags, win, timer;
  763.  
  764.     (void) sprintf(buf,"%03d %s:%s ", (ntohl(td->td_time)/10) % 1000,
  765.             tcpstates[td->td_ostate], tanames[act]);
  766.     Wputs(buf, W_DEBUG);
  767.  
  768.     switch (act) {
  769.     case TA_INPUT:
  770.     case TA_OUTPUT:
  771.     case TA_DROP:
  772.         (void) sprintf(buf,"(src=%s,%d, dst=%s,%d)\n\t",
  773.             inet_ntoa(ti->ti_src), ntohs(ti->ti_sport),
  774.             inet_ntoa(ti->ti_dst), ntohs(ti->ti_dport));
  775.         Wputs(buf, W_DEBUG);
  776.  
  777.         seq = ti->ti_seq;
  778.         ack = ti->ti_ack;
  779.         len = ti->ti_len;
  780.         win = ti->ti_win;
  781.         if (act == TA_OUTPUT) {
  782.             seq = ntohl(seq);
  783.             ack = ntohl(ack);
  784.             len = ntohs(len);
  785.             win = ntohs(win);
  786.         }
  787.         if (act == TA_OUTPUT)
  788.             len -= sizeof (struct tcphdr);
  789.         if (len)
  790.             (void) sprintf(buf,"[%x..%x)@%x", seq, seq+len, ack);
  791.         else
  792.             (void) sprintf(buf,"%x@%x", seq, ack);
  793.  
  794.         Wputs(buf, W_DEBUG);
  795.         if (win) {
  796.             (void) sprintf(buf,"(win=%x)", win);
  797.             Wputs(buf, W_DEBUG);
  798.         }
  799.  
  800.         if (flags = ti->ti_flags) {
  801.             Wputs(" flags=",W_DEBUG);
  802.             Wputs(flagprint((u_short)flags, Th_flags), W_DEBUG);
  803.         }
  804.         break;
  805.  
  806.     case TA_USER:
  807.         timer = req >> 8;
  808.         req &= 0xff;
  809.         (void) sprintf(buf,"%s", prurequests[req]);
  810.         Wputs(buf, W_DEBUG);
  811.         if (req == PRU_SLOWTIMO || req == PRU_FASTTIMO) {
  812.             (void) sprintf(buf,"<%s>", tcptimers[timer]);
  813.             Wputs(buf, W_DEBUG);
  814.         }
  815.         break;
  816.     }
  817.     (void) sprintf(buf," -> %s\n", tcpstates[td->td_cb.t_state]);
  818.     Wputs(buf,W_DEBUG);
  819. }
  820.