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