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