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
107char	*inetname (struct in_addr *);
108void	inetprint (struct in_addr *, int, char *, int);
109#ifdef INET6
110extern void	inet6print (struct in6_addr *, int, char *, int);
111static int udp_done, tcp_done;
112extern int mptcp_done;
113#endif /* INET6 */
114
115#ifdef SRVCACHE
116typedef struct __table_private table_t;
117
118extern table_t *_nc_table_new(uint32_t n);
119extern void _nc_table_free(table_t *tin);
120
121extern void _nc_table_insert(table_t *t, const char *key, void *datum);
122extern void *_nc_table_find(table_t *t, const char *key);
123extern void _nc_table_delete(table_t *t, const char *key);
124
125static table_t *_serv_cache = NULL;
126
127/*
128 * Read and cache all known services
129 */
130static 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
155void
156_serv_cache_close()
157{
158	_nc_table_free(_serv_cache);
159	_serv_cache = NULL;
160}
161
162struct 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
193struct 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
201void
202protopr(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 */
537void
538tcp_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 */
708void
709mptcp_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 */
776void
777udp_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 */
866void
867ip_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 */
945void
946arp_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
990static	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 */
1015void
1016icmp_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 */
1090void
1091igmp_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 */
1152void
1153inetprint(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 */
1186char *
1187inetname(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}
1225