]> git.saurik.com Git - apple/network_cmds.git/blob - netstat.tproj/inet.c
network_cmds-433.tar.gz
[apple/network_cmds.git] / netstat.tproj / inet.c
1 /*
2 * Copyright (c) 2008-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 ** @APPLE_OSREFERENCE_LICENSE_HEADER_END@
26 */
27 /*
28 * Copyright (c) 1983, 1988, 1993, 1995
29 * The Regents of the University of California. All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 */
59
60 #ifndef lint
61 /*
62 static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95";
63 */
64 static const char rcsid[] =
65 "$Id: inet.c,v 1.9 2006/04/04 04:36:27 lindak Exp $";
66 #endif /* not lint */
67
68 #include <sys/param.h>
69 #include <sys/queue.h>
70 #include <sys/socket.h>
71 #include <sys/socketvar.h>
72 #include <sys/sysctl.h>
73
74 #include <net/route.h>
75 #include <net/if_arp.h>
76 #include <netinet/in.h>
77 #include <netinet/in_systm.h>
78 #include <netinet/ip.h>
79 #ifdef INET6
80 #include <netinet/ip6.h>
81 #endif /* INET6 */
82 #include <netinet/in_pcb.h>
83 #include <netinet/ip_icmp.h>
84 #include <netinet/icmp_var.h>
85 #include <netinet/igmp_var.h>
86 #include <netinet/ip_var.h>
87 #include <netinet/tcp.h>
88 #include <netinet/tcpip.h>
89 #include <netinet/tcp_seq.h>
90 #define TCPSTATES
91 #include <netinet/tcp_fsm.h>
92 #include <netinet/tcp_var.h>
93 #include <netinet/udp.h>
94 #include <netinet/udp_var.h>
95
96 #include <arpa/inet.h>
97 #include <err.h>
98 #include <errno.h>
99 #include <netdb.h>
100 #include <stdio.h>
101 #include <stdlib.h>
102 #include <stdint.h>
103 #include <string.h>
104 #include <unistd.h>
105 #include "netstat.h"
106
107 #ifdef __APPLE__
108 #include <TargetConditionals.h>
109 #endif
110
111 #define ROUNDUP64(a) \
112 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint64_t) - 1))) : sizeof(uint64_t))
113 #define ADVANCE64(x, n) (((char *)x) += ROUNDUP64(n))
114
115 char *inetname (struct in_addr *);
116 void inetprint (struct in_addr *, int, char *, int);
117 #ifdef INET6
118 extern void inet6print (struct in6_addr *, int, char *, int);
119 static int udp_done, tcp_done;
120 extern int mptcp_done;
121 #endif /* INET6 */
122
123 #ifdef SRVCACHE
124 typedef struct __table_private table_t;
125
126 extern table_t *_nc_table_new(uint32_t n);
127 extern void _nc_table_free(table_t *tin);
128
129 extern void _nc_table_insert(table_t *t, const char *key, void *datum);
130 extern void *_nc_table_find(table_t *t, const char *key);
131 extern void _nc_table_delete(table_t *t, const char *key);
132
133 static table_t *_serv_cache = NULL;
134
135 /*
136 * Read and cache all known services
137 */
138 static void
139 _serv_cache_open()
140 {
141 struct servent *s;
142 char *key, *name, *test;
143
144 if (_serv_cache != NULL) return;
145
146 _serv_cache = _nc_table_new(8192);
147 setservent(0);
148
149 while (NULL != (s = getservent()))
150 {
151 if (s->s_name == NULL) continue;
152 key = NULL;
153 asprintf(&key, "%hu/%s", (unsigned short)ntohs(s->s_port), s->s_proto);
154 name = strdup(s->s_name);
155 test = _nc_table_find(_serv_cache, key);
156 if (test == NULL) _nc_table_insert(_serv_cache, key, name);
157 free(key);
158 }
159
160 endservent();
161 }
162
163 void
164 _serv_cache_close()
165 {
166 _nc_table_free(_serv_cache);
167 _serv_cache = NULL;
168 }
169
170 struct servent *
171 _serv_cache_getservbyport(int port, char *proto)
172 {
173 static struct servent s;
174 char *key;
175 unsigned short p;
176
177 _serv_cache_open();
178
179 memset(&s, 0, sizeof(struct servent));
180 asprintf(&key, "%u/%s", port, (proto == NULL) ? "udp" : proto);
181
182 s.s_name = _nc_table_find(_serv_cache, key);
183 free(key);
184 if (s.s_name == NULL) return NULL;
185
186 p = port;
187 s.s_port = htons(p);
188 s.s_proto = proto;
189 return &s;
190 }
191
192 #endif /* SRVCACHE */
193
194 /*
195 * Print a summary of connections related to an Internet
196 * protocol. For TCP, also give state of connection.
197 * Listening processes (aflag) are suppressed unless the
198 * -a (all) flag is specified.
199 */
200
201 struct xgen_n {
202 u_int32_t xgn_len; /* length of this structure */
203 u_int32_t xgn_kind; /* number of PCBs at this time */
204 };
205
206 #define ALL_XGN_KIND_INP (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_INPCB)
207 #define ALL_XGN_KIND_TCP (ALL_XGN_KIND_INP | XSO_TCPCB)
208
209 void
210 protopr(uint32_t proto, /* for sysctl version we pass proto # */
211 char *name, int af)
212 {
213 int istcp;
214 static int first = 1;
215 char *buf, *next;
216 const char *mibvar;
217 struct xinpgen *xig, *oxig;
218 struct xgen_n *xgn;
219 size_t len;
220 struct xtcpcb_n *tp = NULL;
221 struct xinpcb_n *inp = NULL;
222 struct xsocket_n *so = NULL;
223 struct xsockbuf_n *so_rcv = NULL;
224 struct xsockbuf_n *so_snd = NULL;
225 struct xsockstat_n *so_stat = NULL;
226 int which = 0;
227
228 istcp = 0;
229 switch (proto) {
230 case IPPROTO_TCP:
231 #ifdef INET6
232 if (tcp_done != 0)
233 return;
234 else
235 tcp_done = 1;
236 #endif
237 istcp = 1;
238 mibvar = "net.inet.tcp.pcblist_n";
239 break;
240 case IPPROTO_UDP:
241 #ifdef INET6
242 if (udp_done != 0)
243 return;
244 else
245 udp_done = 1;
246 #endif
247 mibvar = "net.inet.udp.pcblist_n";
248 break;
249 case IPPROTO_DIVERT:
250 mibvar = "net.inet.divert.pcblist_n";
251 break;
252 default:
253 mibvar = "net.inet.raw.pcblist_n";
254 break;
255 }
256 len = 0;
257 if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
258 if (errno != ENOENT)
259 warn("sysctl: %s", mibvar);
260 return;
261 }
262 if ((buf = malloc(len)) == 0) {
263 warn("malloc %lu bytes", (u_long)len);
264 return;
265 }
266 if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
267 warn("sysctl: %s", mibvar);
268 free(buf);
269 return;
270 }
271
272 /*
273 * Bail-out to avoid logic error in the loop below when
274 * there is in fact no more control block to process
275 */
276 if (len <= sizeof(struct xinpgen)) {
277 free(buf);
278 return;
279 }
280
281 oxig = xig = (struct xinpgen *)buf;
282 for (next = buf + ROUNDUP64(xig->xig_len); next < buf + len; next += ROUNDUP64(xgn->xgn_len)) {
283
284 xgn = (struct xgen_n*)next;
285 if (xgn->xgn_len <= sizeof(struct xinpgen))
286 break;
287
288 if ((which & xgn->xgn_kind) == 0) {
289 which |= xgn->xgn_kind;
290 switch (xgn->xgn_kind) {
291 case XSO_SOCKET:
292 so = (struct xsocket_n *)xgn;
293 break;
294 case XSO_RCVBUF:
295 so_rcv = (struct xsockbuf_n *)xgn;
296 break;
297 case XSO_SNDBUF:
298 so_snd = (struct xsockbuf_n *)xgn;
299 break;
300 case XSO_STATS:
301 so_stat = (struct xsockstat_n *)xgn;
302 break;
303 case XSO_INPCB:
304 inp = (struct xinpcb_n *)xgn;
305 break;
306 case XSO_TCPCB:
307 tp = (struct xtcpcb_n *)xgn;
308 break;
309 default:
310 printf("unexpected kind %d\n", xgn->xgn_kind);
311 break;
312 }
313 } else {
314 if (vflag)
315 printf("got %d twice\n", xgn->xgn_kind);
316 }
317
318 if ((istcp && which != ALL_XGN_KIND_TCP) || (!istcp && which != ALL_XGN_KIND_INP))
319 continue;
320 which = 0;
321
322 /* Ignore sockets for protocols other than the desired one. */
323 if (so->xso_protocol != (int)proto)
324 continue;
325
326 /* Ignore PCBs which were freed during copyout. */
327 if (inp->inp_gencnt > oxig->xig_gen)
328 continue;
329
330 if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
331 #ifdef INET6
332 || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
333 #endif /* INET6 */
334 || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
335 #ifdef INET6
336 && (inp->inp_vflag &
337 INP_IPV6) == 0
338 #endif /* INET6 */
339 ))
340 )
341 continue;
342
343 /*
344 * Local address is not an indication of listening socket or
345 * server sockey but just rather the socket has been bound.
346 * That why many UDP sockets were not displayed in the original code.
347 */
348 if (!aflag && istcp && tp->t_state <= TCPS_LISTEN)
349 continue;
350
351 if (Lflag && !so->so_qlimit)
352 continue;
353
354 if (first) {
355 if (!Lflag) {
356 printf("Active Internet connections");
357 if (aflag)
358 printf(" (including servers)");
359 } else
360 printf(
361 "Current listen queue sizes (qlen/incqlen/maxqlen)");
362 putchar('\n');
363 if (Aflag) {
364 #if !TARGET_OS_EMBEDDED
365 printf("%-16.16s ", "Socket");
366 #else
367 printf("%-8.8s ", "Socket");
368 #endif
369 printf("%-9.9s", "Flowhash");
370 }
371 if (Lflag)
372 printf("%-14.14s %-22.22s\n",
373 "Listen", "Local Address");
374 else {
375 printf((Aflag && !Wflag) ?
376 "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %-11.11s" :
377 "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %-11.11s",
378 "Proto", "Recv-Q", "Send-Q",
379 "Local Address", "Foreign Address",
380 "(state)");
381 if (bflag > 0)
382 printf(" %10.10s %10.10s", "rxbytes", "txbytes");
383 if (prioflag >= 0)
384 printf(" %7.7s[%1d] %7.7s[%1d]", "rxbytes", prioflag, "txbytes", prioflag);
385 printf("\n");
386 }
387 first = 0;
388 }
389 if (Aflag) {
390 if (istcp)
391 #if !TARGET_OS_EMBEDDED
392 printf("%16lx ", (u_long)inp->inp_ppcb);
393 #else
394 printf("%8lx ", (u_long)inp->inp_ppcb);
395
396 #endif
397 else
398 #if !TARGET_OS_EMBEDDED
399 printf("%16lx ", (u_long)so->so_pcb);
400 #else
401 printf("%8lx ", (u_long)so->so_pcb);
402 #endif
403 printf("%8x ", inp->inp_flowhash);
404 }
405 if (Lflag) {
406 char buf[15];
407
408 snprintf(buf, 15, "%d/%d/%d", so->so_qlen,
409 so->so_incqlen, so->so_qlimit);
410 printf("%-14.14s ", buf);
411 }
412 else {
413 const char *vchar;
414
415 #ifdef INET6
416 if ((inp->inp_vflag & INP_IPV6) != 0)
417 vchar = ((inp->inp_vflag & INP_IPV4) != 0)
418 ? "46" : "6 ";
419 else
420 #endif
421 vchar = ((inp->inp_vflag & INP_IPV4) != 0)
422 ? "4 " : " ";
423
424 printf("%-3.3s%-2.2s %6u %6u ", name, vchar,
425 so_rcv->sb_cc,
426 so_snd->sb_cc);
427 }
428 if (nflag) {
429 if (inp->inp_vflag & INP_IPV4) {
430 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
431 name, 1);
432 if (!Lflag)
433 inetprint(&inp->inp_faddr,
434 (int)inp->inp_fport, name, 1);
435 }
436 #ifdef INET6
437 else if (inp->inp_vflag & INP_IPV6) {
438 inet6print(&inp->in6p_laddr,
439 (int)inp->inp_lport, name, 1);
440 if (!Lflag)
441 inet6print(&inp->in6p_faddr,
442 (int)inp->inp_fport, name, 1);
443 } /* else nothing printed now */
444 #endif /* INET6 */
445 } else if (inp->inp_flags & INP_ANONPORT) {
446 if (inp->inp_vflag & INP_IPV4) {
447 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
448 name, 1);
449 if (!Lflag)
450 inetprint(&inp->inp_faddr,
451 (int)inp->inp_fport, name, 0);
452 }
453 #ifdef INET6
454 else if (inp->inp_vflag & INP_IPV6) {
455 inet6print(&inp->in6p_laddr,
456 (int)inp->inp_lport, name, 1);
457 if (!Lflag)
458 inet6print(&inp->in6p_faddr,
459 (int)inp->inp_fport, name, 0);
460 } /* else nothing printed now */
461 #endif /* INET6 */
462 } else {
463 if (inp->inp_vflag & INP_IPV4) {
464 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
465 name, 0);
466 if (!Lflag)
467 inetprint(&inp->inp_faddr,
468 (int)inp->inp_fport, name,
469 inp->inp_lport !=
470 inp->inp_fport);
471 }
472 #ifdef INET6
473 else if (inp->inp_vflag & INP_IPV6) {
474 inet6print(&inp->in6p_laddr,
475 (int)inp->inp_lport, name, 0);
476 if (!Lflag)
477 inet6print(&inp->in6p_faddr,
478 (int)inp->inp_fport, name,
479 inp->inp_lport !=
480 inp->inp_fport);
481 } /* else nothing printed now */
482 #endif /* INET6 */
483 }
484 if (istcp && !Lflag) {
485 if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
486 printf("%-11d", tp->t_state);
487 else {
488 printf("%-11s", tcpstates[tp->t_state]);
489 #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
490 /* Show T/TCP `hidden state' */
491 if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN))
492 putchar('*');
493 #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
494 }
495 }
496 if (!istcp)
497 printf("%-11s", " ");
498 if (bflag > 0) {
499 int i;
500 u_int64_t rxbytes = 0;
501 u_int64_t txbytes = 0;
502
503 for (i = 0; i < SO_TC_STATS_MAX; i++) {
504 rxbytes += so_stat->xst_tc_stats[i].rxbytes;
505 txbytes += so_stat->xst_tc_stats[i].txbytes;
506 }
507
508 printf(" %10llu %10llu", rxbytes, txbytes);
509 }
510 if (prioflag >= 0) {
511 printf(" %10llu %10llu",
512 prioflag < SO_TC_STATS_MAX ? so_stat->xst_tc_stats[prioflag].rxbytes : 0,
513 prioflag < SO_TC_STATS_MAX ? so_stat->xst_tc_stats[prioflag].txbytes : 0);
514 }
515 putchar('\n');
516 }
517 if (xig != oxig && xig->xig_gen != oxig->xig_gen) {
518 if (oxig->xig_count > xig->xig_count) {
519 printf("Some %s sockets may have been deleted.\n",
520 name);
521 } else if (oxig->xig_count < xig->xig_count) {
522 printf("Some %s sockets may have been created.\n",
523 name);
524 } else {
525 printf("Some %s sockets may have been created or deleted",
526 name);
527 }
528 }
529 free(buf);
530 }
531
532 /*
533 * Dump TCP statistics structure.
534 */
535 void
536 tcp_stats(uint32_t off , char *name, int af)
537 {
538 static struct tcpstat ptcpstat;
539 struct tcpstat tcpstat;
540 size_t len = sizeof tcpstat;
541 static uint32_t r_swcsum, pr_swcsum;
542 static uint32_t t_swcsum, pt_swcsum;
543
544 if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
545 warn("sysctl: net.inet.tcp.stats");
546 return;
547 }
548
549 #ifdef INET6
550 if (tcp_done != 0 && interval == 0)
551 return;
552 else
553 tcp_done = 1;
554 #endif
555
556 if (interval && vflag > 0)
557 print_time();
558 printf ("%s:\n", name);
559
560 #define TCPDIFF(f) (tcpstat.f - ptcpstat.f)
561 #define p(f, m) if (TCPDIFF(f) || sflag <= 1) \
562 printf(m, TCPDIFF(f), plural(TCPDIFF(f)))
563 #define p1a(f, m) if (TCPDIFF(f) || sflag <= 1) \
564 printf(m, TCPDIFF(f))
565 #define p2(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
566 printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2), plural(TCPDIFF(f2)))
567 #define p2a(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
568 printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2))
569 #define p3(f, m) if (TCPDIFF(f) || sflag <= 1) \
570 printf(m, TCPDIFF(f), plurales(TCPDIFF(f)))
571
572 p(tcps_sndtotal, "\t%u packet%s sent\n");
573 p2(tcps_sndpack,tcps_sndbyte,
574 "\t\t%u data packet%s (%u byte%s)\n");
575 p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
576 "\t\t%u data packet%s (%u byte%s) retransmitted\n");
577 p(tcps_mturesent, "\t\t%u resend%s initiated by MTU discovery\n");
578 p2a(tcps_sndacks, tcps_delack,
579 "\t\t%u ack-only packet%s (%u delayed)\n");
580 p(tcps_sndurg, "\t\t%u URG only packet%s\n");
581 p(tcps_sndprobe, "\t\t%u window probe packet%s\n");
582 p(tcps_sndwinup, "\t\t%u window update packet%s\n");
583 p(tcps_sndctrl, "\t\t%u control packet%s\n");
584 p(tcps_fcholdpacket, "\t\t%u data packet%s sent after flow control\n");
585 t_swcsum = tcpstat.tcps_snd_swcsum + tcpstat.tcps_snd6_swcsum;
586 if ((t_swcsum - pt_swcsum) || sflag <= 1)
587 printf("\t\t%u checksummed in software\n", (t_swcsum - pt_swcsum));
588 p2(tcps_snd_swcsum, tcps_snd_swcsum_bytes,
589 "\t\t\t%u segment%s (%u byte%s) over IPv4\n");
590 #if INET6
591 p2(tcps_snd6_swcsum, tcps_snd6_swcsum_bytes,
592 "\t\t\t%u segment%s (%u byte%s) over IPv6\n");
593 #endif /* INET6 */
594 p(tcps_rcvtotal, "\t%u packet%s received\n");
595 p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%u ack%s (for %u byte%s)\n");
596 p(tcps_rcvdupack, "\t\t%u duplicate ack%s\n");
597 p(tcps_rcvacktoomuch, "\t\t%u ack%s for unsent data\n");
598 p2(tcps_rcvpack, tcps_rcvbyte,
599 "\t\t%u packet%s (%u byte%s) received in-sequence\n");
600 p2(tcps_rcvduppack, tcps_rcvdupbyte,
601 "\t\t%u completely duplicate packet%s (%u byte%s)\n");
602 p(tcps_pawsdrop, "\t\t%u old duplicate packet%s\n");
603 p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
604 "\t\t%u packet%s with some dup. data (%u byte%s duped)\n");
605 p2(tcps_rcvoopack, tcps_rcvoobyte,
606 "\t\t%u out-of-order packet%s (%u byte%s)\n");
607 p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
608 "\t\t%u packet%s (%u byte%s) of data after window\n");
609 p(tcps_rcvwinprobe, "\t\t%u window probe%s\n");
610 p(tcps_rcvwinupd, "\t\t%u window update packet%s\n");
611 p(tcps_rcvafterclose, "\t\t%u packet%s received after close\n");
612 p(tcps_badrst, "\t\t%u bad reset%s\n");
613 p(tcps_rcvbadsum, "\t\t%u discarded for bad checksum%s\n");
614 r_swcsum = tcpstat.tcps_rcv_swcsum + tcpstat.tcps_rcv6_swcsum;
615 if ((r_swcsum - pr_swcsum) || sflag <= 1)
616 printf("\t\t%u checksummed in software\n",
617 (r_swcsum - pr_swcsum));
618 p2(tcps_rcv_swcsum, tcps_rcv_swcsum_bytes,
619 "\t\t\t%u segment%s (%u byte%s) over IPv4\n");
620 #if INET6
621 p2(tcps_rcv6_swcsum, tcps_rcv6_swcsum_bytes,
622 "\t\t\t%u segment%s (%u byte%s) over IPv6\n");
623 #endif /* INET6 */
624 p(tcps_rcvbadoff, "\t\t%u discarded for bad header offset field%s\n");
625 p1a(tcps_rcvshort, "\t\t%u discarded because packet too short\n");
626 p(tcps_connattempt, "\t%u connection request%s\n");
627 p(tcps_accepts, "\t%u connection accept%s\n");
628 p(tcps_badsyn, "\t%u bad connection attempt%s\n");
629 p(tcps_listendrop, "\t%u listen queue overflow%s\n");
630 p(tcps_connects, "\t%u connection%s established (including accepts)\n");
631 p2(tcps_closed, tcps_drops,
632 "\t%u connection%s closed (including %u drop%s)\n");
633 p(tcps_cachedrtt, "\t\t%u connection%s updated cached RTT on close\n");
634 p(tcps_cachedrttvar,
635 "\t\t%u connection%s updated cached RTT variance on close\n");
636 p(tcps_cachedssthresh,
637 "\t\t%u connection%s updated cached ssthresh on close\n");
638 p(tcps_conndrops, "\t%u embryonic connection%s dropped\n");
639 p2(tcps_rttupdated, tcps_segstimed,
640 "\t%u segment%s updated rtt (of %u attempt%s)\n");
641 p(tcps_rexmttimeo, "\t%u retransmit timeout%s\n");
642 p(tcps_timeoutdrop, "\t\t%u connection%s dropped by rexmit timeout\n");
643 p(tcps_rxtfindrop, "\t\t%u connection%s dropped after retransmitting FIN\n");
644 p(tcps_persisttimeo, "\t%u persist timeout%s\n");
645 p(tcps_persistdrop, "\t\t%u connection%s dropped by persist timeout\n");
646 p(tcps_keeptimeo, "\t%u keepalive timeout%s\n");
647 p(tcps_keepprobe, "\t\t%u keepalive probe%s sent\n");
648 p(tcps_keepdrops, "\t\t%u connection%s dropped by keepalive\n");
649 p(tcps_predack, "\t%u correct ACK header prediction%s\n");
650 p(tcps_preddat, "\t%u correct data packet header prediction%s\n");
651 #ifdef TCP_MAX_SACK
652 /* TCP_MAX_SACK indicates the header has the SACK structures */
653 p(tcps_sack_recovery_episode, "\t%u SACK recovery episode%s\n");
654 p(tcps_sack_rexmits,
655 "\t%u segment rexmit%s in SACK recovery episodes\n");
656 p(tcps_sack_rexmit_bytes,
657 "\t%u byte rexmit%s in SACK recovery episodes\n");
658 p(tcps_sack_rcv_blocks,
659 "\t%u SACK option%s (SACK blocks) received\n");
660 p(tcps_sack_send_blocks, "\t%u SACK option%s (SACK blocks) sent\n");
661 p1a(tcps_sack_sboverflow, "\t%u SACK scoreboard overflow\n");
662 #endif /* TCP_MAX_SACK */
663
664 p(tcps_coalesced_pack, "\t%u LRO coalesced packet%s\n");
665 p(tcps_flowtbl_full, "\t\t%u time%s LRO flow table was full\n");
666 p(tcps_flowtbl_collision, "\t\t%u collision%s in LRO flow table\n");
667 p(tcps_lro_twopack, "\t\t%u time%s LRO coalesced 2 packets\n");
668 p(tcps_lro_multpack, "\t\t%u time%s LRO coalesced 3 or 4 packets\n");
669 p(tcps_lro_largepack, "\t\t%u time%s LRO coalesced 5 or more packets\n");
670
671 p(tcps_limited_txt, "\t%u limited transmit%s done\n");
672 p(tcps_early_rexmt, "\t%u early retransmit%s done\n");
673 p(tcps_sack_ackadv, "\t%u time%s cumulative ack advanced along with SACK\n");
674
675 if (interval > 0) {
676 bcopy(&tcpstat, &ptcpstat, len);
677 pr_swcsum = r_swcsum;
678 pt_swcsum = t_swcsum;
679 }
680
681 #undef TCPDIFF
682 #undef p
683 #undef p1a
684 #undef p2
685 #undef p2a
686 #undef p3
687 }
688
689 #if TARGET_OS_EMBEDDED
690 /*
691 * Dump MPTCP statistics
692 */
693 void
694 mptcp_stats(uint32_t off , char *name, int af)
695 {
696 static struct tcpstat ptcpstat;
697 struct tcpstat tcpstat;
698 size_t len = sizeof tcpstat;
699
700 if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
701 warn("sysctl: net.inet.tcp.stats");
702 return;
703 }
704
705 #ifdef INET6
706 if (mptcp_done != 0 && interval == 0)
707 return;
708 else
709 mptcp_done = 1;
710 #endif
711
712 if (interval && vflag > 0)
713 print_time();
714 printf ("%s:\n", name);
715
716 #define MPTCPDIFF(f) (tcpstat.f - ptcpstat.f)
717 #define p(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
718 printf(m, MPTCPDIFF(f), plural(MPTCPDIFF(f)))
719 #define p1a(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
720 printf(m, MPTCPDIFF(f))
721 #define p2(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
722 printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), \
723 MPTCPDIFF(f2), plural(MPTCPDIFF(f2)))
724 #define p2a(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
725 printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), MPTCPDIFF(f2))
726 #define p3(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
727 printf(m, MPTCPDIFF(f), plurales(MPTCPDIFF(f)))
728
729 p(tcps_mp_sndpacks, "\t%u data packet%s sent\n");
730 p(tcps_mp_sndbytes, "\t%u data byte%s sent\n");
731 p(tcps_mp_rcvtotal, "\t%u data packet%s received\n");
732 p(tcps_mp_rcvbytes, "\t%u data byte%s received\n");
733 p(tcps_invalid_mpcap, "\t%u packet%s with an invalid MPCAP option\n");
734 p(tcps_invalid_joins, "\t%u packet%s with an invalid MPJOIN option\n");
735 p(tcps_mpcap_fallback, "\t%u time%s primary subflow fell back to "
736 "TCP\n");
737 p(tcps_join_fallback, "\t%u time%s secondary subflow fell back to "
738 "TCP\n");
739 p(tcps_estab_fallback, "\t%u DSS option drop%s\n");
740 p(tcps_invalid_opt, "\t%u other invalid MPTCP option%s\n");
741 p(tcps_mp_reducedwin, "\t%u time%s the MPTCP subflow window was reduced\n");
742 p(tcps_mp_badcsum, "\t%u bad DSS checksum%s\n");
743 p(tcps_mp_oodata, "\t%u time%s received out of order data \n");
744 p3(tcps_mp_switches, "\t%u subflow switch%s\n");
745
746 if (interval > 0) {
747 bcopy(&tcpstat, &ptcpstat, len);
748 }
749
750 #undef MPTCPDIFF
751 #undef p
752 #undef p1a
753 #undef p2
754 #undef p2a
755 #undef p3
756 }
757 #endif /* TARGET_OS_EMBEDDED */
758
759 /*
760 * Dump UDP statistics structure.
761 */
762 void
763 udp_stats(uint32_t off , char *name, int af )
764 {
765 static struct udpstat pudpstat;
766 struct udpstat udpstat;
767 size_t len = sizeof udpstat;
768 uint32_t delivered;
769 static uint32_t r_swcsum, pr_swcsum;
770 static uint32_t t_swcsum, pt_swcsum;
771
772 if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, 0, 0) < 0) {
773 warn("sysctl: net.inet.udp.stats");
774 return;
775 }
776
777 #ifdef INET6
778 if (udp_done != 0 && interval == 0)
779 return;
780 else
781 udp_done = 1;
782 #endif
783
784 if (interval && vflag > 0)
785 print_time();
786 printf("%s:\n", name);
787
788 #define UDPDIFF(f) (udpstat.f - pudpstat.f)
789 #define p(f, m) if (UDPDIFF(f) || sflag <= 1) \
790 printf(m, UDPDIFF(f), plural(UDPDIFF(f)))
791 #define p1a(f, m) if (UDPDIFF(f) || sflag <= 1) \
792 printf(m, UDPDIFF(f))
793 #define p2(f1, f2, m) if (UDPDIFF(f1) || UDPDIFF(f2) || sflag <= 1) \
794 printf(m, UDPDIFF(f1), plural(UDPDIFF(f1)), UDPDIFF(f2), plural(UDPDIFF(f2)))
795 p(udps_ipackets, "\t%u datagram%s received\n");
796 p1a(udps_hdrops, "\t\t%u with incomplete header\n");
797 p1a(udps_badlen, "\t\t%u with bad data length field\n");
798 p1a(udps_badsum, "\t\t%u with bad checksum\n");
799 p1a(udps_nosum, "\t\t%u with no checksum\n");
800 r_swcsum = udpstat.udps_rcv_swcsum + udpstat.udps_rcv6_swcsum;
801 if ((r_swcsum - pr_swcsum) || sflag <= 1)
802 printf("\t\t%u checksummed in software\n", (r_swcsum - pr_swcsum));
803 p2(udps_rcv_swcsum, udps_rcv_swcsum_bytes,
804 "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
805 #if INET6
806 p2(udps_rcv6_swcsum, udps_rcv6_swcsum_bytes,
807 "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
808 #endif /* INET6 */
809 p1a(udps_noport, "\t\t%u dropped due to no socket\n");
810 p(udps_noportbcast,
811 "\t\t%u broadcast/multicast datagram%s undelivered\n");
812 /* the next statistic is cumulative in udps_noportbcast */
813 p(udps_filtermcast,
814 "\t\t%u time%s multicast source filter matched\n");
815 p1a(udps_fullsock, "\t\t%u dropped due to full socket buffers\n");
816 p1a(udpps_pcbhashmiss, "\t\t%u not for hashed pcb\n");
817 delivered = UDPDIFF(udps_ipackets) -
818 UDPDIFF(udps_hdrops) -
819 UDPDIFF(udps_badlen) -
820 UDPDIFF(udps_badsum) -
821 UDPDIFF(udps_noport) -
822 UDPDIFF(udps_noportbcast) -
823 UDPDIFF(udps_fullsock);
824 if (delivered || sflag <= 1)
825 printf("\t\t%u delivered\n", delivered);
826 p(udps_opackets, "\t%u datagram%s output\n");
827 t_swcsum = udpstat.udps_snd_swcsum + udpstat.udps_snd6_swcsum;
828 if ((t_swcsum - pt_swcsum) || sflag <= 1)
829 printf("\t\t%u checksummed in software\n", (t_swcsum - pt_swcsum));
830 p2(udps_snd_swcsum, udps_snd_swcsum_bytes,
831 "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
832 #if INET6
833 p2(udps_snd6_swcsum, udps_snd6_swcsum_bytes,
834 "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
835 #endif /* INET6 */
836
837 if (interval > 0) {
838 bcopy(&udpstat, &pudpstat, len);
839 pr_swcsum = r_swcsum;
840 pt_swcsum = t_swcsum;
841 }
842
843 #undef UDPDIFF
844 #undef p
845 #undef p1a
846 #undef p2
847 }
848
849 /*
850 * Dump IP statistics structure.
851 */
852 void
853 ip_stats(uint32_t off , char *name, int af )
854 {
855 static struct ipstat pipstat;
856 struct ipstat ipstat;
857 size_t len = sizeof ipstat;
858
859 if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, 0, 0) < 0) {
860 warn("sysctl: net.inet.ip.stats");
861 return;
862 }
863
864 if (interval && vflag > 0)
865 print_time();
866 printf("%s:\n", name);
867
868 #define IPDIFF(f) (ipstat.f - pipstat.f)
869 #define p(f, m) if (IPDIFF(f) || sflag <= 1) \
870 printf(m, IPDIFF(f), plural(IPDIFF(f)))
871 #define p1a(f, m) if (IPDIFF(f) || sflag <= 1) \
872 printf(m, IPDIFF(f))
873 #define p2(f1, f2, m) if (IPDIFF(f1) || IPDIFF(f2) || sflag <= 1) \
874 printf(m, IPDIFF(f1), plural(IPDIFF(f1)), IPDIFF(f2), plural(IPDIFF(f2)))
875
876 p(ips_total, "\t%u total packet%s received\n");
877 p(ips_badsum, "\t\t%u bad header checksum%s\n");
878 p2(ips_rcv_swcsum, ips_rcv_swcsum_bytes,
879 "\t\t%u header%s (%u byte%s) checksummed in software\n");
880 p1a(ips_toosmall, "\t\t%u with size smaller than minimum\n");
881 p1a(ips_tooshort, "\t\t%u with data size < data length\n");
882 p1a(ips_adj, "\t\t%u with data size > data length\n");
883 p(ips_adj_hwcsum_clr,
884 "\t\t\t%u packet%s forced to software checksum\n");
885 p1a(ips_toolong, "\t\t%u with ip length > max ip packet size\n");
886 p1a(ips_badhlen, "\t\t%u with header length < data size\n");
887 p1a(ips_badlen, "\t\t%u with data length < header length\n");
888 p1a(ips_badoptions, "\t\t%u with bad options\n");
889 p1a(ips_badvers, "\t\t%u with incorrect version number\n");
890 p(ips_fragments, "\t\t%u fragment%s received\n");
891 p1a(ips_fragdropped, "\t\t\t%u dropped (dup or out of space)\n");
892 p1a(ips_fragtimeout, "\t\t\t%u dropped after timeout\n");
893 p1a(ips_reassembled, "\t\t\t%u reassembled ok\n");
894 p(ips_delivered, "\t\t%u packet%s for this host\n");
895 p(ips_noproto, "\t\t%u packet%s for unknown/unsupported protocol\n");
896 p(ips_forward, "\t\t%u packet%s forwarded");
897 p(ips_fastforward, " (%u packet%s fast forwarded)");
898 if (IPDIFF(ips_forward) || sflag <= 1)
899 putchar('\n');
900 p(ips_cantforward, "\t\t%u packet%s not forwardable\n");
901 p(ips_notmember,
902 "\t\t%u packet%s received for unknown multicast group\n");
903 p(ips_redirectsent, "\t\t%u redirect%s sent\n");
904 p(ips_localout, "\t%u packet%s sent from this host\n");
905 p(ips_rawout, "\t\t%u packet%s sent with fabricated ip header\n");
906 p(ips_odropped,
907 "\t\t%u output packet%s dropped due to no bufs, etc.\n");
908 p(ips_noroute, "\t\t%u output packet%s discarded due to no route\n");
909 p(ips_fragmented, "\t\t%u output datagram%s fragmented\n");
910 p(ips_ofragments, "\t\t%u fragment%s created\n");
911 p(ips_cantfrag, "\t\t%u datagram%s that can't be fragmented\n");
912 p(ips_nogif, "\t\t%u tunneling packet%s that can't find gif\n");
913 p(ips_badaddr, "\t\t%u datagram%s with bad address in header\n");
914 p(ips_pktdropcntrl,
915 "\t\t%u packet%s dropped due to no bufs for control data\n");
916 p2(ips_snd_swcsum, ips_snd_swcsum_bytes,
917 "\t\t%u header%s (%u byte%s) checksummed in software\n");
918
919 if (interval > 0)
920 bcopy(&ipstat, &pipstat, len);
921
922 #undef IPDIFF
923 #undef p
924 #undef p1a
925 #undef p2
926 }
927
928 /*
929 * Dump ARP statistics structure.
930 */
931 void
932 arp_stats(uint32_t off, char *name, int af)
933 {
934 static struct arpstat parpstat;
935 struct arpstat arpstat;
936 size_t len = sizeof (arpstat);
937
938 if (sysctlbyname("net.link.ether.inet.stats", &arpstat,
939 &len, 0, 0) < 0) {
940 warn("sysctl: net.link.ether.inet.stats");
941 return;
942 }
943
944 if (interval && vflag > 0)
945 print_time();
946 printf("%s:\n", name);
947
948 #define ARPDIFF(f) (arpstat.f - parpstat.f)
949 #define p(f, m) if (ARPDIFF(f) || sflag <= 1) \
950 printf(m, ARPDIFF(f), plural(ARPDIFF(f)))
951 #define p2(f, m) if (ARPDIFF(f) || sflag <= 1) \
952 printf(m, ARPDIFF(f), pluralies(ARPDIFF(f)))
953
954 p(txrequests, "\t%u ARP request%s sent\n");
955 p2(txreplies, "\t%u ARP repl%s sent\n");
956 p(txannounces, "\t%u ARP announcement%s sent\n");
957 p(rxrequests, "\t%u ARP request%s received\n");
958 p2(rxreplies, "\t%u ARP repl%s received\n");
959 p(received, "\t%u total ARP packet%s received\n");
960 p(txconflicts, "\t%u ARP conflict probe%s sent\n");
961 p(invalidreqs, "\t%u invalid ARP resolve request%s\n");
962 p(reqnobufs, "\t%u total packet%s dropped due to lack of memory\n");
963 p(dropped, "\t%u total packet%s dropped due to no ARP entry\n");
964 p(purged, "\t%u total packet%s dropped during ARP entry removal\n");
965 p2(timeouts, "\t%u ARP entr%s timed out\n");
966 p(dupips, "\t%u Duplicate IP%s seen\n");
967
968 if (interval > 0)
969 bcopy(&arpstat, &parpstat, len);
970
971 #undef ARPDIFF
972 #undef p
973 #undef p2
974 }
975
976 static char *icmpnames[] = {
977 "echo reply",
978 "#1",
979 "#2",
980 "destination unreachable",
981 "source quench",
982 "routing redirect",
983 "#6",
984 "#7",
985 "echo",
986 "router advertisement",
987 "router solicitation",
988 "time exceeded",
989 "parameter problem",
990 "time stamp",
991 "time stamp reply",
992 "information request",
993 "information request reply",
994 "address mask request",
995 "address mask reply",
996 };
997
998 /*
999 * Dump ICMP statistics.
1000 */
1001 void
1002 icmp_stats(uint32_t off , char *name, int af )
1003 {
1004 static struct icmpstat picmpstat;
1005 struct icmpstat icmpstat;
1006 int i, first;
1007 int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
1008 size_t len;
1009
1010 mib[0] = CTL_NET;
1011 mib[1] = PF_INET;
1012 mib[2] = IPPROTO_ICMP;
1013 mib[3] = ICMPCTL_STATS;
1014
1015 len = sizeof icmpstat;
1016 memset(&icmpstat, 0, len);
1017 if (sysctl(mib, 4, &icmpstat, &len, (void *)0, 0) < 0)
1018 return; /* XXX should complain, but not traditional */
1019
1020 if (interval && vflag > 0)
1021 print_time();
1022 printf("%s:\n", name);
1023
1024 #define ICMPDIFF(f) (icmpstat.f - picmpstat.f)
1025 #define p(f, m) if (ICMPDIFF(f) || sflag <= 1) \
1026 printf(m, ICMPDIFF(f), plural(ICMPDIFF(f)))
1027 #define p1a(f, m) if (ICMPDIFF(f) || sflag <= 1) \
1028 printf(m, ICMPDIFF(f))
1029
1030 p(icps_error, "\t%u call%s to icmp_error\n");
1031 p(icps_oldicmp,
1032 "\t%u error%s not generated 'cuz old message was icmp\n");
1033 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
1034 if (ICMPDIFF(icps_outhist[i]) != 0) {
1035 if (first) {
1036 printf("\tOutput histogram:\n");
1037 first = 0;
1038 }
1039 printf("\t\t%s: %u\n", icmpnames[i],
1040 ICMPDIFF(icps_outhist[i]));
1041 }
1042 p(icps_badcode, "\t%u message%s with bad code fields\n");
1043 p(icps_tooshort, "\t%u message%s < minimum length\n");
1044 p(icps_checksum, "\t%u bad checksum%s\n");
1045 p(icps_badlen, "\t%u message%s with bad length\n");
1046 p1a(icps_bmcastecho, "\t%u multicast echo requests ignored\n");
1047 p1a(icps_bmcasttstamp, "\t%u multicast timestamp requests ignored\n");
1048 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
1049 if (ICMPDIFF(icps_inhist[i]) != 0) {
1050 if (first) {
1051 printf("\tInput histogram:\n");
1052 first = 0;
1053 }
1054 printf("\t\t%s: %u\n", icmpnames[i],
1055 ICMPDIFF(icps_inhist[i]));
1056 }
1057 p(icps_reflect, "\t%u message response%s generated\n");
1058
1059 #undef ICMPDIFF
1060 #undef p
1061 #undef p1a
1062 mib[3] = ICMPCTL_MASKREPL;
1063 len = sizeof i;
1064 if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
1065 return;
1066 printf("\tICMP address mask responses are %sabled\n",
1067 i ? "en" : "dis");
1068
1069 if (interval > 0)
1070 bcopy(&icmpstat, &picmpstat, sizeof (icmpstat));
1071 }
1072
1073 /*
1074 * Dump IGMP statistics structure.
1075 */
1076 void
1077 igmp_stats(uint32_t off , char *name, int af )
1078 {
1079 static struct igmpstat_v3 pigmpstat;
1080 struct igmpstat_v3 igmpstat;
1081 size_t len = sizeof igmpstat;
1082
1083 if (sysctlbyname("net.inet.igmp.v3stats", &igmpstat, &len, 0, 0) < 0) {
1084 warn("sysctl: net.inet.igmp.v3stats");
1085 return;
1086 }
1087
1088 if (igmpstat.igps_version != IGPS_VERSION_3) {
1089 warnx("%s: version mismatch (%d != %d)", __func__,
1090 igmpstat.igps_version, IGPS_VERSION_3);
1091 }
1092 if (igmpstat.igps_len != IGPS_VERSION3_LEN) {
1093 warnx("%s: size mismatch (%d != %d)", __func__,
1094 igmpstat.igps_len, IGPS_VERSION3_LEN);
1095 }
1096
1097 if (interval && vflag > 0)
1098 print_time();
1099 printf("%s:\n", name);
1100
1101 #define IGMPDIFF(f) ((uintmax_t)(igmpstat.f - pigmpstat.f))
1102 #define p64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
1103 printf(m, IGMPDIFF(f), plural(IGMPDIFF(f)))
1104 #define py64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
1105 printf(m, IGMPDIFF(f), IGMPDIFF(f) != 1 ? "ies" : "y")
1106
1107 p64(igps_rcv_total, "\t%ju message%s received\n");
1108 p64(igps_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
1109 p64(igps_rcv_badttl, "\t%ju message%s received with wrong TTL\n");
1110 p64(igps_rcv_badsum, "\t%ju message%s received with bad checksum\n");
1111 py64(igps_rcv_v1v2_queries, "\t%ju V1/V2 membership quer%s received\n");
1112 py64(igps_rcv_v3_queries, "\t%ju V3 membership quer%s received\n");
1113 py64(igps_rcv_badqueries,
1114 "\t%ju membership quer%s received with invalid field(s)\n");
1115 py64(igps_rcv_gen_queries, "\t%ju general quer%s received\n");
1116 py64(igps_rcv_group_queries, "\t%ju group quer%s received\n");
1117 py64(igps_rcv_gsr_queries, "\t%ju group-source quer%s received\n");
1118 py64(igps_drop_gsr_queries, "\t%ju group-source quer%s dropped\n");
1119 p64(igps_rcv_reports, "\t%ju membership report%s received\n");
1120 p64(igps_rcv_badreports,
1121 "\t%ju membership report%s received with invalid field(s)\n");
1122 p64(igps_rcv_ourreports,
1123 "\t%ju membership report%s received for groups to which we belong\n");
1124 p64(igps_rcv_nora, "\t%ju V3 report%s received without Router Alert\n");
1125 p64(igps_snd_reports, "\t%ju membership report%s sent\n");
1126
1127 if (interval > 0)
1128 bcopy(&igmpstat, &pigmpstat, len);
1129
1130 #undef IGMPDIFF
1131 #undef p64
1132 #undef py64
1133 }
1134
1135 /*
1136 * Pretty print an Internet address (net address + port).
1137 */
1138 void
1139 inetprint(struct in_addr *in, int port, char *proto, int numeric_port)
1140 {
1141 struct servent *sp = 0;
1142 char line[80], *cp;
1143 int width;
1144
1145 if (Wflag)
1146 snprintf(line, sizeof(line), "%s.", inetname(in));
1147 else
1148 snprintf(line, sizeof(line), "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
1149 cp = index(line, '\0');
1150 if (!numeric_port && port)
1151 #ifdef _SERVICE_CACHE_
1152 sp = _serv_cache_getservbyport(port, proto);
1153 #else
1154 sp = getservbyport((int)port, proto);
1155 #endif
1156 if (sp || port == 0)
1157 snprintf(cp, sizeof(line) - (cp - line), "%.15s ", sp ? sp->s_name : "*");
1158 else
1159 snprintf(cp, sizeof(line) - (cp - line), "%d ", ntohs((u_short)port));
1160 width = (Aflag && !Wflag) ? 18 : 22;
1161 if (Wflag)
1162 printf("%-*s ", width, line);
1163 else
1164 printf("%-*.*s ", width, width, line);
1165 }
1166
1167 /*
1168 * Construct an Internet address representation.
1169 * If the nflag has been supplied, give
1170 * numeric value, otherwise try for symbolic name.
1171 */
1172 char *
1173 inetname(struct in_addr *inp)
1174 {
1175 register char *cp;
1176 static char line[MAXHOSTNAMELEN];
1177 struct hostent *hp;
1178 struct netent *np;
1179
1180 cp = 0;
1181 if (!nflag && inp->s_addr != INADDR_ANY) {
1182 int net = inet_netof(*inp);
1183 int lna = inet_lnaof(*inp);
1184
1185 if (lna == INADDR_ANY) {
1186 np = getnetbyaddr(net, AF_INET);
1187 if (np)
1188 cp = np->n_name;
1189 }
1190 if (cp == 0) {
1191 hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
1192 if (hp) {
1193 cp = hp->h_name;
1194 //### trimdomain(cp, strlen(cp));
1195 }
1196 }
1197 }
1198 if (inp->s_addr == INADDR_ANY)
1199 strlcpy(line, "*", sizeof(line));
1200 else if (cp) {
1201 strncpy(line, cp, sizeof(line) - 1);
1202 line[sizeof(line) - 1] = '\0';
1203 } else {
1204 inp->s_addr = ntohl(inp->s_addr);
1205 #define C(x) ((u_int)((x) & 0xff))
1206 snprintf(line, sizeof(line), "%u.%u.%u.%u", C(inp->s_addr >> 24),
1207 C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
1208 }
1209 return (line);
1210 }