1 /* $NetBSD: netstat.c,v 1.15 2000/01/05 11:59:12 itojun Exp $ */ 2 3 /*- 4 * Copyright (c) 1980, 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93"; 40 #endif 41 __RCSID("$NetBSD: netstat.c,v 1.15 2000/01/05 11:59:12 itojun Exp $"); 42 #endif /* not lint */ 43 44 /* 45 * netstat 46 */ 47 #include <sys/param.h> 48 #include <sys/socket.h> 49 #include <sys/socketvar.h> 50 #include <sys/mbuf.h> 51 #include <sys/protosw.h> 52 53 #include <netinet/in.h> 54 55 #include <arpa/inet.h> 56 #include <net/route.h> 57 58 #include <netinet/in_systm.h> 59 #include <netinet/ip.h> 60 #include <netinet/in_pcb.h> 61 #include <netinet/ip_icmp.h> 62 #include <netinet/icmp_var.h> 63 #include <netinet/ip_var.h> 64 #ifdef INET6 65 #include <netinet/ip6.h> 66 #include <netinet6/in6_pcb.h> 67 #endif 68 #include <netinet/tcp.h> 69 #include <netinet/tcpip.h> 70 #include <netinet/tcp_seq.h> 71 #define TCPSTATES 72 #include <netinet/tcp_fsm.h> 73 #include <netinet/tcp_timer.h> 74 #include <netinet/tcp_var.h> 75 #include <netinet/tcp_debug.h> 76 #include <netinet/udp.h> 77 #include <netinet/udp_var.h> 78 79 #include <netdb.h> 80 #include <stdlib.h> 81 #include <string.h> 82 #include <nlist.h> 83 #include <paths.h> 84 #include "systat.h" 85 #include "extern.h" 86 87 static void enter __P((struct inpcb *, struct socket *, int, char *)); 88 static const char *inetname __P((struct in_addr)); 89 static void inetprint __P((struct in_addr *, int, char *)); 90 #ifdef INET6 91 static void enter6 __P((struct in6pcb *, struct socket *, int, char *)); 92 static const char *inet6name __P((struct in6_addr *)); 93 static void inet6print __P((struct in6_addr *, int, char *)); 94 #endif 95 96 #define streq(a,b) (strcmp(a,b)==0) 97 98 struct netinfo { 99 struct netinfo *ni_forw, *ni_prev; 100 int ni_family; 101 short ni_line; /* line on screen */ 102 short ni_seen; /* 0 when not present in list */ 103 short ni_flags; 104 #define NIF_LACHG 0x1 /* local address changed */ 105 #define NIF_FACHG 0x2 /* foreign address changed */ 106 short ni_state; /* tcp state */ 107 char *ni_proto; /* protocol */ 108 struct in_addr ni_laddr; /* local address */ 109 #ifdef INET6 110 struct in6_addr ni_laddr6; /* local address */ 111 #endif 112 long ni_lport; /* local port */ 113 struct in_addr ni_faddr; /* foreign address */ 114 #ifdef INET6 115 struct in6_addr ni_faddr6; /* foreign address */ 116 #endif 117 long ni_fport; /* foreign port */ 118 long ni_rcvcc; /* rcv buffer character count */ 119 long ni_sndcc; /* snd buffer character count */ 120 }; 121 122 static struct { 123 struct netinfo *ni_forw, *ni_prev; 124 } netcb; 125 126 static int aflag = 0; 127 static int nflag = 0; 128 static int lastrow = 1; 129 130 WINDOW * 131 opennetstat() 132 { 133 134 sethostent(1); 135 setnetent(1); 136 return (subwin(stdscr, LINES-5-1, 0, 5, 0)); 137 } 138 139 void 140 closenetstat(w) 141 WINDOW *w; 142 { 143 struct netinfo *p; 144 145 endhostent(); 146 endnetent(); 147 p = (struct netinfo *)netcb.ni_forw; 148 while (p != (struct netinfo *)&netcb) { 149 if (p->ni_line != -1) 150 lastrow--; 151 p->ni_line = -1; 152 p = p->ni_forw; 153 } 154 if (w != NULL) { 155 wclear(w); 156 wrefresh(w); 157 delwin(w); 158 } 159 } 160 161 static struct nlist namelist[] = { 162 #define X_TCBTABLE 0 163 { "_tcbtable" }, 164 #define X_UDBTABLE 1 165 { "_udbtable" }, 166 #ifdef INET6 167 #define X_TCB6 2 168 { "_tcb6" }, 169 #define X_UDB6 3 170 { "_udb6" }, 171 #endif 172 { "" }, 173 }; 174 175 int 176 initnetstat() 177 { 178 if (kvm_nlist(kd, namelist)) { 179 nlisterr(namelist); 180 return(0); 181 } 182 if (namelist[X_TCBTABLE].n_value == 0) { 183 error("No symbols in namelist"); 184 return(0); 185 } 186 netcb.ni_forw = netcb.ni_prev = (struct netinfo *)&netcb; 187 protos = TCP|UDP; 188 return(1); 189 } 190 191 void 192 fetchnetstat() 193 { 194 struct inpcbtable pcbtable; 195 struct inpcb *head, *prev, *next; 196 struct netinfo *p; 197 struct inpcb inpcb; 198 struct socket sockb; 199 struct tcpcb tcpcb; 200 #ifdef INET6 201 struct in6pcb in6pcb; 202 struct in6pcb *head6, *prev6, *next6; 203 #endif 204 void *off; 205 int istcp; 206 207 if (namelist[X_TCBTABLE].n_value == 0) 208 return; 209 for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) 210 p->ni_seen = 0; 211 if (protos&TCP) { 212 off = NPTR(X_TCBTABLE); 213 istcp = 1; 214 } 215 else if (protos&UDP) { 216 off = NPTR(X_UDBTABLE); 217 istcp = 0; 218 } 219 else { 220 error("No protocols to display"); 221 return; 222 } 223 again: 224 KREAD(off, &pcbtable, sizeof pcbtable); 225 prev = head = (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue; 226 next = pcbtable.inpt_queue.cqh_first; 227 while (next != head) { 228 KREAD(next, &inpcb, sizeof (inpcb)); 229 if (inpcb.inp_queue.cqe_prev != prev) { 230 printf("prev = %p, head = %p, next = %p, inpcb...prev = %p\n", prev, head, next, inpcb.inp_queue.cqe_prev); 231 p = netcb.ni_forw; 232 for (; p != (struct netinfo *)&netcb; p = p->ni_forw) 233 p->ni_seen = 1; 234 error("Kernel state in transition"); 235 return; 236 } 237 prev = next; 238 next = inpcb.inp_queue.cqe_next; 239 240 if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) 241 continue; 242 if (nhosts && !checkhost(&inpcb)) 243 continue; 244 if (nports && !checkport(&inpcb)) 245 continue; 246 KREAD(inpcb.inp_socket, &sockb, sizeof (sockb)); 247 if (istcp) { 248 KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb)); 249 enter(&inpcb, &sockb, tcpcb.t_state, "tcp"); 250 } else 251 enter(&inpcb, &sockb, 0, "udp"); 252 } 253 if (istcp && (protos&UDP)) { 254 istcp = 0; 255 off = NPTR(X_UDBTABLE); 256 goto again; 257 } 258 259 #ifdef INET6 260 if (protos&TCP) { 261 off = NPTR(X_TCB6); 262 istcp = 1; 263 } 264 else if (protos&UDP) { 265 off = NPTR(X_UDB6); 266 istcp = 0; 267 } 268 else { 269 error("No protocols to display"); 270 return; 271 } 272 again6: 273 KREAD(off, &in6pcb, sizeof (struct in6pcb)); 274 prev6 = head6 = (struct in6pcb *)off; 275 next6 = in6pcb.in6p_next; 276 while (next6 != head6) { 277 KREAD(next6, &in6pcb, sizeof (in6pcb)); 278 if (in6pcb.in6p_prev != prev6) { 279 printf("prev = %p, head = %p, next = %p, inpcb...prev = %p\n", prev6, head6, next6, in6pcb.in6p_prev); 280 p = netcb.ni_forw; 281 for (; p != (struct netinfo *)&netcb; p = p->ni_forw) 282 p->ni_seen = 1; 283 error("Kernel state in transition"); 284 return; 285 } 286 prev6 = next6; 287 next6 = in6pcb.in6p_next; 288 289 if (!aflag && IN6_IS_ADDR_UNSPECIFIED(&in6pcb.in6p_laddr)) 290 continue; 291 if (nhosts && !checkhost6(&in6pcb)) 292 continue; 293 if (nports && !checkport6(&in6pcb)) 294 continue; 295 KREAD(in6pcb.in6p_socket, &sockb, sizeof (sockb)); 296 if (istcp) { 297 KREAD(in6pcb.in6p_ppcb, &tcpcb, sizeof (tcpcb)); 298 enter6(&in6pcb, &sockb, tcpcb.t_state, "tcp"); 299 } else 300 enter6(&in6pcb, &sockb, 0, "udp"); 301 } 302 if (istcp && (protos&UDP)) { 303 istcp = 0; 304 off = NPTR(X_UDB6); 305 goto again6; 306 } 307 #endif /*INET6*/ 308 } 309 310 static void 311 enter(inp, so, state, proto) 312 struct inpcb *inp; 313 struct socket *so; 314 int state; 315 char *proto; 316 { 317 struct netinfo *p; 318 319 /* 320 * Only take exact matches, any sockets with 321 * previously unbound addresses will be deleted 322 * below in the display routine because they 323 * will appear as ``not seen'' in the kernel 324 * data structures. 325 */ 326 for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) { 327 if (p->ni_family != AF_INET) 328 continue; 329 if (!streq(proto, p->ni_proto)) 330 continue; 331 if (p->ni_lport != inp->inp_lport || 332 p->ni_laddr.s_addr != inp->inp_laddr.s_addr) 333 continue; 334 if (p->ni_faddr.s_addr == inp->inp_faddr.s_addr && 335 p->ni_fport == inp->inp_fport) 336 break; 337 } 338 if (p == (struct netinfo *)&netcb) { 339 if ((p = malloc(sizeof(*p))) == NULL) { 340 error("Out of memory"); 341 return; 342 } 343 p->ni_prev = (struct netinfo *)&netcb; 344 p->ni_forw = netcb.ni_forw; 345 netcb.ni_forw->ni_prev = p; 346 netcb.ni_forw = p; 347 p->ni_line = -1; 348 p->ni_laddr = inp->inp_laddr; 349 p->ni_lport = inp->inp_lport; 350 p->ni_faddr = inp->inp_faddr; 351 p->ni_fport = inp->inp_fport; 352 p->ni_proto = proto; 353 p->ni_flags = NIF_LACHG|NIF_FACHG; 354 p->ni_family = AF_INET; 355 } 356 p->ni_rcvcc = so->so_rcv.sb_cc; 357 p->ni_sndcc = so->so_snd.sb_cc; 358 p->ni_state = state; 359 p->ni_seen = 1; 360 } 361 362 #ifdef INET6 363 static void 364 enter6(in6p, so, state, proto) 365 struct in6pcb *in6p; 366 struct socket *so; 367 int state; 368 char *proto; 369 { 370 struct netinfo *p; 371 372 /* 373 * Only take exact matches, any sockets with 374 * previously unbound addresses will be deleted 375 * below in the display routine because they 376 * will appear as ``not seen'' in the kernel 377 * data structures. 378 */ 379 for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) { 380 if (p->ni_family != AF_INET6) 381 continue; 382 if (!streq(proto, p->ni_proto)) 383 continue; 384 if (p->ni_lport != in6p->in6p_lport || 385 !IN6_ARE_ADDR_EQUAL(&p->ni_laddr6, &in6p->in6p_laddr)) 386 continue; 387 if (IN6_ARE_ADDR_EQUAL(&p->ni_faddr6, &in6p->in6p_faddr) && 388 p->ni_fport == in6p->in6p_fport) 389 break; 390 } 391 if (p == (struct netinfo *)&netcb) { 392 if ((p = malloc(sizeof(*p))) == NULL) { 393 error("Out of memory"); 394 return; 395 } 396 p->ni_prev = (struct netinfo *)&netcb; 397 p->ni_forw = netcb.ni_forw; 398 netcb.ni_forw->ni_prev = p; 399 netcb.ni_forw = p; 400 p->ni_line = -1; 401 p->ni_laddr6 = in6p->in6p_laddr; 402 p->ni_lport = in6p->in6p_lport; 403 p->ni_faddr6 = in6p->in6p_faddr; 404 p->ni_fport = in6p->in6p_fport; 405 p->ni_proto = proto; 406 p->ni_flags = NIF_LACHG|NIF_FACHG; 407 p->ni_family = AF_INET6; 408 } 409 p->ni_rcvcc = so->so_rcv.sb_cc; 410 p->ni_sndcc = so->so_snd.sb_cc; 411 p->ni_state = state; 412 p->ni_seen = 1; 413 } 414 #endif 415 416 /* column locations */ 417 #define LADDR 0 418 #define FADDR LADDR+23 419 #define PROTO FADDR+23 420 #define RCVCC PROTO+6 421 #define SNDCC RCVCC+7 422 #define STATE SNDCC+7 423 424 void 425 labelnetstat() 426 { 427 428 if (namelist[X_TCBTABLE].n_type == 0) 429 return; 430 wmove(wnd, 0, 0); wclrtobot(wnd); 431 mvwaddstr(wnd, 0, LADDR, "Local Address"); 432 mvwaddstr(wnd, 0, FADDR, "Foreign Address"); 433 mvwaddstr(wnd, 0, PROTO, "Proto"); 434 mvwaddstr(wnd, 0, RCVCC, "Recv-Q"); 435 mvwaddstr(wnd, 0, SNDCC, "Send-Q"); 436 mvwaddstr(wnd, 0, STATE, "(state)"); 437 } 438 439 void 440 shownetstat() 441 { 442 struct netinfo *p, *q; 443 444 /* 445 * First, delete any connections that have gone 446 * away and adjust the position of connections 447 * below to reflect the deleted line. 448 */ 449 p = netcb.ni_forw; 450 while (p != (struct netinfo *)&netcb) { 451 if (p->ni_line == -1 || p->ni_seen) { 452 p = p->ni_forw; 453 continue; 454 } 455 wmove(wnd, p->ni_line, 0); wdeleteln(wnd); 456 q = netcb.ni_forw; 457 for (; q != (struct netinfo *)&netcb; q = q->ni_forw) 458 if (q != p && q->ni_line > p->ni_line) { 459 q->ni_line--; 460 /* this shouldn't be necessary */ 461 q->ni_flags |= NIF_LACHG|NIF_FACHG; 462 } 463 lastrow--; 464 q = p->ni_forw; 465 p->ni_prev->ni_forw = p->ni_forw; 466 p->ni_forw->ni_prev = p->ni_prev; 467 free(p); 468 p = q; 469 } 470 /* 471 * Update existing connections and add new ones. 472 */ 473 for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) { 474 if (p->ni_line == -1) { 475 /* 476 * Add a new entry if possible. 477 */ 478 if (lastrow > getmaxy(wnd)) 479 continue; 480 p->ni_line = lastrow++; 481 p->ni_flags |= NIF_LACHG|NIF_FACHG; 482 } 483 if (p->ni_flags & NIF_LACHG) { 484 wmove(wnd, p->ni_line, LADDR); 485 switch (p->ni_family) { 486 case AF_INET: 487 inetprint(&p->ni_laddr, p->ni_lport, 488 p->ni_proto); 489 break; 490 #ifdef INET6 491 case AF_INET6: 492 inet6print(&p->ni_laddr6, p->ni_lport, 493 p->ni_proto); 494 break; 495 #endif 496 } 497 p->ni_flags &= ~NIF_LACHG; 498 } 499 if (p->ni_flags & NIF_FACHG) { 500 wmove(wnd, p->ni_line, FADDR); 501 switch (p->ni_family) { 502 case AF_INET: 503 inetprint(&p->ni_faddr, p->ni_fport, 504 p->ni_proto); 505 break; 506 #ifdef INET6 507 case AF_INET6: 508 inet6print(&p->ni_faddr6, p->ni_fport, 509 p->ni_proto); 510 break; 511 #endif 512 } 513 p->ni_flags &= ~NIF_FACHG; 514 } 515 mvwaddstr(wnd, p->ni_line, PROTO, p->ni_proto); 516 #ifdef INET6 517 if (p->ni_family == AF_INET6) 518 waddstr(wnd, "6"); 519 #endif 520 mvwprintw(wnd, p->ni_line, RCVCC, "%6d", p->ni_rcvcc); 521 mvwprintw(wnd, p->ni_line, SNDCC, "%6d", p->ni_sndcc); 522 if (streq(p->ni_proto, "tcp")) { 523 if (p->ni_state < 0 || p->ni_state >= TCP_NSTATES) 524 mvwprintw(wnd, p->ni_line, STATE, "%d", 525 p->ni_state); 526 else 527 mvwaddstr(wnd, p->ni_line, STATE, 528 tcpstates[p->ni_state]); 529 } 530 wclrtoeol(wnd); 531 } 532 if (lastrow < getmaxy(wnd)) { 533 wmove(wnd, lastrow, 0); wclrtobot(wnd); 534 wmove(wnd, getmaxy(wnd), 0); wdeleteln(wnd); /* XXX */ 535 } 536 } 537 538 /* 539 * Pretty print an Internet address (net address + port). 540 * If the nflag was specified, use numbers instead of names. 541 */ 542 static void 543 inetprint(in, port, proto) 544 struct in_addr *in; 545 int port; 546 char *proto; 547 { 548 struct servent *sp = 0; 549 char line[80], *cp; 550 551 (void)snprintf(line, sizeof line, "%.*s.", 16, inetname(*in)); 552 cp = strchr(line, '\0'); 553 if (!nflag && port) 554 sp = getservbyport(port, proto); 555 if (sp || port == 0) 556 (void)snprintf(cp, line + sizeof line - cp, "%.8s", 557 sp ? sp->s_name : "*"); 558 else 559 (void)snprintf(cp, line + sizeof line - cp, "%d", 560 ntohs((u_short)port)); 561 /* pad to full column to clear any garbage */ 562 cp = strchr(line, '\0'); 563 while (cp - line < 22) 564 *cp++ = ' '; 565 *cp = '\0'; 566 waddstr(wnd, line); 567 } 568 569 #ifdef INET6 570 static void 571 inet6print(in6, port, proto) 572 struct in6_addr *in6; 573 int port; 574 char *proto; 575 { 576 struct servent *sp = 0; 577 char line[80], *cp; 578 579 (void)snprintf(line, sizeof line, "%.*s.", 16, inet6name(in6)); 580 cp = strchr(line, '\0'); 581 if (!nflag && port) 582 sp = getservbyport(port, proto); 583 if (sp || port == 0) 584 (void)snprintf(cp, line + sizeof line - cp, "%.8s", 585 sp ? sp->s_name : "*"); 586 else 587 (void)snprintf(cp, line + sizeof line - cp, "%d", 588 ntohs((u_short)port)); 589 /* pad to full column to clear any garbage */ 590 cp = strchr(line, '\0'); 591 while (cp - line < 22) 592 *cp++ = ' '; 593 *cp = '\0'; 594 waddstr(wnd, line); 595 } 596 #endif 597 598 /* 599 * Construct an Internet address representation. 600 * If the nflag has been supplied, give 601 * numeric value, otherwise try for symbolic name. 602 */ 603 static const char * 604 inetname(in) 605 struct in_addr in; 606 { 607 char *cp = 0; 608 static char line[50]; 609 struct hostent *hp; 610 struct netent *np; 611 612 if (!nflag && in.s_addr != INADDR_ANY) { 613 int net = inet_netof(in); 614 int lna = inet_lnaof(in); 615 616 if (lna == INADDR_ANY) { 617 np = getnetbyaddr(net, AF_INET); 618 if (np) 619 cp = np->n_name; 620 } 621 if (cp == 0) { 622 hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET); 623 if (hp) 624 cp = hp->h_name; 625 } 626 } 627 if (in.s_addr == INADDR_ANY) 628 strncpy(line, "*", sizeof(line) - 1); 629 else if (cp) 630 strncpy(line, cp, sizeof(line) - 1); 631 else { 632 in.s_addr = ntohl(in.s_addr); 633 #define C(x) ((x) & 0xff) 634 (void)snprintf(line, sizeof line, "%u.%u.%u.%u", 635 C(in.s_addr >> 24), C(in.s_addr >> 16), 636 C(in.s_addr >> 8), C(in.s_addr)); 637 #undef C 638 } 639 line[sizeof(line) - 1] = '\0'; 640 return (line); 641 } 642 643 #ifdef INET6 644 static const char * 645 inet6name(in6) 646 struct in6_addr *in6; 647 { 648 static char line[NI_MAXHOST]; 649 struct sockaddr_in6 sin6; 650 int flags; 651 652 if (nflag) 653 flags = NI_NUMERICHOST; 654 else 655 flags = 0; 656 if (IN6_IS_ADDR_UNSPECIFIED(in6)) 657 return "*"; 658 memset(&sin6, 0, sizeof(sin6)); 659 sin6.sin6_family = AF_INET6; 660 sin6.sin6_len = sizeof(struct sockaddr_in6); 661 sin6.sin6_addr = *in6; 662 if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 663 line, sizeof(line), NULL, 0, flags) == 0) 664 return line; 665 return "?"; 666 } 667 #endif 668 669 /* please note: there are also some netstat commands in netcmds.c */ 670 671 void 672 netstat_all (args) 673 char *args; 674 { 675 aflag = !aflag; 676 fetchnetstat(); 677 shownetstat(); 678 refresh(); 679 } 680 681 void 682 netstat_names (args) 683 char *args; 684 { 685 struct netinfo *p; 686 687 if (nflag == 0) 688 return; 689 690 p = netcb.ni_forw; 691 for (; p != (struct netinfo *)&netcb; p = p->ni_forw) { 692 if (p->ni_line == -1) 693 continue; 694 p->ni_flags |= NIF_LACHG|NIF_FACHG; 695 } 696 nflag = 0; 697 wclear(wnd); 698 labelnetstat(); 699 shownetstat(); 700 refresh(); 701 } 702 703 void 704 netstat_numbers (args) 705 char *args; 706 { 707 struct netinfo *p; 708 709 if (nflag != 0) 710 return; 711 712 p = netcb.ni_forw; 713 for (; p != (struct netinfo *)&netcb; p = p->ni_forw) { 714 if (p->ni_line == -1) 715 continue; 716 p->ni_flags |= NIF_LACHG|NIF_FACHG; 717 } 718 nflag = 1; 719 wclear(wnd); 720 labelnetstat(); 721 shownetstat(); 722 refresh(); 723 } 724