xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c (revision 2c5ec7a875dcd76853e6618614e990f1e8cdd56d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright (c) 1990  Mentat Inc.
24  * netstat.c 2.2, last change 9/9/91
25  * MROUTING Revision 3.5
26  * Copyright 2018, Joyent, Inc.
27  */
28 
29 /*
30  * simple netstat based on snmp/mib-2 interface to the TCP/IP stack
31  *
32  * NOTES:
33  * 1. A comment "LINTED: (note 1)" appears before certain lines where
34  *    lint would have complained, "pointer cast may result in improper
35  *    alignment". These are lines where lint had suspected potential
36  *    improper alignment of a data structure; in each such situation
37  *    we have relied on the kernel guaranteeing proper alignment.
38  * 2. Some 'for' loops have been commented as "'for' loop 1", etc
39  *    because they have 'continue' or 'break' statements in their
40  *    bodies. 'continue' statements have been used inside some loops
41  *    where avoiding them would have led to deep levels of indentation.
42  *
43  * TODO:
44  *	Add ability to request subsets from kernel (with level = MIB2_IP;
45  *	name = 0 meaning everything for compatibility)
46  */
47 
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <stdarg.h>
51 #include <unistd.h>
52 #include <strings.h>
53 #include <string.h>
54 #include <errno.h>
55 #include <ctype.h>
56 #include <kstat.h>
57 #include <assert.h>
58 #include <locale.h>
59 #include <synch.h>
60 #include <thread.h>
61 
62 #include <sys/types.h>
63 #include <sys/stream.h>
64 #include <stropts.h>
65 #include <sys/strstat.h>
66 #include <sys/tihdr.h>
67 
68 #include <sys/socket.h>
69 #include <sys/sockio.h>
70 #include <netinet/in.h>
71 #include <net/if.h>
72 #include <net/route.h>
73 
74 #include <inet/mib2.h>
75 #include <inet/ip.h>
76 #include <inet/arp.h>
77 #include <inet/tcp.h>
78 #include <netinet/igmp_var.h>
79 #include <netinet/ip_mroute.h>
80 
81 #include <arpa/inet.h>
82 #include <netdb.h>
83 #include <fcntl.h>
84 #include <sys/systeminfo.h>
85 #include <arpa/inet.h>
86 
87 #include <netinet/dhcp.h>
88 #include <dhcpagent_ipc.h>
89 #include <dhcpagent_util.h>
90 #include <compat.h>
91 
92 #include <libtsnet.h>
93 #include <tsol/label.h>
94 
95 #include "statcommon.h"
96 
97 extern void	unixpr(kstat_ctl_t *kc);
98 
99 #define	STR_EXPAND	4
100 
101 #define	V4MASK_TO_V6(v4, v6)	((v6)._S6_un._S6_u32[0] = 0xfffffffful, \
102 				(v6)._S6_un._S6_u32[1] = 0xfffffffful, \
103 				(v6)._S6_un._S6_u32[2] = 0xfffffffful, \
104 				(v6)._S6_un._S6_u32[3] = (v4))
105 
106 #define	IN6_IS_V4MASK(v6)	((v6)._S6_un._S6_u32[0] == 0xfffffffful && \
107 				(v6)._S6_un._S6_u32[1] == 0xfffffffful && \
108 				(v6)._S6_un._S6_u32[2] == 0xfffffffful)
109 
110 /*
111  * This is used as a cushion in the buffer allocation directed by SIOCGLIFNUM.
112  * Because there's no locking between SIOCGLIFNUM and SIOCGLIFCONF, it's
113  * possible for an administrator to plumb new interfaces between those two
114  * calls, resulting in the failure of the latter.  This addition makes that
115  * less likely.
116  */
117 #define	LIFN_GUARD_VALUE	10
118 
119 typedef struct mib_item_s {
120 	struct mib_item_s	*next_item;
121 	int			group;
122 	int			mib_id;
123 	int			length;
124 	void			*valp;
125 } mib_item_t;
126 
127 struct	ifstat {
128 	uint64_t	ipackets;
129 	uint64_t	ierrors;
130 	uint64_t	opackets;
131 	uint64_t	oerrors;
132 	uint64_t	collisions;
133 };
134 
135 struct iflist {
136 	struct iflist	*next_if;
137 	char		ifname[LIFNAMSIZ];
138 	struct ifstat	tot;
139 };
140 
141 static	mib_item_t	*mibget(int sd);
142 static	void		mibfree(mib_item_t *firstitem);
143 static	int		mibopen(void);
144 static void		mib_get_constants(mib_item_t *item);
145 static mib_item_t	*mib_item_dup(mib_item_t *item);
146 static mib_item_t	*mib_item_diff(mib_item_t *item1,
147     mib_item_t *item2);
148 static void		mib_item_destroy(mib_item_t **item);
149 
150 static boolean_t	octetstrmatch(const Octet_t *a, const Octet_t *b);
151 static char		*octetstr(const Octet_t *op, int code,
152 			    char *dst, uint_t dstlen);
153 static char		*pr_addr(uint_t addr,
154 			    char *dst, uint_t dstlen);
155 static char		*pr_addrnz(ipaddr_t addr, char *dst, uint_t dstlen);
156 static char		*pr_addr6(const in6_addr_t *addr,
157 			    char *dst, uint_t dstlen);
158 static char		*pr_mask(uint_t addr,
159 			    char *dst, uint_t dstlen);
160 static char		*pr_prefix6(const struct in6_addr *addr,
161 			    uint_t prefixlen, char *dst, uint_t dstlen);
162 static char		*pr_ap(uint_t addr, uint_t port,
163 			    char *proto, char *dst, uint_t dstlen);
164 static char		*pr_ap6(const in6_addr_t *addr, uint_t port,
165 			    char *proto, char *dst, uint_t dstlen);
166 static char		*pr_net(uint_t addr, uint_t mask,
167 			    char *dst, uint_t dstlen);
168 static char		*pr_netaddr(uint_t addr, uint_t mask,
169 			    char *dst, uint_t dstlen);
170 static char		*fmodestr(uint_t fmode);
171 static char		*portname(uint_t port, char *proto,
172 			    char *dst, uint_t dstlen);
173 
174 static const char	*mitcp_state(int code,
175 			    const mib2_transportMLPEntry_t *attr);
176 static const char	*miudp_state(int code,
177 			    const mib2_transportMLPEntry_t *attr);
178 
179 static void		stat_report(mib_item_t *item);
180 static void		mrt_stat_report(mib_item_t *item);
181 static void		arp_report(mib_item_t *item);
182 static void		ndp_report(mib_item_t *item);
183 static void		mrt_report(mib_item_t *item);
184 static void		if_stat_total(struct ifstat *oldstats,
185 			    struct ifstat *newstats, struct ifstat *sumstats);
186 static void		if_report(mib_item_t *item, char *ifname,
187 			    int Iflag_only, boolean_t once_only);
188 static void		if_report_ip4(mib2_ipAddrEntry_t *ap,
189 			    char ifname[], char logintname[],
190 			    struct ifstat *statptr, boolean_t ksp_not_null);
191 static void		if_report_ip6(mib2_ipv6AddrEntry_t *ap6,
192 			    char ifname[], char logintname[],
193 			    struct ifstat *statptr, boolean_t ksp_not_null);
194 static void		ire_report(const mib_item_t *item);
195 static void		tcp_report(const mib_item_t *item);
196 static void		udp_report(const mib_item_t *item);
197 static void		group_report(mib_item_t *item);
198 static void		dce_report(mib_item_t *item);
199 static void		print_ip_stats(mib2_ip_t *ip);
200 static void		print_icmp_stats(mib2_icmp_t *icmp);
201 static void		print_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6);
202 static void		print_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6);
203 static void		print_sctp_stats(mib2_sctp_t *tcp);
204 static void		print_tcp_stats(mib2_tcp_t *tcp);
205 static void		print_udp_stats(mib2_udp_t *udp);
206 static void		print_rawip_stats(mib2_rawip_t *rawip);
207 static void		print_igmp_stats(struct igmpstat *igps);
208 static void		print_mrt_stats(struct mrtstat *mrts);
209 static void		sctp_report(const mib_item_t *item);
210 static void		sum_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6,
211 			    mib2_ipv6IfStatsEntry_t *sum6);
212 static void		sum_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6,
213 			    mib2_ipv6IfIcmpEntry_t *sum6);
214 static void		m_report(void);
215 static void		dhcp_report(char *);
216 
217 static	uint64_t	kstat_named_value(kstat_t *, char *);
218 static	kid_t		safe_kstat_read(kstat_ctl_t *, kstat_t *, void *);
219 static int		isnum(char *);
220 static char		*plural(int n);
221 static char		*pluraly(int n);
222 static char		*plurales(int n);
223 static void		process_filter(char *arg);
224 static char		*ifindex2str(uint_t, char *);
225 static boolean_t	family_selected(int family);
226 
227 static void		usage(char *);
228 static void 		fatal(int errcode, char *str1, ...);
229 
230 #define	PLURAL(n) plural((int)n)
231 #define	PLURALY(n) pluraly((int)n)
232 #define	PLURALES(n) plurales((int)n)
233 #define	IFLAGMOD(flg, val1, val2)	if (flg == val1) flg = val2
234 #define	MDIFF(diff, elem2, elem1, member)	(diff)->member = \
235 	(elem2)->member - (elem1)->member
236 
237 
238 static	boolean_t	Aflag = B_FALSE;	/* All sockets/ifs/rtng-tbls */
239 static	boolean_t	CIDRflag = B_FALSE;	/* CIDR for IPv4 -i/-r addrs */
240 static	boolean_t	Dflag = B_FALSE;	/* DCE info */
241 static	boolean_t	Iflag = B_FALSE;	/* IP Traffic Interfaces */
242 static	boolean_t	Mflag = B_FALSE;	/* STREAMS Memory Statistics */
243 static	boolean_t	Nflag = B_FALSE;	/* Numeric Network Addresses */
244 static	boolean_t	Rflag = B_FALSE;	/* Routing Tables */
245 static	boolean_t	RSECflag = B_FALSE;	/* Security attributes */
246 static	boolean_t	Sflag = B_FALSE;	/* Per-protocol Statistics */
247 static	boolean_t	Vflag = B_FALSE;	/* Verbose */
248 static	boolean_t	Pflag = B_FALSE;	/* Net to Media Tables */
249 static	boolean_t	Gflag = B_FALSE;	/* Multicast group membership */
250 static	boolean_t	MMflag = B_FALSE;	/* Multicast routing table */
251 static	boolean_t	DHCPflag = B_FALSE;	/* DHCP statistics */
252 static	boolean_t	Xflag = B_FALSE;	/* Debug Info */
253 
254 static	int	v4compat = 0;	/* Compatible printing format for status */
255 
256 static int	proto = IPPROTO_MAX;	/* all protocols */
257 kstat_ctl_t	*kc = NULL;
258 
259 /*
260  * Name service timeout detection constants.
261  */
262 static mutex_t ns_lock = ERRORCHECKMUTEX;
263 static boolean_t ns_active = B_FALSE;	/* Is a lookup ongoing? */
264 static hrtime_t ns_starttime;		/* Time the lookup started */
265 static int ns_sleeptime = 2;		/* Time in seconds between checks */
266 static int ns_warntime = 2;		/* Time in seconds before warning */
267 
268 /*
269  * Sizes of data structures extracted from the base mib.
270  * This allows the size of the tables entries to grow while preserving
271  * binary compatibility.
272  */
273 static int ipAddrEntrySize;
274 static int ipRouteEntrySize;
275 static int ipNetToMediaEntrySize;
276 static int ipMemberEntrySize;
277 static int ipGroupSourceEntrySize;
278 static int ipRouteAttributeSize;
279 static int vifctlSize;
280 static int mfcctlSize;
281 
282 static int ipv6IfStatsEntrySize;
283 static int ipv6IfIcmpEntrySize;
284 static int ipv6AddrEntrySize;
285 static int ipv6RouteEntrySize;
286 static int ipv6NetToMediaEntrySize;
287 static int ipv6MemberEntrySize;
288 static int ipv6GroupSourceEntrySize;
289 
290 static int ipDestEntrySize;
291 
292 static int transportMLPSize;
293 static int tcpConnEntrySize;
294 static int tcp6ConnEntrySize;
295 static int udpEntrySize;
296 static int udp6EntrySize;
297 static int sctpEntrySize;
298 static int sctpLocalEntrySize;
299 static int sctpRemoteEntrySize;
300 
301 #define	protocol_selected(p)	(proto == IPPROTO_MAX || proto == (p))
302 
303 /* Machinery used for -f (filter) option */
304 enum { FK_AF = 0, FK_OUTIF, FK_DST, FK_FLAGS, NFILTERKEYS };
305 
306 static const char *filter_keys[NFILTERKEYS] = {
307 	"af", "outif", "dst", "flags"
308 };
309 
310 static m_label_t *zone_security_label = NULL;
311 
312 /* Flags on routes */
313 #define	FLF_A		0x00000001
314 #define	FLF_b		0x00000002
315 #define	FLF_D		0x00000004
316 #define	FLF_G		0x00000008
317 #define	FLF_H		0x00000010
318 #define	FLF_L		0x00000020
319 #define	FLF_U		0x00000040
320 #define	FLF_M		0x00000080
321 #define	FLF_S		0x00000100
322 #define	FLF_C		0x00000200	/* IRE_IF_CLONE */
323 #define	FLF_I		0x00000400	/* RTF_INDIRECT */
324 #define	FLF_R		0x00000800	/* RTF_REJECT */
325 #define	FLF_B		0x00001000	/* RTF_BLACKHOLE */
326 #define	FLF_Z		0x00100000	/* RTF_ZONE */
327 
328 static const char flag_list[] = "AbDGHLUMSCIRBZ";
329 
330 typedef struct filter_rule filter_t;
331 
332 struct filter_rule {
333 	filter_t *f_next;
334 	union {
335 		int f_family;
336 		const char *f_ifname;
337 		struct {
338 			struct hostent *f_address;
339 			in6_addr_t f_mask;
340 		} a;
341 		struct {
342 			uint_t f_flagset;
343 			uint_t f_flagclear;
344 		} f;
345 	} u;
346 };
347 
348 /*
349  * The user-specified filters are linked into lists separated by
350  * keyword (type of filter).  Thus, the matching algorithm is:
351  *	For each non-empty filter list
352  *		If no filters in the list match
353  *			then stop here; route doesn't match
354  *	If loop above completes, then route does match and will be
355  *	displayed.
356  */
357 static filter_t *filters[NFILTERKEYS];
358 
359 static uint_t timestamp_fmt = NODATE;
360 
361 #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
362 #define	TEXT_DOMAIN "SYS_TEST"		/* Use this only if it isn't */
363 #endif
364 
365 static void
366 ns_lookup_start(void)
367 {
368 	mutex_enter(&ns_lock);
369 	ns_active = B_TRUE;
370 	ns_starttime = gethrtime();
371 	mutex_exit(&ns_lock);
372 }
373 
374 static void
375 ns_lookup_end(void)
376 {
377 	mutex_enter(&ns_lock);
378 	ns_active = B_FALSE;
379 	mutex_exit(&ns_lock);
380 }
381 
382 /*
383  * When name services are not functioning, this program appears to hang to the
384  * user. To try and give the user a chance of figuring out that this might be
385  * the case, we end up warning them and suggest that they may want to use the -n
386  * flag.
387  */
388 /* ARGSUSED */
389 static void *
390 ns_warning_thr(void *unsued)
391 {
392 	for (;;) {
393 		hrtime_t now;
394 
395 		(void) sleep(ns_sleeptime);
396 		now = gethrtime();
397 		mutex_enter(&ns_lock);
398 		if (ns_active && now - ns_starttime >= ns_warntime * NANOSEC) {
399 			(void) fprintf(stderr, "warning: data "
400 			    "available, but name service lookups are "
401 			    "taking a while. Use the -n option to "
402 			    "disable name service lookups.\n");
403 			mutex_exit(&ns_lock);
404 			return (NULL);
405 		}
406 		mutex_exit(&ns_lock);
407 	}
408 
409 	/* LINTED: E_STMT_NOT_REACHED */
410 	return (NULL);
411 }
412 
413 
414 int
415 main(int argc, char **argv)
416 {
417 	char		*name;
418 	mib_item_t	*item = NULL;
419 	mib_item_t	*previtem = NULL;
420 	int		sd = -1;
421 	char	*ifname = NULL;
422 	int	interval = 0;	/* Single time by default */
423 	int	count = -1;	/* Forever */
424 	int	c;
425 	int	d;
426 	/*
427 	 * Possible values of 'Iflag_only':
428 	 * -1, no feature-flags;
429 	 *  0, IFlag and other feature-flags enabled
430 	 *  1, IFlag is the only feature-flag enabled
431 	 * : trinary variable, modified using IFLAGMOD()
432 	 */
433 	int Iflag_only = -1;
434 	boolean_t once_only = B_FALSE; /* '-i' with count > 1 */
435 	extern char	*optarg;
436 	extern int	optind;
437 	char *default_ip_str = NULL;
438 
439 	name = argv[0];
440 
441 	v4compat = get_compat_flag(&default_ip_str);
442 	if (v4compat == DEFAULT_PROT_BAD_VALUE)
443 		fatal(2, "%s: %s: Bad value for %s in %s\n", name,
444 		    default_ip_str, DEFAULT_IP, INET_DEFAULT_FILE);
445 	free(default_ip_str);
446 
447 	(void) setlocale(LC_ALL, "");
448 	(void) textdomain(TEXT_DOMAIN);
449 
450 	while ((c = getopt(argc, argv, "acdimnrspMgvxf:P:I:DRT:")) != -1) {
451 		switch ((char)c) {
452 		case 'a':		/* all connections */
453 			Aflag = B_TRUE;
454 			break;
455 
456 		case 'c':
457 			CIDRflag = B_TRUE;
458 			break;
459 
460 		case 'd':		/* DCE info */
461 			Dflag = B_TRUE;
462 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
463 			break;
464 
465 		case 'i':		/* interface (ill/ipif report) */
466 			Iflag = B_TRUE;
467 			IFLAGMOD(Iflag_only, -1, 1); /* '-i' exists */
468 			break;
469 
470 		case 'm':		/* streams msg report */
471 			Mflag = B_TRUE;
472 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
473 			break;
474 
475 		case 'n':		/* numeric format */
476 			Nflag = B_TRUE;
477 			break;
478 
479 		case 'r':		/* route tables */
480 			Rflag = B_TRUE;
481 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
482 			break;
483 
484 		case 'R':		/* security attributes */
485 			RSECflag = B_TRUE;
486 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
487 			break;
488 
489 		case 's':		/* per-protocol statistics */
490 			Sflag = B_TRUE;
491 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
492 			break;
493 
494 		case 'p':		/* arp/ndp table */
495 			Pflag = B_TRUE;
496 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
497 			break;
498 
499 		case 'M':		/* multicast routing tables */
500 			MMflag = B_TRUE;
501 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
502 			break;
503 
504 		case 'g':		/* multicast group membership */
505 			Gflag = B_TRUE;
506 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
507 			break;
508 
509 		case 'v':		/* verbose output format */
510 			Vflag = B_TRUE;
511 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
512 			break;
513 
514 		case 'x':		/* turn on debugging */
515 			Xflag = B_TRUE;
516 			break;
517 
518 		case 'f':
519 			process_filter(optarg);
520 			break;
521 
522 		case 'P':
523 			if (strcmp(optarg, "ip") == 0) {
524 				proto = IPPROTO_IP;
525 			} else if (strcmp(optarg, "ipv6") == 0 ||
526 			    strcmp(optarg, "ip6") == 0) {
527 				v4compat = 0;	/* Overridden */
528 				proto = IPPROTO_IPV6;
529 			} else if (strcmp(optarg, "icmp") == 0) {
530 				proto = IPPROTO_ICMP;
531 			} else if (strcmp(optarg, "icmpv6") == 0 ||
532 			    strcmp(optarg, "icmp6") == 0) {
533 				v4compat = 0;	/* Overridden */
534 				proto = IPPROTO_ICMPV6;
535 			} else if (strcmp(optarg, "igmp") == 0) {
536 				proto = IPPROTO_IGMP;
537 			} else if (strcmp(optarg, "udp") == 0) {
538 				proto = IPPROTO_UDP;
539 			} else if (strcmp(optarg, "tcp") == 0) {
540 				proto = IPPROTO_TCP;
541 			} else if (strcmp(optarg, "sctp") == 0) {
542 				proto = IPPROTO_SCTP;
543 			} else if (strcmp(optarg, "raw") == 0 ||
544 			    strcmp(optarg, "rawip") == 0) {
545 				proto = IPPROTO_RAW;
546 			} else {
547 				fatal(1, "%s: unknown protocol.\n", optarg);
548 			}
549 			break;
550 
551 		case 'I':
552 			ifname = optarg;
553 			Iflag = B_TRUE;
554 			IFLAGMOD(Iflag_only, -1, 1); /* see macro def'n */
555 			break;
556 
557 		case 'D':
558 			DHCPflag = B_TRUE;
559 			Iflag_only = 0;
560 			break;
561 
562 		case 'T':
563 			if (optarg) {
564 				if (*optarg == 'u')
565 					timestamp_fmt = UDATE;
566 				else if (*optarg == 'd')
567 					timestamp_fmt = DDATE;
568 				else
569 					usage(name);
570 			} else {
571 				usage(name);
572 			}
573 			break;
574 
575 		case '?':
576 		default:
577 			usage(name);
578 		}
579 	}
580 
581 	/*
582 	 * Make sure -R option is set only on a labeled system.
583 	 */
584 	if (RSECflag && !is_system_labeled()) {
585 		(void) fprintf(stderr, "-R set but labeling is not enabled\n");
586 		usage(name);
587 	}
588 
589 	/*
590 	 * Handle other arguments: find interval, count; the
591 	 * flags that accept 'interval' and 'count' are OR'd
592 	 * in the outermost 'if'; more flags may be added as
593 	 * required
594 	 */
595 	if (Iflag || Sflag || Mflag) {
596 		for (d = optind; d < argc; d++) {
597 			if (isnum(argv[d])) {
598 				interval = atoi(argv[d]);
599 				if (d + 1 < argc &&
600 				    isnum(argv[d + 1])) {
601 					count = atoi(argv[d + 1]);
602 					optind++;
603 				}
604 				optind++;
605 				if (interval == 0 || count == 0)
606 					usage(name);
607 				break;
608 			}
609 		}
610 	}
611 	if (optind < argc) {
612 		if (Iflag && isnum(argv[optind])) {
613 			count = atoi(argv[optind]);
614 			if (count == 0)
615 				usage(name);
616 			optind++;
617 		}
618 	}
619 	if (optind < argc) {
620 		(void) fprintf(stderr,
621 		    "%s: extra arguments\n", name);
622 		usage(name);
623 	}
624 	if (interval)
625 		setbuf(stdout, NULL);
626 
627 	/*
628 	 * Start up the thread to check for name services warnings.
629 	 */
630 	if (thr_create(NULL, 0, ns_warning_thr, NULL,
631 	    THR_DETACHED | THR_DAEMON, NULL) != 0) {
632 		fatal(1, "%s: failed to create name services "
633 		    "thread: %s\n", name, strerror(errno));
634 	}
635 
636 	if (DHCPflag) {
637 		dhcp_report(Iflag ? ifname : NULL);
638 		exit(0);
639 	}
640 
641 	/*
642 	 * Get this process's security label if the -R switch is set.
643 	 * We use this label as the current zone's security label.
644 	 */
645 	if (RSECflag) {
646 		zone_security_label = m_label_alloc(MAC_LABEL);
647 		if (zone_security_label == NULL)
648 			fatal(errno, "m_label_alloc() failed");
649 		if (getplabel(zone_security_label) < 0)
650 			fatal(errno, "getplabel() failed");
651 	}
652 
653 	/* Get data structures: priming before iteration */
654 	if (family_selected(AF_INET) || family_selected(AF_INET6)) {
655 		sd = mibopen();
656 		if (sd == -1)
657 			fatal(1, "can't open mib stream\n");
658 		if ((item = mibget(sd)) == NULL) {
659 			(void) close(sd);
660 			fatal(1, "mibget() failed\n");
661 		}
662 		/* Extract constant sizes - need do once only */
663 		mib_get_constants(item);
664 	}
665 	if ((kc = kstat_open()) == NULL) {
666 		mibfree(item);
667 		(void) close(sd);
668 		fail(1, "kstat_open(): can't open /dev/kstat");
669 	}
670 
671 	if (interval <= 0) {
672 		count = 1;
673 		once_only = B_TRUE;
674 	}
675 	/* 'for' loop 1: */
676 	for (;;) {
677 		mib_item_t *curritem = NULL; /* only for -[M]s */
678 
679 		if (timestamp_fmt != NODATE)
680 			print_timestamp(timestamp_fmt);
681 
682 		/* netstat: AF_INET[6] behaviour */
683 		if (family_selected(AF_INET) || family_selected(AF_INET6)) {
684 			if (Sflag) {
685 				curritem = mib_item_diff(previtem, item);
686 				if (curritem == NULL)
687 					fatal(1, "can't process mib data, "
688 					    "out of memory\n");
689 				mib_item_destroy(&previtem);
690 			}
691 
692 			if (!(Dflag || Iflag || Rflag || Sflag || Mflag ||
693 			    MMflag || Pflag || Gflag || DHCPflag)) {
694 				if (protocol_selected(IPPROTO_UDP))
695 					udp_report(item);
696 				if (protocol_selected(IPPROTO_TCP))
697 					tcp_report(item);
698 				if (protocol_selected(IPPROTO_SCTP))
699 					sctp_report(item);
700 			}
701 			if (Iflag)
702 				if_report(item, ifname, Iflag_only, once_only);
703 			if (Mflag)
704 				m_report();
705 			if (Rflag)
706 				ire_report(item);
707 			if (Sflag && MMflag) {
708 				mrt_stat_report(curritem);
709 			} else {
710 				if (Sflag)
711 					stat_report(curritem);
712 				if (MMflag)
713 					mrt_report(item);
714 			}
715 			if (Gflag)
716 				group_report(item);
717 			if (Pflag) {
718 				if (family_selected(AF_INET))
719 					arp_report(item);
720 				if (family_selected(AF_INET6))
721 					ndp_report(item);
722 			}
723 			if (Dflag)
724 				dce_report(item);
725 			mib_item_destroy(&curritem);
726 		}
727 
728 		/* netstat: AF_UNIX behaviour */
729 		if (family_selected(AF_UNIX) &&
730 		    (!(Dflag || Iflag || Rflag || Sflag || Mflag ||
731 		    MMflag || Pflag || Gflag)))
732 			unixpr(kc);
733 		(void) kstat_close(kc);
734 
735 		/* iteration handling code */
736 		if (count > 0 && --count == 0)
737 			break;
738 		(void) sleep(interval);
739 
740 		/* re-populating of data structures */
741 		if (family_selected(AF_INET) || family_selected(AF_INET6)) {
742 			if (Sflag) {
743 				/* previtem is a cut-down list */
744 				previtem = mib_item_dup(item);
745 				if (previtem == NULL)
746 					fatal(1, "can't process mib data, "
747 					    "out of memory\n");
748 			}
749 			mibfree(item);
750 			(void) close(sd);
751 			if ((sd = mibopen()) == -1)
752 				fatal(1, "can't open mib stream anymore\n");
753 			if ((item = mibget(sd)) == NULL) {
754 				(void) close(sd);
755 				fatal(1, "mibget() failed\n");
756 			}
757 		}
758 		if ((kc = kstat_open()) == NULL)
759 			fail(1, "kstat_open(): can't open /dev/kstat");
760 
761 	} /* 'for' loop 1 ends */
762 	mibfree(item);
763 	(void) close(sd);
764 	if (zone_security_label != NULL)
765 		m_label_free(zone_security_label);
766 
767 	return (0);
768 }
769 
770 
771 static int
772 isnum(char *p)
773 {
774 	int	len;
775 	int	i;
776 
777 	len = strlen(p);
778 	for (i = 0; i < len; i++)
779 		if (!isdigit(p[i]))
780 			return (0);
781 	return (1);
782 }
783 
784 
785 /* --------------------------------- MIBGET -------------------------------- */
786 
787 static mib_item_t *
788 mibget(int sd)
789 {
790 	/*
791 	 * buf is an automatic for this function, so the
792 	 * compiler has complete control over its alignment;
793 	 * it is assumed this alignment is satisfactory for
794 	 * it to be casted to certain other struct pointers
795 	 * here, such as struct T_optmgmt_ack * .
796 	 */
797 	uintptr_t		buf[512 / sizeof (uintptr_t)];
798 	int			flags;
799 	int			i, j, getcode;
800 	struct strbuf		ctlbuf, databuf;
801 	struct T_optmgmt_req	*tor = (struct T_optmgmt_req *)buf;
802 	struct T_optmgmt_ack	*toa = (struct T_optmgmt_ack *)buf;
803 	struct T_error_ack	*tea = (struct T_error_ack *)buf;
804 	struct opthdr		*req;
805 	mib_item_t		*first_item = NULL;
806 	mib_item_t		*last_item  = NULL;
807 	mib_item_t		*temp;
808 
809 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
810 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
811 	tor->OPT_length = sizeof (struct opthdr);
812 	tor->MGMT_flags = T_CURRENT;
813 
814 
815 	/*
816 	 * Note: we use the special level value below so that IP will return
817 	 * us information concerning IRE_MARK_TESTHIDDEN routes.
818 	 */
819 	req = (struct opthdr *)&tor[1];
820 	req->level = EXPER_IP_AND_ALL_IRES;
821 	req->name  = 0;
822 	req->len   = 1;
823 
824 	ctlbuf.buf = (char *)buf;
825 	ctlbuf.len = tor->OPT_length + tor->OPT_offset;
826 	flags = 0;
827 	if (putmsg(sd, &ctlbuf, (struct strbuf *)0, flags) == -1) {
828 		perror("mibget: putmsg(ctl) failed");
829 		goto error_exit;
830 	}
831 
832 	/*
833 	 * Each reply consists of a ctl part for one fixed structure
834 	 * or table, as defined in mib2.h.  The format is a T_OPTMGMT_ACK,
835 	 * containing an opthdr structure.  level/name identify the entry,
836 	 * len is the size of the data part of the message.
837 	 */
838 	req = (struct opthdr *)&toa[1];
839 	ctlbuf.maxlen = sizeof (buf);
840 	j = 1;
841 	for (;;) {
842 		flags = 0;
843 		getcode = getmsg(sd, &ctlbuf, (struct strbuf *)0, &flags);
844 		if (getcode == -1) {
845 			perror("mibget getmsg(ctl) failed");
846 			if (Xflag) {
847 				(void) fputs("#   level   name    len\n",
848 				    stderr);
849 				i = 0;
850 				for (last_item = first_item; last_item;
851 				    last_item = last_item->next_item)
852 					(void) printf("%d  %4d   %5d   %d\n",
853 					    ++i,
854 					    last_item->group,
855 					    last_item->mib_id,
856 					    last_item->length);
857 			}
858 			goto error_exit;
859 		}
860 		if (getcode == 0 &&
861 		    ctlbuf.len >= sizeof (struct T_optmgmt_ack) &&
862 		    toa->PRIM_type == T_OPTMGMT_ACK &&
863 		    toa->MGMT_flags == T_SUCCESS &&
864 		    req->len == 0) {
865 			if (Xflag)
866 				(void) printf("mibget getmsg() %d returned "
867 				    "EOD (level %ld, name %ld)\n",
868 				    j, req->level, req->name);
869 			return (first_item);		/* this is EOD msg */
870 		}
871 
872 		if (ctlbuf.len >= sizeof (struct T_error_ack) &&
873 		    tea->PRIM_type == T_ERROR_ACK) {
874 			(void) fprintf(stderr,
875 			    "mibget %d gives T_ERROR_ACK: TLI_error = 0x%lx, "
876 			    "UNIX_error = 0x%lx\n",
877 			    j, tea->TLI_error, tea->UNIX_error);
878 
879 			errno = (tea->TLI_error == TSYSERR) ?
880 			    tea->UNIX_error : EPROTO;
881 			goto error_exit;
882 		}
883 
884 		if (getcode != MOREDATA ||
885 		    ctlbuf.len < sizeof (struct T_optmgmt_ack) ||
886 		    toa->PRIM_type != T_OPTMGMT_ACK ||
887 		    toa->MGMT_flags != T_SUCCESS) {
888 			(void) printf("mibget getmsg(ctl) %d returned %d, "
889 			    "ctlbuf.len = %d, PRIM_type = %ld\n",
890 			    j, getcode, ctlbuf.len, toa->PRIM_type);
891 
892 			if (toa->PRIM_type == T_OPTMGMT_ACK)
893 				(void) printf("T_OPTMGMT_ACK: "
894 				    "MGMT_flags = 0x%lx, req->len = %ld\n",
895 				    toa->MGMT_flags, req->len);
896 			errno = ENOMSG;
897 			goto error_exit;
898 		}
899 
900 		temp = (mib_item_t *)malloc(sizeof (mib_item_t));
901 		if (temp == NULL) {
902 			perror("mibget malloc failed");
903 			goto error_exit;
904 		}
905 		if (last_item != NULL)
906 			last_item->next_item = temp;
907 		else
908 			first_item = temp;
909 		last_item = temp;
910 		last_item->next_item = NULL;
911 		last_item->group = req->level;
912 		last_item->mib_id = req->name;
913 		last_item->length = req->len;
914 		last_item->valp = malloc((int)req->len);
915 		if (last_item->valp == NULL)
916 			goto error_exit;
917 		if (Xflag)
918 			(void) printf("msg %d: group = %4d   mib_id = %5d"
919 			    "length = %d\n",
920 			    j, last_item->group, last_item->mib_id,
921 			    last_item->length);
922 
923 		databuf.maxlen = last_item->length;
924 		databuf.buf    = (char *)last_item->valp;
925 		databuf.len    = 0;
926 		flags = 0;
927 		getcode = getmsg(sd, (struct strbuf *)0, &databuf, &flags);
928 		if (getcode == -1) {
929 			perror("mibget getmsg(data) failed");
930 			goto error_exit;
931 		} else if (getcode != 0) {
932 			(void) printf("mibget getmsg(data) returned %d, "
933 			    "databuf.maxlen = %d, databuf.len = %d\n",
934 			    getcode, databuf.maxlen, databuf.len);
935 			goto error_exit;
936 		}
937 		j++;
938 	}
939 	/* NOTREACHED */
940 
941 error_exit:;
942 	mibfree(first_item);
943 	return (NULL);
944 }
945 
946 /*
947  * mibfree: frees a linked list of type (mib_item_t *)
948  * returned by mibget(); this is NOT THE SAME AS
949  * mib_item_destroy(), so should be used for objects
950  * returned by mibget() only
951  */
952 static void
953 mibfree(mib_item_t *firstitem)
954 {
955 	mib_item_t *lastitem;
956 
957 	while (firstitem != NULL) {
958 		lastitem = firstitem;
959 		firstitem = firstitem->next_item;
960 		if (lastitem->valp != NULL)
961 			free(lastitem->valp);
962 		free(lastitem);
963 	}
964 }
965 
966 static int
967 mibopen(void)
968 {
969 	int	sd;
970 
971 	sd = open("/dev/arp", O_RDWR);
972 	if (sd == -1) {
973 		perror("arp open");
974 		return (-1);
975 	}
976 	if (ioctl(sd, I_PUSH, "tcp") == -1) {
977 		perror("tcp I_PUSH");
978 		(void) close(sd);
979 		return (-1);
980 	}
981 	if (ioctl(sd, I_PUSH, "udp") == -1) {
982 		perror("udp I_PUSH");
983 		(void) close(sd);
984 		return (-1);
985 	}
986 	if (ioctl(sd, I_PUSH, "icmp") == -1) {
987 		perror("icmp I_PUSH");
988 		(void) close(sd);
989 		return (-1);
990 	}
991 	return (sd);
992 }
993 
994 /*
995  * mib_item_dup: returns a clean mib_item_t * linked
996  * list, so that for every element item->mib_id is 0;
997  * to deallocate this linked list, use mib_item_destroy
998  */
999 static mib_item_t *
1000 mib_item_dup(mib_item_t *item)
1001 {
1002 	int	c = 0;
1003 	mib_item_t *localp;
1004 	mib_item_t *tempp;
1005 
1006 	for (tempp = item; tempp; tempp = tempp->next_item)
1007 		if (tempp->mib_id == 0)
1008 			c++;
1009 	tempp = NULL;
1010 
1011 	localp = (mib_item_t *)malloc(c * sizeof (mib_item_t));
1012 	if (localp == NULL)
1013 		return (NULL);
1014 	c = 0;
1015 	for (; item; item = item->next_item) {
1016 		if (item->mib_id == 0) {
1017 			/* Replicate item in localp */
1018 			(localp[c]).next_item = NULL;
1019 			(localp[c]).group = item->group;
1020 			(localp[c]).mib_id = item->mib_id;
1021 			(localp[c]).length = item->length;
1022 			(localp[c]).valp = (uintptr_t *)malloc(
1023 			    item->length);
1024 			if ((localp[c]).valp == NULL) {
1025 				mib_item_destroy(&localp);
1026 				return (NULL);
1027 			}
1028 			(void *) memcpy((localp[c]).valp,
1029 			    item->valp,
1030 			    item->length);
1031 			tempp = &(localp[c]);
1032 			if (c > 0)
1033 				(localp[c - 1]).next_item = tempp;
1034 			c++;
1035 		}
1036 	}
1037 	return (localp);
1038 }
1039 
1040 /*
1041  * mib_item_diff: takes two (mib_item_t *) linked lists
1042  * item1 and item2 and computes the difference between
1043  * differentiable values in item2 against item1 for every
1044  * given member of item2; returns an mib_item_t * linked
1045  * list of diff's, or a copy of item2 if item1 is NULL;
1046  * will return NULL if system out of memory; works only
1047  * for item->mib_id == 0
1048  */
1049 static mib_item_t *
1050 mib_item_diff(mib_item_t *item1, mib_item_t *item2)
1051 {
1052 	int	nitems	= 0; /* no. of items in item2 */
1053 	mib_item_t *tempp2;  /* walking copy of item2 */
1054 	mib_item_t *tempp1;  /* walking copy of item1 */
1055 	mib_item_t *diffp;
1056 	mib_item_t *diffptr; /* walking copy of diffp */
1057 	mib_item_t *prevp = NULL;
1058 
1059 	if (item1 == NULL) {
1060 		diffp = mib_item_dup(item2);
1061 		return (diffp);
1062 	}
1063 
1064 	for (tempp2 = item2;
1065 	    tempp2;
1066 	    tempp2 = tempp2->next_item) {
1067 		if (tempp2->mib_id == 0)
1068 			switch (tempp2->group) {
1069 			/*
1070 			 * upon adding a case here, the same
1071 			 * must also be added in the next
1072 			 * switch statement, alongwith
1073 			 * appropriate code
1074 			 */
1075 			case MIB2_IP:
1076 			case MIB2_IP6:
1077 			case EXPER_DVMRP:
1078 			case EXPER_IGMP:
1079 			case MIB2_ICMP:
1080 			case MIB2_ICMP6:
1081 			case MIB2_TCP:
1082 			case MIB2_UDP:
1083 			case MIB2_SCTP:
1084 			case EXPER_RAWIP:
1085 				nitems++;
1086 			}
1087 	}
1088 	tempp2 = NULL;
1089 	if (nitems == 0) {
1090 		diffp = mib_item_dup(item2);
1091 		return (diffp);
1092 	}
1093 
1094 	diffp = (mib_item_t *)calloc(nitems, sizeof (mib_item_t));
1095 	if (diffp == NULL)
1096 		return (NULL);
1097 	diffptr = diffp;
1098 	/* 'for' loop 1: */
1099 	for (tempp2 = item2; tempp2 != NULL; tempp2 = tempp2->next_item) {
1100 		if (tempp2->mib_id != 0)
1101 			continue; /* 'for' loop 1 */
1102 		/* 'for' loop 2: */
1103 		for (tempp1 = item1; tempp1 != NULL;
1104 		    tempp1 = tempp1->next_item) {
1105 			if (!(tempp1->mib_id == 0 &&
1106 			    tempp1->group == tempp2->group &&
1107 			    tempp1->mib_id == tempp2->mib_id))
1108 				continue; /* 'for' loop 2 */
1109 			/* found comparable data sets */
1110 			if (prevp != NULL)
1111 				prevp->next_item = diffptr;
1112 			switch (tempp2->group) {
1113 			/*
1114 			 * Indenting note: Because of long variable names
1115 			 * in cases MIB2_IP6 and MIB2_ICMP6, their contents
1116 			 * have been indented by one tab space only
1117 			 */
1118 			case MIB2_IP: {
1119 				mib2_ip_t *i2 = (mib2_ip_t *)tempp2->valp;
1120 				mib2_ip_t *i1 = (mib2_ip_t *)tempp1->valp;
1121 				mib2_ip_t *d;
1122 
1123 				diffptr->group = tempp2->group;
1124 				diffptr->mib_id = tempp2->mib_id;
1125 				diffptr->length = tempp2->length;
1126 				d = (mib2_ip_t *)calloc(tempp2->length, 1);
1127 				if (d == NULL)
1128 					goto mibdiff_out_of_memory;
1129 				diffptr->valp = d;
1130 				d->ipForwarding = i2->ipForwarding;
1131 				d->ipDefaultTTL = i2->ipDefaultTTL;
1132 				MDIFF(d, i2, i1, ipInReceives);
1133 				MDIFF(d, i2, i1, ipInHdrErrors);
1134 				MDIFF(d, i2, i1, ipInAddrErrors);
1135 				MDIFF(d, i2, i1, ipInCksumErrs);
1136 				MDIFF(d, i2, i1, ipForwDatagrams);
1137 				MDIFF(d, i2, i1, ipForwProhibits);
1138 				MDIFF(d, i2, i1, ipInUnknownProtos);
1139 				MDIFF(d, i2, i1, ipInDiscards);
1140 				MDIFF(d, i2, i1, ipInDelivers);
1141 				MDIFF(d, i2, i1, ipOutRequests);
1142 				MDIFF(d, i2, i1, ipOutDiscards);
1143 				MDIFF(d, i2, i1, ipOutNoRoutes);
1144 				MDIFF(d, i2, i1, ipReasmTimeout);
1145 				MDIFF(d, i2, i1, ipReasmReqds);
1146 				MDIFF(d, i2, i1, ipReasmOKs);
1147 				MDIFF(d, i2, i1, ipReasmFails);
1148 				MDIFF(d, i2, i1, ipReasmDuplicates);
1149 				MDIFF(d, i2, i1, ipReasmPartDups);
1150 				MDIFF(d, i2, i1, ipFragOKs);
1151 				MDIFF(d, i2, i1, ipFragFails);
1152 				MDIFF(d, i2, i1, ipFragCreates);
1153 				MDIFF(d, i2, i1, ipRoutingDiscards);
1154 				MDIFF(d, i2, i1, tcpInErrs);
1155 				MDIFF(d, i2, i1, udpNoPorts);
1156 				MDIFF(d, i2, i1, udpInCksumErrs);
1157 				MDIFF(d, i2, i1, udpInOverflows);
1158 				MDIFF(d, i2, i1, rawipInOverflows);
1159 				MDIFF(d, i2, i1, ipsecInSucceeded);
1160 				MDIFF(d, i2, i1, ipsecInFailed);
1161 				MDIFF(d, i2, i1, ipInIPv6);
1162 				MDIFF(d, i2, i1, ipOutIPv6);
1163 				MDIFF(d, i2, i1, ipOutSwitchIPv6);
1164 				prevp = diffptr++;
1165 				break;
1166 			}
1167 			case MIB2_IP6: {
1168 			mib2_ipv6IfStatsEntry_t *i2;
1169 			mib2_ipv6IfStatsEntry_t *i1;
1170 			mib2_ipv6IfStatsEntry_t *d;
1171 
1172 			i2 = (mib2_ipv6IfStatsEntry_t *)tempp2->valp;
1173 			i1 = (mib2_ipv6IfStatsEntry_t *)tempp1->valp;
1174 			diffptr->group = tempp2->group;
1175 			diffptr->mib_id = tempp2->mib_id;
1176 			diffptr->length = tempp2->length;
1177 			d = (mib2_ipv6IfStatsEntry_t *)calloc(
1178 			    tempp2->length, 1);
1179 			if (d == NULL)
1180 				goto mibdiff_out_of_memory;
1181 			diffptr->valp = d;
1182 			d->ipv6Forwarding = i2->ipv6Forwarding;
1183 			d->ipv6DefaultHopLimit =
1184 			    i2->ipv6DefaultHopLimit;
1185 
1186 			MDIFF(d, i2, i1, ipv6InReceives);
1187 			MDIFF(d, i2, i1, ipv6InHdrErrors);
1188 			MDIFF(d, i2, i1, ipv6InTooBigErrors);
1189 			MDIFF(d, i2, i1, ipv6InNoRoutes);
1190 			MDIFF(d, i2, i1, ipv6InAddrErrors);
1191 			MDIFF(d, i2, i1, ipv6InUnknownProtos);
1192 			MDIFF(d, i2, i1, ipv6InTruncatedPkts);
1193 			MDIFF(d, i2, i1, ipv6InDiscards);
1194 			MDIFF(d, i2, i1, ipv6InDelivers);
1195 			MDIFF(d, i2, i1, ipv6OutForwDatagrams);
1196 			MDIFF(d, i2, i1, ipv6OutRequests);
1197 			MDIFF(d, i2, i1, ipv6OutDiscards);
1198 			MDIFF(d, i2, i1, ipv6OutNoRoutes);
1199 			MDIFF(d, i2, i1, ipv6OutFragOKs);
1200 			MDIFF(d, i2, i1, ipv6OutFragFails);
1201 			MDIFF(d, i2, i1, ipv6OutFragCreates);
1202 			MDIFF(d, i2, i1, ipv6ReasmReqds);
1203 			MDIFF(d, i2, i1, ipv6ReasmOKs);
1204 			MDIFF(d, i2, i1, ipv6ReasmFails);
1205 			MDIFF(d, i2, i1, ipv6InMcastPkts);
1206 			MDIFF(d, i2, i1, ipv6OutMcastPkts);
1207 			MDIFF(d, i2, i1, ipv6ReasmDuplicates);
1208 			MDIFF(d, i2, i1, ipv6ReasmPartDups);
1209 			MDIFF(d, i2, i1, ipv6ForwProhibits);
1210 			MDIFF(d, i2, i1, udpInCksumErrs);
1211 			MDIFF(d, i2, i1, udpInOverflows);
1212 			MDIFF(d, i2, i1, rawipInOverflows);
1213 			MDIFF(d, i2, i1, ipv6InIPv4);
1214 			MDIFF(d, i2, i1, ipv6OutIPv4);
1215 			MDIFF(d, i2, i1, ipv6OutSwitchIPv4);
1216 			prevp = diffptr++;
1217 			break;
1218 			}
1219 			case EXPER_DVMRP: {
1220 				struct mrtstat *m2;
1221 				struct mrtstat *m1;
1222 				struct mrtstat *d;
1223 
1224 				m2 = (struct mrtstat *)tempp2->valp;
1225 				m1 = (struct mrtstat *)tempp1->valp;
1226 				diffptr->group = tempp2->group;
1227 				diffptr->mib_id = tempp2->mib_id;
1228 				diffptr->length = tempp2->length;
1229 				d = (struct mrtstat *)calloc(tempp2->length, 1);
1230 				if (d == NULL)
1231 					goto mibdiff_out_of_memory;
1232 				diffptr->valp = d;
1233 				MDIFF(d, m2, m1, mrts_mfc_hits);
1234 				MDIFF(d, m2, m1, mrts_mfc_misses);
1235 				MDIFF(d, m2, m1, mrts_fwd_in);
1236 				MDIFF(d, m2, m1, mrts_fwd_out);
1237 				d->mrts_upcalls = m2->mrts_upcalls;
1238 				MDIFF(d, m2, m1, mrts_fwd_drop);
1239 				MDIFF(d, m2, m1, mrts_bad_tunnel);
1240 				MDIFF(d, m2, m1, mrts_cant_tunnel);
1241 				MDIFF(d, m2, m1, mrts_wrong_if);
1242 				MDIFF(d, m2, m1, mrts_upq_ovflw);
1243 				MDIFF(d, m2, m1, mrts_cache_cleanups);
1244 				MDIFF(d, m2, m1, mrts_drop_sel);
1245 				MDIFF(d, m2, m1, mrts_q_overflow);
1246 				MDIFF(d, m2, m1, mrts_pkt2large);
1247 				MDIFF(d, m2, m1, mrts_pim_badversion);
1248 				MDIFF(d, m2, m1, mrts_pim_rcv_badcsum);
1249 				MDIFF(d, m2, m1, mrts_pim_badregisters);
1250 				MDIFF(d, m2, m1, mrts_pim_regforwards);
1251 				MDIFF(d, m2, m1, mrts_pim_regsend_drops);
1252 				MDIFF(d, m2, m1, mrts_pim_malformed);
1253 				MDIFF(d, m2, m1, mrts_pim_nomemory);
1254 				prevp = diffptr++;
1255 				break;
1256 			}
1257 			case EXPER_IGMP: {
1258 				struct igmpstat *i2;
1259 				struct igmpstat *i1;
1260 				struct igmpstat *d;
1261 
1262 				i2 = (struct igmpstat *)tempp2->valp;
1263 				i1 = (struct igmpstat *)tempp1->valp;
1264 				diffptr->group = tempp2->group;
1265 				diffptr->mib_id = tempp2->mib_id;
1266 				diffptr->length = tempp2->length;
1267 				d = (struct igmpstat *)calloc(
1268 				    tempp2->length, 1);
1269 				if (d == NULL)
1270 					goto mibdiff_out_of_memory;
1271 				diffptr->valp = d;
1272 				MDIFF(d, i2, i1, igps_rcv_total);
1273 				MDIFF(d, i2, i1, igps_rcv_tooshort);
1274 				MDIFF(d, i2, i1, igps_rcv_badsum);
1275 				MDIFF(d, i2, i1, igps_rcv_queries);
1276 				MDIFF(d, i2, i1, igps_rcv_badqueries);
1277 				MDIFF(d, i2, i1, igps_rcv_reports);
1278 				MDIFF(d, i2, i1, igps_rcv_badreports);
1279 				MDIFF(d, i2, i1, igps_rcv_ourreports);
1280 				MDIFF(d, i2, i1, igps_snd_reports);
1281 				prevp = diffptr++;
1282 				break;
1283 			}
1284 			case MIB2_ICMP: {
1285 				mib2_icmp_t *i2;
1286 				mib2_icmp_t *i1;
1287 				mib2_icmp_t *d;
1288 
1289 				i2 = (mib2_icmp_t *)tempp2->valp;
1290 				i1 = (mib2_icmp_t *)tempp1->valp;
1291 				diffptr->group = tempp2->group;
1292 				diffptr->mib_id = tempp2->mib_id;
1293 				diffptr->length = tempp2->length;
1294 				d = (mib2_icmp_t *)calloc(tempp2->length, 1);
1295 				if (d == NULL)
1296 					goto mibdiff_out_of_memory;
1297 				diffptr->valp = d;
1298 				MDIFF(d, i2, i1, icmpInMsgs);
1299 				MDIFF(d, i2, i1, icmpInErrors);
1300 				MDIFF(d, i2, i1, icmpInCksumErrs);
1301 				MDIFF(d, i2, i1, icmpInUnknowns);
1302 				MDIFF(d, i2, i1, icmpInDestUnreachs);
1303 				MDIFF(d, i2, i1, icmpInTimeExcds);
1304 				MDIFF(d, i2, i1, icmpInParmProbs);
1305 				MDIFF(d, i2, i1, icmpInSrcQuenchs);
1306 				MDIFF(d, i2, i1, icmpInRedirects);
1307 				MDIFF(d, i2, i1, icmpInBadRedirects);
1308 				MDIFF(d, i2, i1, icmpInEchos);
1309 				MDIFF(d, i2, i1, icmpInEchoReps);
1310 				MDIFF(d, i2, i1, icmpInTimestamps);
1311 				MDIFF(d, i2, i1, icmpInAddrMasks);
1312 				MDIFF(d, i2, i1, icmpInAddrMaskReps);
1313 				MDIFF(d, i2, i1, icmpInFragNeeded);
1314 				MDIFF(d, i2, i1, icmpOutMsgs);
1315 				MDIFF(d, i2, i1, icmpOutDrops);
1316 				MDIFF(d, i2, i1, icmpOutErrors);
1317 				MDIFF(d, i2, i1, icmpOutDestUnreachs);
1318 				MDIFF(d, i2, i1, icmpOutTimeExcds);
1319 				MDIFF(d, i2, i1, icmpOutParmProbs);
1320 				MDIFF(d, i2, i1, icmpOutSrcQuenchs);
1321 				MDIFF(d, i2, i1, icmpOutRedirects);
1322 				MDIFF(d, i2, i1, icmpOutEchos);
1323 				MDIFF(d, i2, i1, icmpOutEchoReps);
1324 				MDIFF(d, i2, i1, icmpOutTimestamps);
1325 				MDIFF(d, i2, i1, icmpOutTimestampReps);
1326 				MDIFF(d, i2, i1, icmpOutAddrMasks);
1327 				MDIFF(d, i2, i1, icmpOutAddrMaskReps);
1328 				MDIFF(d, i2, i1, icmpOutFragNeeded);
1329 				MDIFF(d, i2, i1, icmpInOverflows);
1330 				prevp = diffptr++;
1331 				break;
1332 			}
1333 			case MIB2_ICMP6: {
1334 	mib2_ipv6IfIcmpEntry_t *i2;
1335 	mib2_ipv6IfIcmpEntry_t *i1;
1336 	mib2_ipv6IfIcmpEntry_t *d;
1337 
1338 	i2 = (mib2_ipv6IfIcmpEntry_t *)tempp2->valp;
1339 	i1 = (mib2_ipv6IfIcmpEntry_t *)tempp1->valp;
1340 	diffptr->group = tempp2->group;
1341 	diffptr->mib_id = tempp2->mib_id;
1342 	diffptr->length = tempp2->length;
1343 	d = (mib2_ipv6IfIcmpEntry_t *)calloc(tempp2->length, 1);
1344 	if (d == NULL)
1345 		goto mibdiff_out_of_memory;
1346 	diffptr->valp = d;
1347 	MDIFF(d, i2, i1, ipv6IfIcmpInMsgs);
1348 	MDIFF(d, i2, i1, ipv6IfIcmpInErrors);
1349 	MDIFF(d, i2, i1, ipv6IfIcmpInDestUnreachs);
1350 	MDIFF(d, i2, i1, ipv6IfIcmpInAdminProhibs);
1351 	MDIFF(d, i2, i1, ipv6IfIcmpInTimeExcds);
1352 	MDIFF(d, i2, i1, ipv6IfIcmpInParmProblems);
1353 	MDIFF(d, i2, i1, ipv6IfIcmpInPktTooBigs);
1354 	MDIFF(d, i2, i1, ipv6IfIcmpInEchos);
1355 	MDIFF(d, i2, i1, ipv6IfIcmpInEchoReplies);
1356 	MDIFF(d, i2, i1, ipv6IfIcmpInRouterSolicits);
1357 	MDIFF(d, i2, i1, ipv6IfIcmpInRouterAdvertisements);
1358 	MDIFF(d, i2, i1, ipv6IfIcmpInNeighborSolicits);
1359 	MDIFF(d, i2, i1, ipv6IfIcmpInNeighborAdvertisements);
1360 	MDIFF(d, i2, i1, ipv6IfIcmpInRedirects);
1361 	MDIFF(d, i2, i1, ipv6IfIcmpInBadRedirects);
1362 	MDIFF(d, i2, i1, ipv6IfIcmpInGroupMembQueries);
1363 	MDIFF(d, i2, i1, ipv6IfIcmpInGroupMembResponses);
1364 	MDIFF(d, i2, i1, ipv6IfIcmpInGroupMembReductions);
1365 	MDIFF(d, i2, i1, ipv6IfIcmpInOverflows);
1366 	MDIFF(d, i2, i1, ipv6IfIcmpOutMsgs);
1367 	MDIFF(d, i2, i1, ipv6IfIcmpOutErrors);
1368 	MDIFF(d, i2, i1, ipv6IfIcmpOutDestUnreachs);
1369 	MDIFF(d, i2, i1, ipv6IfIcmpOutAdminProhibs);
1370 	MDIFF(d, i2, i1, ipv6IfIcmpOutTimeExcds);
1371 	MDIFF(d, i2, i1, ipv6IfIcmpOutParmProblems);
1372 	MDIFF(d, i2, i1, ipv6IfIcmpOutPktTooBigs);
1373 	MDIFF(d, i2, i1, ipv6IfIcmpOutEchos);
1374 	MDIFF(d, i2, i1, ipv6IfIcmpOutEchoReplies);
1375 	MDIFF(d, i2, i1, ipv6IfIcmpOutRouterSolicits);
1376 	MDIFF(d, i2, i1, ipv6IfIcmpOutRouterAdvertisements);
1377 	MDIFF(d, i2, i1, ipv6IfIcmpOutNeighborSolicits);
1378 	MDIFF(d, i2, i1, ipv6IfIcmpOutNeighborAdvertisements);
1379 	MDIFF(d, i2, i1, ipv6IfIcmpOutRedirects);
1380 	MDIFF(d, i2, i1, ipv6IfIcmpOutGroupMembQueries);
1381 	MDIFF(d, i2, i1, ipv6IfIcmpOutGroupMembResponses);
1382 	MDIFF(d, i2, i1, ipv6IfIcmpOutGroupMembReductions);
1383 	prevp = diffptr++;
1384 	break;
1385 			}
1386 			case MIB2_TCP: {
1387 				mib2_tcp_t *t2;
1388 				mib2_tcp_t *t1;
1389 				mib2_tcp_t *d;
1390 
1391 				t2 = (mib2_tcp_t *)tempp2->valp;
1392 				t1 = (mib2_tcp_t *)tempp1->valp;
1393 				diffptr->group = tempp2->group;
1394 				diffptr->mib_id = tempp2->mib_id;
1395 				diffptr->length = tempp2->length;
1396 				d = (mib2_tcp_t *)calloc(tempp2->length, 1);
1397 				if (d == NULL)
1398 					goto mibdiff_out_of_memory;
1399 				diffptr->valp = d;
1400 				d->tcpRtoMin = t2->tcpRtoMin;
1401 				d->tcpRtoMax = t2->tcpRtoMax;
1402 				d->tcpMaxConn = t2->tcpMaxConn;
1403 				MDIFF(d, t2, t1, tcpActiveOpens);
1404 				MDIFF(d, t2, t1, tcpPassiveOpens);
1405 				MDIFF(d, t2, t1, tcpAttemptFails);
1406 				MDIFF(d, t2, t1, tcpEstabResets);
1407 				d->tcpCurrEstab = t2->tcpCurrEstab;
1408 				MDIFF(d, t2, t1, tcpHCOutSegs);
1409 				MDIFF(d, t2, t1, tcpOutDataSegs);
1410 				MDIFF(d, t2, t1, tcpOutDataBytes);
1411 				MDIFF(d, t2, t1, tcpRetransSegs);
1412 				MDIFF(d, t2, t1, tcpRetransBytes);
1413 				MDIFF(d, t2, t1, tcpOutAck);
1414 				MDIFF(d, t2, t1, tcpOutAckDelayed);
1415 				MDIFF(d, t2, t1, tcpOutUrg);
1416 				MDIFF(d, t2, t1, tcpOutWinUpdate);
1417 				MDIFF(d, t2, t1, tcpOutWinProbe);
1418 				MDIFF(d, t2, t1, tcpOutControl);
1419 				MDIFF(d, t2, t1, tcpOutRsts);
1420 				MDIFF(d, t2, t1, tcpOutFastRetrans);
1421 				MDIFF(d, t2, t1, tcpHCInSegs);
1422 				MDIFF(d, t2, t1, tcpInAckSegs);
1423 				MDIFF(d, t2, t1, tcpInAckBytes);
1424 				MDIFF(d, t2, t1, tcpInDupAck);
1425 				MDIFF(d, t2, t1, tcpInAckUnsent);
1426 				MDIFF(d, t2, t1, tcpInDataInorderSegs);
1427 				MDIFF(d, t2, t1, tcpInDataInorderBytes);
1428 				MDIFF(d, t2, t1, tcpInDataUnorderSegs);
1429 				MDIFF(d, t2, t1, tcpInDataUnorderBytes);
1430 				MDIFF(d, t2, t1, tcpInDataDupSegs);
1431 				MDIFF(d, t2, t1, tcpInDataDupBytes);
1432 				MDIFF(d, t2, t1, tcpInDataPartDupSegs);
1433 				MDIFF(d, t2, t1, tcpInDataPartDupBytes);
1434 				MDIFF(d, t2, t1, tcpInDataPastWinSegs);
1435 				MDIFF(d, t2, t1, tcpInDataPastWinBytes);
1436 				MDIFF(d, t2, t1, tcpInWinProbe);
1437 				MDIFF(d, t2, t1, tcpInWinUpdate);
1438 				MDIFF(d, t2, t1, tcpInClosed);
1439 				MDIFF(d, t2, t1, tcpRttNoUpdate);
1440 				MDIFF(d, t2, t1, tcpRttUpdate);
1441 				MDIFF(d, t2, t1, tcpTimRetrans);
1442 				MDIFF(d, t2, t1, tcpTimRetransDrop);
1443 				MDIFF(d, t2, t1, tcpTimKeepalive);
1444 				MDIFF(d, t2, t1, tcpTimKeepaliveProbe);
1445 				MDIFF(d, t2, t1, tcpTimKeepaliveDrop);
1446 				MDIFF(d, t2, t1, tcpListenDrop);
1447 				MDIFF(d, t2, t1, tcpListenDropQ0);
1448 				MDIFF(d, t2, t1, tcpHalfOpenDrop);
1449 				MDIFF(d, t2, t1, tcpOutSackRetransSegs);
1450 				prevp = diffptr++;
1451 				break;
1452 			}
1453 			case MIB2_UDP: {
1454 				mib2_udp_t *u2;
1455 				mib2_udp_t *u1;
1456 				mib2_udp_t *d;
1457 
1458 				u2 = (mib2_udp_t *)tempp2->valp;
1459 				u1 = (mib2_udp_t *)tempp1->valp;
1460 				diffptr->group = tempp2->group;
1461 				diffptr->mib_id = tempp2->mib_id;
1462 				diffptr->length = tempp2->length;
1463 				d = (mib2_udp_t *)calloc(tempp2->length, 1);
1464 				if (d == NULL)
1465 					goto mibdiff_out_of_memory;
1466 				diffptr->valp = d;
1467 				MDIFF(d, u2, u1, udpHCInDatagrams);
1468 				MDIFF(d, u2, u1, udpInErrors);
1469 				MDIFF(d, u2, u1, udpHCOutDatagrams);
1470 				MDIFF(d, u2, u1, udpOutErrors);
1471 				prevp = diffptr++;
1472 				break;
1473 			}
1474 			case MIB2_SCTP: {
1475 				mib2_sctp_t *s2;
1476 				mib2_sctp_t *s1;
1477 				mib2_sctp_t *d;
1478 
1479 				s2 = (mib2_sctp_t *)tempp2->valp;
1480 				s1 = (mib2_sctp_t *)tempp1->valp;
1481 				diffptr->group = tempp2->group;
1482 				diffptr->mib_id = tempp2->mib_id;
1483 				diffptr->length = tempp2->length;
1484 				d = (mib2_sctp_t *)calloc(tempp2->length, 1);
1485 				if (d == NULL)
1486 					goto mibdiff_out_of_memory;
1487 				diffptr->valp = d;
1488 				d->sctpRtoAlgorithm = s2->sctpRtoAlgorithm;
1489 				d->sctpRtoMin = s2->sctpRtoMin;
1490 				d->sctpRtoMax = s2->sctpRtoMax;
1491 				d->sctpRtoInitial = s2->sctpRtoInitial;
1492 				d->sctpMaxAssocs = s2->sctpMaxAssocs;
1493 				d->sctpValCookieLife = s2->sctpValCookieLife;
1494 				d->sctpMaxInitRetr = s2->sctpMaxInitRetr;
1495 				d->sctpCurrEstab = s2->sctpCurrEstab;
1496 				MDIFF(d, s2, s1, sctpActiveEstab);
1497 				MDIFF(d, s2, s1, sctpPassiveEstab);
1498 				MDIFF(d, s2, s1, sctpAborted);
1499 				MDIFF(d, s2, s1, sctpShutdowns);
1500 				MDIFF(d, s2, s1, sctpOutOfBlue);
1501 				MDIFF(d, s2, s1, sctpChecksumError);
1502 				MDIFF(d, s2, s1, sctpOutCtrlChunks);
1503 				MDIFF(d, s2, s1, sctpOutOrderChunks);
1504 				MDIFF(d, s2, s1, sctpOutUnorderChunks);
1505 				MDIFF(d, s2, s1, sctpRetransChunks);
1506 				MDIFF(d, s2, s1, sctpOutAck);
1507 				MDIFF(d, s2, s1, sctpOutAckDelayed);
1508 				MDIFF(d, s2, s1, sctpOutWinUpdate);
1509 				MDIFF(d, s2, s1, sctpOutFastRetrans);
1510 				MDIFF(d, s2, s1, sctpOutWinProbe);
1511 				MDIFF(d, s2, s1, sctpInCtrlChunks);
1512 				MDIFF(d, s2, s1, sctpInOrderChunks);
1513 				MDIFF(d, s2, s1, sctpInUnorderChunks);
1514 				MDIFF(d, s2, s1, sctpInAck);
1515 				MDIFF(d, s2, s1, sctpInDupAck);
1516 				MDIFF(d, s2, s1, sctpInAckUnsent);
1517 				MDIFF(d, s2, s1, sctpFragUsrMsgs);
1518 				MDIFF(d, s2, s1, sctpReasmUsrMsgs);
1519 				MDIFF(d, s2, s1, sctpOutSCTPPkts);
1520 				MDIFF(d, s2, s1, sctpInSCTPPkts);
1521 				MDIFF(d, s2, s1, sctpInInvalidCookie);
1522 				MDIFF(d, s2, s1, sctpTimRetrans);
1523 				MDIFF(d, s2, s1, sctpTimRetransDrop);
1524 				MDIFF(d, s2, s1, sctpTimHeartBeatProbe);
1525 				MDIFF(d, s2, s1, sctpTimHeartBeatDrop);
1526 				MDIFF(d, s2, s1, sctpListenDrop);
1527 				MDIFF(d, s2, s1, sctpInClosed);
1528 				prevp = diffptr++;
1529 				break;
1530 			}
1531 			case EXPER_RAWIP: {
1532 				mib2_rawip_t *r2;
1533 				mib2_rawip_t *r1;
1534 				mib2_rawip_t *d;
1535 
1536 				r2 = (mib2_rawip_t *)tempp2->valp;
1537 				r1 = (mib2_rawip_t *)tempp1->valp;
1538 				diffptr->group = tempp2->group;
1539 				diffptr->mib_id = tempp2->mib_id;
1540 				diffptr->length = tempp2->length;
1541 				d = (mib2_rawip_t *)calloc(tempp2->length, 1);
1542 				if (d == NULL)
1543 					goto mibdiff_out_of_memory;
1544 				diffptr->valp = d;
1545 				MDIFF(d, r2, r1, rawipInDatagrams);
1546 				MDIFF(d, r2, r1, rawipInErrors);
1547 				MDIFF(d, r2, r1, rawipInCksumErrs);
1548 				MDIFF(d, r2, r1, rawipOutDatagrams);
1549 				MDIFF(d, r2, r1, rawipOutErrors);
1550 				prevp = diffptr++;
1551 				break;
1552 			}
1553 			/*
1554 			 * there are more "group" types but they aren't
1555 			 * required for the -s and -Ms options
1556 			 */
1557 			}
1558 		} /* 'for' loop 2 ends */
1559 		tempp1 = NULL;
1560 	} /* 'for' loop 1 ends */
1561 	tempp2 = NULL;
1562 	diffptr--;
1563 	diffptr->next_item = NULL;
1564 	return (diffp);
1565 
1566 mibdiff_out_of_memory:;
1567 	mib_item_destroy(&diffp);
1568 	return (NULL);
1569 }
1570 
1571 /*
1572  * mib_item_destroy: cleans up a mib_item_t *
1573  * that was created by calling mib_item_dup or
1574  * mib_item_diff
1575  */
1576 static void
1577 mib_item_destroy(mib_item_t **itemp)
1578 {
1579 	int	nitems = 0;
1580 	int	c = 0;
1581 	mib_item_t *tempp;
1582 
1583 	if (itemp == NULL || *itemp == NULL)
1584 		return;
1585 
1586 	for (tempp = *itemp; tempp != NULL; tempp = tempp->next_item)
1587 		if (tempp->mib_id == 0)
1588 			nitems++;
1589 		else
1590 			return;	/* cannot destroy! */
1591 
1592 	if (nitems == 0)
1593 		return;		/* cannot destroy! */
1594 
1595 	for (c = nitems - 1; c >= 0; c--) {
1596 		if ((itemp[0][c]).valp != NULL)
1597 			free((itemp[0][c]).valp);
1598 	}
1599 	free(*itemp);
1600 
1601 	*itemp = NULL;
1602 }
1603 
1604 /* Compare two Octet_ts.  Return B_TRUE if they match, B_FALSE if not. */
1605 static boolean_t
1606 octetstrmatch(const Octet_t *a, const Octet_t *b)
1607 {
1608 	if (a == NULL || b == NULL)
1609 		return (B_FALSE);
1610 
1611 	if (a->o_length != b->o_length)
1612 		return (B_FALSE);
1613 
1614 	return (memcmp(a->o_bytes, b->o_bytes, a->o_length) == 0);
1615 }
1616 
1617 /* If octetstr() changes make an appropriate change to STR_EXPAND */
1618 static char *
1619 octetstr(const Octet_t *op, int code, char *dst, uint_t dstlen)
1620 {
1621 	int	i;
1622 	char	*cp;
1623 
1624 	cp = dst;
1625 	if (op) {
1626 		for (i = 0; i < op->o_length; i++) {
1627 			switch (code) {
1628 			case 'd':
1629 				if (cp - dst + 4 > dstlen) {
1630 					*cp = '\0';
1631 					return (dst);
1632 				}
1633 				(void) snprintf(cp, 5, "%d.",
1634 				    0xff & op->o_bytes[i]);
1635 				cp = strchr(cp, '\0');
1636 				break;
1637 			case 'a':
1638 				if (cp - dst + 1 > dstlen) {
1639 					*cp = '\0';
1640 					return (dst);
1641 				}
1642 				*cp++ = op->o_bytes[i];
1643 				break;
1644 			case 'h':
1645 			default:
1646 				if (cp - dst + 3 > dstlen) {
1647 					*cp = '\0';
1648 					return (dst);
1649 				}
1650 				(void) snprintf(cp, 4, "%02x:",
1651 				    0xff & op->o_bytes[i]);
1652 				cp += 3;
1653 				break;
1654 			}
1655 		}
1656 	}
1657 	if (code != 'a' && cp != dst)
1658 		cp--;
1659 	*cp = '\0';
1660 	return (dst);
1661 }
1662 
1663 static const char *
1664 mitcp_state(int state, const mib2_transportMLPEntry_t *attr)
1665 {
1666 	static char tcpsbuf[50];
1667 	const char *cp;
1668 
1669 	switch (state) {
1670 	case TCPS_CLOSED:
1671 		cp = "CLOSED";
1672 		break;
1673 	case TCPS_IDLE:
1674 		cp = "IDLE";
1675 		break;
1676 	case TCPS_BOUND:
1677 		cp = "BOUND";
1678 		break;
1679 	case TCPS_LISTEN:
1680 		cp = "LISTEN";
1681 		break;
1682 	case TCPS_SYN_SENT:
1683 		cp = "SYN_SENT";
1684 		break;
1685 	case TCPS_SYN_RCVD:
1686 		cp = "SYN_RCVD";
1687 		break;
1688 	case TCPS_ESTABLISHED:
1689 		cp = "ESTABLISHED";
1690 		break;
1691 	case TCPS_CLOSE_WAIT:
1692 		cp = "CLOSE_WAIT";
1693 		break;
1694 	case TCPS_FIN_WAIT_1:
1695 		cp = "FIN_WAIT_1";
1696 		break;
1697 	case TCPS_CLOSING:
1698 		cp = "CLOSING";
1699 		break;
1700 	case TCPS_LAST_ACK:
1701 		cp = "LAST_ACK";
1702 		break;
1703 	case TCPS_FIN_WAIT_2:
1704 		cp = "FIN_WAIT_2";
1705 		break;
1706 	case TCPS_TIME_WAIT:
1707 		cp = "TIME_WAIT";
1708 		break;
1709 	default:
1710 		(void) snprintf(tcpsbuf, sizeof (tcpsbuf),
1711 		    "UnknownState(%d)", state);
1712 		cp = tcpsbuf;
1713 		break;
1714 	}
1715 
1716 	if (RSECflag && attr != NULL && attr->tme_flags != 0) {
1717 		if (cp != tcpsbuf) {
1718 			(void) strlcpy(tcpsbuf, cp, sizeof (tcpsbuf));
1719 			cp = tcpsbuf;
1720 		}
1721 		if (attr->tme_flags & MIB2_TMEF_PRIVATE)
1722 			(void) strlcat(tcpsbuf, " P", sizeof (tcpsbuf));
1723 		if (attr->tme_flags & MIB2_TMEF_SHARED)
1724 			(void) strlcat(tcpsbuf, " S", sizeof (tcpsbuf));
1725 	}
1726 
1727 	return (cp);
1728 }
1729 
1730 static const char *
1731 miudp_state(int state, const mib2_transportMLPEntry_t *attr)
1732 {
1733 	static char udpsbuf[50];
1734 	const char *cp;
1735 
1736 	switch (state) {
1737 	case MIB2_UDP_unbound:
1738 		cp = "Unbound";
1739 		break;
1740 	case MIB2_UDP_idle:
1741 		cp = "Idle";
1742 		break;
1743 	case MIB2_UDP_connected:
1744 		cp = "Connected";
1745 		break;
1746 	default:
1747 		(void) snprintf(udpsbuf, sizeof (udpsbuf),
1748 		    "Unknown State(%d)", state);
1749 		cp = udpsbuf;
1750 		break;
1751 	}
1752 
1753 	if (RSECflag && attr != NULL && attr->tme_flags != 0) {
1754 		if (cp != udpsbuf) {
1755 			(void) strlcpy(udpsbuf, cp, sizeof (udpsbuf));
1756 			cp = udpsbuf;
1757 		}
1758 		if (attr->tme_flags & MIB2_TMEF_PRIVATE)
1759 			(void) strlcat(udpsbuf, " P", sizeof (udpsbuf));
1760 		if (attr->tme_flags & MIB2_TMEF_SHARED)
1761 			(void) strlcat(udpsbuf, " S", sizeof (udpsbuf));
1762 	}
1763 
1764 	return (cp);
1765 }
1766 
1767 static int odd;
1768 
1769 static void
1770 prval_init(void)
1771 {
1772 	odd = 0;
1773 }
1774 
1775 static void
1776 prval(char *str, Counter val)
1777 {
1778 	(void) printf("\t%-20s=%6u", str, val);
1779 	if (odd++ & 1)
1780 		(void) putchar('\n');
1781 }
1782 
1783 static void
1784 prval64(char *str, Counter64 val)
1785 {
1786 	(void) printf("\t%-20s=%6llu", str, val);
1787 	if (odd++ & 1)
1788 		(void) putchar('\n');
1789 }
1790 
1791 static void
1792 pr_int_val(char *str, int val)
1793 {
1794 	(void) printf("\t%-20s=%6d", str, val);
1795 	if (odd++ & 1)
1796 		(void) putchar('\n');
1797 }
1798 
1799 static void
1800 pr_sctp_rtoalgo(char *str, int val)
1801 {
1802 	(void) printf("\t%-20s=", str);
1803 	switch (val) {
1804 		case MIB2_SCTP_RTOALGO_OTHER:
1805 			(void) printf("%6.6s", "other");
1806 			break;
1807 
1808 		case MIB2_SCTP_RTOALGO_VANJ:
1809 			(void) printf("%6.6s", "vanj");
1810 			break;
1811 
1812 		default:
1813 			(void) printf("%6d", val);
1814 			break;
1815 	}
1816 	if (odd++ & 1)
1817 		(void) putchar('\n');
1818 }
1819 
1820 static void
1821 prval_end(void)
1822 {
1823 	if (odd++ & 1)
1824 		(void) putchar('\n');
1825 }
1826 
1827 /* Extract constant sizes */
1828 static void
1829 mib_get_constants(mib_item_t *item)
1830 {
1831 	/* 'for' loop 1: */
1832 	for (; item; item = item->next_item) {
1833 		if (item->mib_id != 0)
1834 			continue; /* 'for' loop 1 */
1835 
1836 		switch (item->group) {
1837 		case MIB2_IP: {
1838 			mib2_ip_t	*ip = (mib2_ip_t *)item->valp;
1839 
1840 			ipAddrEntrySize = ip->ipAddrEntrySize;
1841 			ipRouteEntrySize = ip->ipRouteEntrySize;
1842 			ipNetToMediaEntrySize = ip->ipNetToMediaEntrySize;
1843 			ipMemberEntrySize = ip->ipMemberEntrySize;
1844 			ipGroupSourceEntrySize = ip->ipGroupSourceEntrySize;
1845 			ipRouteAttributeSize = ip->ipRouteAttributeSize;
1846 			transportMLPSize = ip->transportMLPSize;
1847 			ipDestEntrySize = ip->ipDestEntrySize;
1848 			assert(IS_P2ALIGNED(ipAddrEntrySize,
1849 			    sizeof (mib2_ipAddrEntry_t *)));
1850 			assert(IS_P2ALIGNED(ipRouteEntrySize,
1851 			    sizeof (mib2_ipRouteEntry_t *)));
1852 			assert(IS_P2ALIGNED(ipNetToMediaEntrySize,
1853 			    sizeof (mib2_ipNetToMediaEntry_t *)));
1854 			assert(IS_P2ALIGNED(ipMemberEntrySize,
1855 			    sizeof (ip_member_t *)));
1856 			assert(IS_P2ALIGNED(ipGroupSourceEntrySize,
1857 			    sizeof (ip_grpsrc_t *)));
1858 			assert(IS_P2ALIGNED(ipRouteAttributeSize,
1859 			    sizeof (mib2_ipAttributeEntry_t *)));
1860 			assert(IS_P2ALIGNED(transportMLPSize,
1861 			    sizeof (mib2_transportMLPEntry_t *)));
1862 			break;
1863 		}
1864 		case EXPER_DVMRP: {
1865 			struct mrtstat	*mrts = (struct mrtstat *)item->valp;
1866 
1867 			vifctlSize = mrts->mrts_vifctlSize;
1868 			mfcctlSize = mrts->mrts_mfcctlSize;
1869 			assert(IS_P2ALIGNED(vifctlSize,
1870 			    sizeof (struct vifclt *)));
1871 			assert(IS_P2ALIGNED(mfcctlSize,
1872 			    sizeof (struct mfcctl *)));
1873 			break;
1874 		}
1875 		case MIB2_IP6: {
1876 			mib2_ipv6IfStatsEntry_t *ip6;
1877 			/* Just use the first entry */
1878 
1879 			ip6 = (mib2_ipv6IfStatsEntry_t *)item->valp;
1880 			ipv6IfStatsEntrySize = ip6->ipv6IfStatsEntrySize;
1881 			ipv6AddrEntrySize = ip6->ipv6AddrEntrySize;
1882 			ipv6RouteEntrySize = ip6->ipv6RouteEntrySize;
1883 			ipv6NetToMediaEntrySize = ip6->ipv6NetToMediaEntrySize;
1884 			ipv6MemberEntrySize = ip6->ipv6MemberEntrySize;
1885 			ipv6GroupSourceEntrySize =
1886 			    ip6->ipv6GroupSourceEntrySize;
1887 			assert(IS_P2ALIGNED(ipv6IfStatsEntrySize,
1888 			    sizeof (mib2_ipv6IfStatsEntry_t *)));
1889 			assert(IS_P2ALIGNED(ipv6AddrEntrySize,
1890 			    sizeof (mib2_ipv6AddrEntry_t *)));
1891 			assert(IS_P2ALIGNED(ipv6RouteEntrySize,
1892 			    sizeof (mib2_ipv6RouteEntry_t *)));
1893 			assert(IS_P2ALIGNED(ipv6NetToMediaEntrySize,
1894 			    sizeof (mib2_ipv6NetToMediaEntry_t *)));
1895 			assert(IS_P2ALIGNED(ipv6MemberEntrySize,
1896 			    sizeof (ipv6_member_t *)));
1897 			assert(IS_P2ALIGNED(ipv6GroupSourceEntrySize,
1898 			    sizeof (ipv6_grpsrc_t *)));
1899 			break;
1900 		}
1901 		case MIB2_ICMP6: {
1902 			mib2_ipv6IfIcmpEntry_t *icmp6;
1903 			/* Just use the first entry */
1904 
1905 			icmp6 = (mib2_ipv6IfIcmpEntry_t *)item->valp;
1906 			ipv6IfIcmpEntrySize = icmp6->ipv6IfIcmpEntrySize;
1907 			assert(IS_P2ALIGNED(ipv6IfIcmpEntrySize,
1908 			    sizeof (mib2_ipv6IfIcmpEntry_t *)));
1909 			break;
1910 		}
1911 		case MIB2_TCP: {
1912 			mib2_tcp_t	*tcp = (mib2_tcp_t *)item->valp;
1913 
1914 			tcpConnEntrySize = tcp->tcpConnTableSize;
1915 			tcp6ConnEntrySize = tcp->tcp6ConnTableSize;
1916 			assert(IS_P2ALIGNED(tcpConnEntrySize,
1917 			    sizeof (mib2_tcpConnEntry_t *)));
1918 			assert(IS_P2ALIGNED(tcp6ConnEntrySize,
1919 			    sizeof (mib2_tcp6ConnEntry_t *)));
1920 			break;
1921 		}
1922 		case MIB2_UDP: {
1923 			mib2_udp_t	*udp = (mib2_udp_t *)item->valp;
1924 
1925 			udpEntrySize = udp->udpEntrySize;
1926 			udp6EntrySize = udp->udp6EntrySize;
1927 			assert(IS_P2ALIGNED(udpEntrySize,
1928 			    sizeof (mib2_udpEntry_t *)));
1929 			assert(IS_P2ALIGNED(udp6EntrySize,
1930 			    sizeof (mib2_udp6Entry_t *)));
1931 			break;
1932 		}
1933 		case MIB2_SCTP: {
1934 			mib2_sctp_t	*sctp = (mib2_sctp_t *)item->valp;
1935 
1936 			sctpEntrySize = sctp->sctpEntrySize;
1937 			sctpLocalEntrySize = sctp->sctpLocalEntrySize;
1938 			sctpRemoteEntrySize = sctp->sctpRemoteEntrySize;
1939 			break;
1940 		}
1941 		}
1942 	} /* 'for' loop 1 ends */
1943 
1944 	if (Xflag) {
1945 		(void) puts("mib_get_constants:");
1946 		(void) printf("\tipv6IfStatsEntrySize %d\n",
1947 		    ipv6IfStatsEntrySize);
1948 		(void) printf("\tipAddrEntrySize %d\n", ipAddrEntrySize);
1949 		(void) printf("\tipRouteEntrySize %d\n", ipRouteEntrySize);
1950 		(void) printf("\tipNetToMediaEntrySize %d\n",
1951 		    ipNetToMediaEntrySize);
1952 		(void) printf("\tipMemberEntrySize %d\n", ipMemberEntrySize);
1953 		(void) printf("\tipRouteAttributeSize %d\n",
1954 		    ipRouteAttributeSize);
1955 		(void) printf("\tvifctlSize %d\n", vifctlSize);
1956 		(void) printf("\tmfcctlSize %d\n", mfcctlSize);
1957 
1958 		(void) printf("\tipv6AddrEntrySize %d\n", ipv6AddrEntrySize);
1959 		(void) printf("\tipv6RouteEntrySize %d\n", ipv6RouteEntrySize);
1960 		(void) printf("\tipv6NetToMediaEntrySize %d\n",
1961 		    ipv6NetToMediaEntrySize);
1962 		(void) printf("\tipv6MemberEntrySize %d\n",
1963 		    ipv6MemberEntrySize);
1964 		(void) printf("\tipv6IfIcmpEntrySize %d\n",
1965 		    ipv6IfIcmpEntrySize);
1966 		(void) printf("\tipDestEntrySize %d\n", ipDestEntrySize);
1967 		(void) printf("\ttransportMLPSize %d\n", transportMLPSize);
1968 		(void) printf("\ttcpConnEntrySize %d\n", tcpConnEntrySize);
1969 		(void) printf("\ttcp6ConnEntrySize %d\n", tcp6ConnEntrySize);
1970 		(void) printf("\tudpEntrySize %d\n", udpEntrySize);
1971 		(void) printf("\tudp6EntrySize %d\n", udp6EntrySize);
1972 		(void) printf("\tsctpEntrySize %d\n", sctpEntrySize);
1973 		(void) printf("\tsctpLocalEntrySize %d\n", sctpLocalEntrySize);
1974 		(void) printf("\tsctpRemoteEntrySize %d\n",
1975 		    sctpRemoteEntrySize);
1976 	}
1977 }
1978 
1979 
1980 /* ----------------------------- STAT_REPORT ------------------------------- */
1981 
1982 static void
1983 stat_report(mib_item_t *item)
1984 {
1985 	int	jtemp = 0;
1986 	char	ifname[LIFNAMSIZ + 1];
1987 
1988 	/* 'for' loop 1: */
1989 	for (; item; item = item->next_item) {
1990 		if (Xflag) {
1991 			(void) printf("\n--- Entry %d ---\n", ++jtemp);
1992 			(void) printf("Group = %d, mib_id = %d, "
1993 			    "length = %d, valp = 0x%p\n",
1994 			    item->group, item->mib_id,
1995 			    item->length, item->valp);
1996 		}
1997 		if (item->mib_id != 0)
1998 			continue; /* 'for' loop 1 */
1999 
2000 		switch (item->group) {
2001 		case MIB2_IP: {
2002 			mib2_ip_t	*ip = (mib2_ip_t *)item->valp;
2003 
2004 			if (protocol_selected(IPPROTO_IP) &&
2005 			    family_selected(AF_INET)) {
2006 				(void) fputs(v4compat ? "\nIP" : "\nIPv4",
2007 				    stdout);
2008 				print_ip_stats(ip);
2009 			}
2010 			break;
2011 		}
2012 		case MIB2_ICMP: {
2013 			mib2_icmp_t	*icmp =
2014 			    (mib2_icmp_t *)item->valp;
2015 
2016 			if (protocol_selected(IPPROTO_ICMP) &&
2017 			    family_selected(AF_INET)) {
2018 				(void) fputs(v4compat ? "\nICMP" : "\nICMPv4",
2019 				    stdout);
2020 				print_icmp_stats(icmp);
2021 			}
2022 			break;
2023 		}
2024 		case MIB2_IP6: {
2025 			mib2_ipv6IfStatsEntry_t *ip6;
2026 			mib2_ipv6IfStatsEntry_t sum6;
2027 
2028 			if (!(protocol_selected(IPPROTO_IPV6)) ||
2029 			    !(family_selected(AF_INET6)))
2030 				break;
2031 			bzero(&sum6, sizeof (sum6));
2032 			/* 'for' loop 2a: */
2033 			for (ip6 = (mib2_ipv6IfStatsEntry_t *)item->valp;
2034 			    (char *)ip6 < (char *)item->valp + item->length;
2035 			    /* LINTED: (note 1) */
2036 			    ip6 = (mib2_ipv6IfStatsEntry_t *)((char *)ip6 +
2037 			    ipv6IfStatsEntrySize)) {
2038 				if (ip6->ipv6IfIndex == 0) {
2039 					/*
2040 					 * The "unknown interface" ip6
2041 					 * mib. Just add to the sum.
2042 					 */
2043 					sum_ip6_stats(ip6, &sum6);
2044 					continue; /* 'for' loop 2a */
2045 				}
2046 				if (Aflag) {
2047 					(void) printf("\nIPv6 for %s\n",
2048 					    ifindex2str(ip6->ipv6IfIndex,
2049 					    ifname));
2050 					print_ip6_stats(ip6);
2051 				}
2052 				sum_ip6_stats(ip6, &sum6);
2053 			} /* 'for' loop 2a ends */
2054 			(void) fputs("\nIPv6", stdout);
2055 			print_ip6_stats(&sum6);
2056 			break;
2057 		}
2058 		case MIB2_ICMP6: {
2059 			mib2_ipv6IfIcmpEntry_t *icmp6;
2060 			mib2_ipv6IfIcmpEntry_t sum6;
2061 
2062 			if (!(protocol_selected(IPPROTO_ICMPV6)) ||
2063 			    !(family_selected(AF_INET6)))
2064 				break;
2065 			bzero(&sum6, sizeof (sum6));
2066 			/* 'for' loop 2b: */
2067 			for (icmp6 = (mib2_ipv6IfIcmpEntry_t *)item->valp;
2068 			    (char *)icmp6 < (char *)item->valp + item->length;
2069 			    icmp6 = (void *)((char *)icmp6 +
2070 			    ipv6IfIcmpEntrySize)) {
2071 				if (icmp6->ipv6IfIcmpIfIndex == 0) {
2072 					/*
2073 					 * The "unknown interface" icmp6
2074 					 * mib. Just add to the sum.
2075 					 */
2076 					sum_icmp6_stats(icmp6, &sum6);
2077 					continue; /* 'for' loop 2b: */
2078 				}
2079 				if (Aflag) {
2080 					(void) printf("\nICMPv6 for %s\n",
2081 					    ifindex2str(
2082 					    icmp6->ipv6IfIcmpIfIndex, ifname));
2083 					print_icmp6_stats(icmp6);
2084 				}
2085 				sum_icmp6_stats(icmp6, &sum6);
2086 			} /* 'for' loop 2b ends */
2087 			(void) fputs("\nICMPv6", stdout);
2088 			print_icmp6_stats(&sum6);
2089 			break;
2090 		}
2091 		case MIB2_TCP: {
2092 			mib2_tcp_t	*tcp = (mib2_tcp_t *)item->valp;
2093 
2094 			if (protocol_selected(IPPROTO_TCP) &&
2095 			    (family_selected(AF_INET) ||
2096 			    family_selected(AF_INET6))) {
2097 				(void) fputs("\nTCP", stdout);
2098 				print_tcp_stats(tcp);
2099 			}
2100 			break;
2101 		}
2102 		case MIB2_UDP: {
2103 			mib2_udp_t	*udp = (mib2_udp_t *)item->valp;
2104 
2105 			if (protocol_selected(IPPROTO_UDP) &&
2106 			    (family_selected(AF_INET) ||
2107 			    family_selected(AF_INET6))) {
2108 				(void) fputs("\nUDP", stdout);
2109 				print_udp_stats(udp);
2110 			}
2111 			break;
2112 		}
2113 		case MIB2_SCTP: {
2114 			mib2_sctp_t	*sctp = (mib2_sctp_t *)item->valp;
2115 
2116 			if (protocol_selected(IPPROTO_SCTP) &&
2117 			    (family_selected(AF_INET) ||
2118 			    family_selected(AF_INET6))) {
2119 				(void) fputs("\nSCTP", stdout);
2120 				print_sctp_stats(sctp);
2121 			}
2122 			break;
2123 		}
2124 		case EXPER_RAWIP: {
2125 			mib2_rawip_t	*rawip =
2126 			    (mib2_rawip_t *)item->valp;
2127 
2128 			if (protocol_selected(IPPROTO_RAW) &&
2129 			    (family_selected(AF_INET) ||
2130 			    family_selected(AF_INET6))) {
2131 				(void) fputs("\nRAWIP", stdout);
2132 				print_rawip_stats(rawip);
2133 			}
2134 			break;
2135 		}
2136 		case EXPER_IGMP: {
2137 			struct igmpstat	*igps =
2138 			    (struct igmpstat *)item->valp;
2139 
2140 			if (protocol_selected(IPPROTO_IGMP) &&
2141 			    (family_selected(AF_INET))) {
2142 				(void) fputs("\nIGMP:\n", stdout);
2143 				print_igmp_stats(igps);
2144 			}
2145 			break;
2146 		}
2147 		}
2148 	} /* 'for' loop 1 ends */
2149 	(void) putchar('\n');
2150 	(void) fflush(stdout);
2151 }
2152 
2153 static void
2154 print_ip_stats(mib2_ip_t *ip)
2155 {
2156 	prval_init();
2157 	pr_int_val("ipForwarding",	ip->ipForwarding);
2158 	pr_int_val("ipDefaultTTL",	ip->ipDefaultTTL);
2159 	prval("ipInReceives",		ip->ipInReceives);
2160 	prval("ipInHdrErrors",		ip->ipInHdrErrors);
2161 	prval("ipInAddrErrors",		ip->ipInAddrErrors);
2162 	prval("ipInCksumErrs",		ip->ipInCksumErrs);
2163 	prval("ipForwDatagrams",	ip->ipForwDatagrams);
2164 	prval("ipForwProhibits",	ip->ipForwProhibits);
2165 	prval("ipInUnknownProtos",	ip->ipInUnknownProtos);
2166 	prval("ipInDiscards",		ip->ipInDiscards);
2167 	prval("ipInDelivers",		ip->ipInDelivers);
2168 	prval("ipOutRequests",		ip->ipOutRequests);
2169 	prval("ipOutDiscards",		ip->ipOutDiscards);
2170 	prval("ipOutNoRoutes",		ip->ipOutNoRoutes);
2171 	pr_int_val("ipReasmTimeout",	ip->ipReasmTimeout);
2172 	prval("ipReasmReqds",		ip->ipReasmReqds);
2173 	prval("ipReasmOKs",		ip->ipReasmOKs);
2174 	prval("ipReasmFails",		ip->ipReasmFails);
2175 	prval("ipReasmDuplicates",	ip->ipReasmDuplicates);
2176 	prval("ipReasmPartDups",	ip->ipReasmPartDups);
2177 	prval("ipFragOKs",		ip->ipFragOKs);
2178 	prval("ipFragFails",		ip->ipFragFails);
2179 	prval("ipFragCreates",		ip->ipFragCreates);
2180 	prval("ipRoutingDiscards",	ip->ipRoutingDiscards);
2181 
2182 	prval("tcpInErrs",		ip->tcpInErrs);
2183 	prval("udpNoPorts",		ip->udpNoPorts);
2184 	prval("udpInCksumErrs",		ip->udpInCksumErrs);
2185 	prval("udpInOverflows",		ip->udpInOverflows);
2186 	prval("rawipInOverflows",	ip->rawipInOverflows);
2187 	prval("ipsecInSucceeded",	ip->ipsecInSucceeded);
2188 	prval("ipsecInFailed",		ip->ipsecInFailed);
2189 	prval("ipInIPv6",		ip->ipInIPv6);
2190 	prval("ipOutIPv6",		ip->ipOutIPv6);
2191 	prval("ipOutSwitchIPv6",	ip->ipOutSwitchIPv6);
2192 	prval_end();
2193 }
2194 
2195 static void
2196 print_icmp_stats(mib2_icmp_t *icmp)
2197 {
2198 	prval_init();
2199 	prval("icmpInMsgs",		icmp->icmpInMsgs);
2200 	prval("icmpInErrors",		icmp->icmpInErrors);
2201 	prval("icmpInCksumErrs",	icmp->icmpInCksumErrs);
2202 	prval("icmpInUnknowns",		icmp->icmpInUnknowns);
2203 	prval("icmpInDestUnreachs",	icmp->icmpInDestUnreachs);
2204 	prval("icmpInTimeExcds",	icmp->icmpInTimeExcds);
2205 	prval("icmpInParmProbs",	icmp->icmpInParmProbs);
2206 	prval("icmpInSrcQuenchs",	icmp->icmpInSrcQuenchs);
2207 	prval("icmpInRedirects",	icmp->icmpInRedirects);
2208 	prval("icmpInBadRedirects",	icmp->icmpInBadRedirects);
2209 	prval("icmpInEchos",		icmp->icmpInEchos);
2210 	prval("icmpInEchoReps",		icmp->icmpInEchoReps);
2211 	prval("icmpInTimestamps",	icmp->icmpInTimestamps);
2212 	prval("icmpInTimestampReps",	icmp->icmpInTimestampReps);
2213 	prval("icmpInAddrMasks",	icmp->icmpInAddrMasks);
2214 	prval("icmpInAddrMaskReps",	icmp->icmpInAddrMaskReps);
2215 	prval("icmpInFragNeeded",	icmp->icmpInFragNeeded);
2216 	prval("icmpOutMsgs",		icmp->icmpOutMsgs);
2217 	prval("icmpOutDrops",		icmp->icmpOutDrops);
2218 	prval("icmpOutErrors",		icmp->icmpOutErrors);
2219 	prval("icmpOutDestUnreachs",	icmp->icmpOutDestUnreachs);
2220 	prval("icmpOutTimeExcds",	icmp->icmpOutTimeExcds);
2221 	prval("icmpOutParmProbs",	icmp->icmpOutParmProbs);
2222 	prval("icmpOutSrcQuenchs",	icmp->icmpOutSrcQuenchs);
2223 	prval("icmpOutRedirects",	icmp->icmpOutRedirects);
2224 	prval("icmpOutEchos",		icmp->icmpOutEchos);
2225 	prval("icmpOutEchoReps",	icmp->icmpOutEchoReps);
2226 	prval("icmpOutTimestamps",	icmp->icmpOutTimestamps);
2227 	prval("icmpOutTimestampReps",	icmp->icmpOutTimestampReps);
2228 	prval("icmpOutAddrMasks",	icmp->icmpOutAddrMasks);
2229 	prval("icmpOutAddrMaskReps",	icmp->icmpOutAddrMaskReps);
2230 	prval("icmpOutFragNeeded",	icmp->icmpOutFragNeeded);
2231 	prval("icmpInOverflows",	icmp->icmpInOverflows);
2232 	prval_end();
2233 }
2234 
2235 static void
2236 print_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6)
2237 {
2238 	prval_init();
2239 	prval("ipv6Forwarding",		ip6->ipv6Forwarding);
2240 	prval("ipv6DefaultHopLimit",	ip6->ipv6DefaultHopLimit);
2241 
2242 	prval("ipv6InReceives",		ip6->ipv6InReceives);
2243 	prval("ipv6InHdrErrors",	ip6->ipv6InHdrErrors);
2244 	prval("ipv6InTooBigErrors",	ip6->ipv6InTooBigErrors);
2245 	prval("ipv6InNoRoutes",		ip6->ipv6InNoRoutes);
2246 	prval("ipv6InAddrErrors",	ip6->ipv6InAddrErrors);
2247 	prval("ipv6InUnknownProtos",	ip6->ipv6InUnknownProtos);
2248 	prval("ipv6InTruncatedPkts",	ip6->ipv6InTruncatedPkts);
2249 	prval("ipv6InDiscards",		ip6->ipv6InDiscards);
2250 	prval("ipv6InDelivers",		ip6->ipv6InDelivers);
2251 	prval("ipv6OutForwDatagrams",	ip6->ipv6OutForwDatagrams);
2252 	prval("ipv6OutRequests",	ip6->ipv6OutRequests);
2253 	prval("ipv6OutDiscards",	ip6->ipv6OutDiscards);
2254 	prval("ipv6OutNoRoutes",	ip6->ipv6OutNoRoutes);
2255 	prval("ipv6OutFragOKs",		ip6->ipv6OutFragOKs);
2256 	prval("ipv6OutFragFails",	ip6->ipv6OutFragFails);
2257 	prval("ipv6OutFragCreates",	ip6->ipv6OutFragCreates);
2258 	prval("ipv6ReasmReqds",		ip6->ipv6ReasmReqds);
2259 	prval("ipv6ReasmOKs",		ip6->ipv6ReasmOKs);
2260 	prval("ipv6ReasmFails",		ip6->ipv6ReasmFails);
2261 	prval("ipv6InMcastPkts",	ip6->ipv6InMcastPkts);
2262 	prval("ipv6OutMcastPkts",	ip6->ipv6OutMcastPkts);
2263 	prval("ipv6ReasmDuplicates",	ip6->ipv6ReasmDuplicates);
2264 	prval("ipv6ReasmPartDups",	ip6->ipv6ReasmPartDups);
2265 	prval("ipv6ForwProhibits",	ip6->ipv6ForwProhibits);
2266 	prval("udpInCksumErrs",		ip6->udpInCksumErrs);
2267 	prval("udpInOverflows",		ip6->udpInOverflows);
2268 	prval("rawipInOverflows",	ip6->rawipInOverflows);
2269 	prval("ipv6InIPv4",		ip6->ipv6InIPv4);
2270 	prval("ipv6OutIPv4",		ip6->ipv6OutIPv4);
2271 	prval("ipv6OutSwitchIPv4",	ip6->ipv6OutSwitchIPv4);
2272 	prval_end();
2273 }
2274 
2275 static void
2276 print_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6)
2277 {
2278 	prval_init();
2279 	prval("icmp6InMsgs",		icmp6->ipv6IfIcmpInMsgs);
2280 	prval("icmp6InErrors",		icmp6->ipv6IfIcmpInErrors);
2281 	prval("icmp6InDestUnreachs",	icmp6->ipv6IfIcmpInDestUnreachs);
2282 	prval("icmp6InAdminProhibs",	icmp6->ipv6IfIcmpInAdminProhibs);
2283 	prval("icmp6InTimeExcds",	icmp6->ipv6IfIcmpInTimeExcds);
2284 	prval("icmp6InParmProblems",	icmp6->ipv6IfIcmpInParmProblems);
2285 	prval("icmp6InPktTooBigs",	icmp6->ipv6IfIcmpInPktTooBigs);
2286 	prval("icmp6InEchos",		icmp6->ipv6IfIcmpInEchos);
2287 	prval("icmp6InEchoReplies",	icmp6->ipv6IfIcmpInEchoReplies);
2288 	prval("icmp6InRouterSols",	icmp6->ipv6IfIcmpInRouterSolicits);
2289 	prval("icmp6InRouterAds",
2290 	    icmp6->ipv6IfIcmpInRouterAdvertisements);
2291 	prval("icmp6InNeighborSols",	icmp6->ipv6IfIcmpInNeighborSolicits);
2292 	prval("icmp6InNeighborAds",
2293 	    icmp6->ipv6IfIcmpInNeighborAdvertisements);
2294 	prval("icmp6InRedirects",	icmp6->ipv6IfIcmpInRedirects);
2295 	prval("icmp6InBadRedirects",	icmp6->ipv6IfIcmpInBadRedirects);
2296 	prval("icmp6InGroupQueries",	icmp6->ipv6IfIcmpInGroupMembQueries);
2297 	prval("icmp6InGroupResps",	icmp6->ipv6IfIcmpInGroupMembResponses);
2298 	prval("icmp6InGroupReds",	icmp6->ipv6IfIcmpInGroupMembReductions);
2299 	prval("icmp6InOverflows",	icmp6->ipv6IfIcmpInOverflows);
2300 	prval_end();
2301 	prval_init();
2302 	prval("icmp6OutMsgs",		icmp6->ipv6IfIcmpOutMsgs);
2303 	prval("icmp6OutErrors",		icmp6->ipv6IfIcmpOutErrors);
2304 	prval("icmp6OutDestUnreachs",	icmp6->ipv6IfIcmpOutDestUnreachs);
2305 	prval("icmp6OutAdminProhibs",	icmp6->ipv6IfIcmpOutAdminProhibs);
2306 	prval("icmp6OutTimeExcds",	icmp6->ipv6IfIcmpOutTimeExcds);
2307 	prval("icmp6OutParmProblems",	icmp6->ipv6IfIcmpOutParmProblems);
2308 	prval("icmp6OutPktTooBigs",	icmp6->ipv6IfIcmpOutPktTooBigs);
2309 	prval("icmp6OutEchos",		icmp6->ipv6IfIcmpOutEchos);
2310 	prval("icmp6OutEchoReplies",	icmp6->ipv6IfIcmpOutEchoReplies);
2311 	prval("icmp6OutRouterSols",	icmp6->ipv6IfIcmpOutRouterSolicits);
2312 	prval("icmp6OutRouterAds",
2313 	    icmp6->ipv6IfIcmpOutRouterAdvertisements);
2314 	prval("icmp6OutNeighborSols",	icmp6->ipv6IfIcmpOutNeighborSolicits);
2315 	prval("icmp6OutNeighborAds",
2316 	    icmp6->ipv6IfIcmpOutNeighborAdvertisements);
2317 	prval("icmp6OutRedirects",	icmp6->ipv6IfIcmpOutRedirects);
2318 	prval("icmp6OutGroupQueries",	icmp6->ipv6IfIcmpOutGroupMembQueries);
2319 	prval("icmp6OutGroupResps",
2320 	    icmp6->ipv6IfIcmpOutGroupMembResponses);
2321 	prval("icmp6OutGroupReds",
2322 	    icmp6->ipv6IfIcmpOutGroupMembReductions);
2323 	prval_end();
2324 }
2325 
2326 static void
2327 print_sctp_stats(mib2_sctp_t *sctp)
2328 {
2329 	prval_init();
2330 	pr_sctp_rtoalgo("sctpRtoAlgorithm", sctp->sctpRtoAlgorithm);
2331 	prval("sctpRtoMin",		sctp->sctpRtoMin);
2332 	prval("sctpRtoMax",		sctp->sctpRtoMax);
2333 	prval("sctpRtoInitial",		sctp->sctpRtoInitial);
2334 	pr_int_val("sctpMaxAssocs",	sctp->sctpMaxAssocs);
2335 	prval("sctpValCookieLife",	sctp->sctpValCookieLife);
2336 	prval("sctpMaxInitRetr",	sctp->sctpMaxInitRetr);
2337 	prval("sctpCurrEstab",		sctp->sctpCurrEstab);
2338 	prval("sctpActiveEstab",	sctp->sctpActiveEstab);
2339 	prval("sctpPassiveEstab",	sctp->sctpPassiveEstab);
2340 	prval("sctpAborted",		sctp->sctpAborted);
2341 	prval("sctpShutdowns",		sctp->sctpShutdowns);
2342 	prval("sctpOutOfBlue",		sctp->sctpOutOfBlue);
2343 	prval("sctpChecksumError",	sctp->sctpChecksumError);
2344 	prval64("sctpOutCtrlChunks",	sctp->sctpOutCtrlChunks);
2345 	prval64("sctpOutOrderChunks",	sctp->sctpOutOrderChunks);
2346 	prval64("sctpOutUnorderChunks",	sctp->sctpOutUnorderChunks);
2347 	prval64("sctpRetransChunks",	sctp->sctpRetransChunks);
2348 	prval("sctpOutAck",		sctp->sctpOutAck);
2349 	prval("sctpOutAckDelayed",	sctp->sctpOutAckDelayed);
2350 	prval("sctpOutWinUpdate",	sctp->sctpOutWinUpdate);
2351 	prval("sctpOutFastRetrans",	sctp->sctpOutFastRetrans);
2352 	prval("sctpOutWinProbe",	sctp->sctpOutWinProbe);
2353 	prval64("sctpInCtrlChunks",	sctp->sctpInCtrlChunks);
2354 	prval64("sctpInOrderChunks",	sctp->sctpInOrderChunks);
2355 	prval64("sctpInUnorderChunks",	sctp->sctpInUnorderChunks);
2356 	prval("sctpInAck",		sctp->sctpInAck);
2357 	prval("sctpInDupAck",		sctp->sctpInDupAck);
2358 	prval("sctpInAckUnsent",	sctp->sctpInAckUnsent);
2359 	prval64("sctpFragUsrMsgs",	sctp->sctpFragUsrMsgs);
2360 	prval64("sctpReasmUsrMsgs",	sctp->sctpReasmUsrMsgs);
2361 	prval64("sctpOutSCTPPkts",	sctp->sctpOutSCTPPkts);
2362 	prval64("sctpInSCTPPkts",	sctp->sctpInSCTPPkts);
2363 	prval("sctpInInvalidCookie",	sctp->sctpInInvalidCookie);
2364 	prval("sctpTimRetrans",		sctp->sctpTimRetrans);
2365 	prval("sctpTimRetransDrop",	sctp->sctpTimRetransDrop);
2366 	prval("sctpTimHearBeatProbe",	sctp->sctpTimHeartBeatProbe);
2367 	prval("sctpTimHearBeatDrop",	sctp->sctpTimHeartBeatDrop);
2368 	prval("sctpListenDrop",		sctp->sctpListenDrop);
2369 	prval("sctpInClosed",		sctp->sctpInClosed);
2370 	prval_end();
2371 }
2372 
2373 static void
2374 print_tcp_stats(mib2_tcp_t *tcp)
2375 {
2376 	prval_init();
2377 	pr_int_val("tcpRtoAlgorithm",	tcp->tcpRtoAlgorithm);
2378 	pr_int_val("tcpRtoMin",		tcp->tcpRtoMin);
2379 	pr_int_val("tcpRtoMax",		tcp->tcpRtoMax);
2380 	pr_int_val("tcpMaxConn",	tcp->tcpMaxConn);
2381 	prval("tcpActiveOpens",		tcp->tcpActiveOpens);
2382 	prval("tcpPassiveOpens",	tcp->tcpPassiveOpens);
2383 	prval("tcpAttemptFails",	tcp->tcpAttemptFails);
2384 	prval("tcpEstabResets",		tcp->tcpEstabResets);
2385 	prval("tcpCurrEstab",		tcp->tcpCurrEstab);
2386 	prval64("tcpOutSegs",		tcp->tcpHCOutSegs);
2387 	prval("tcpOutDataSegs",		tcp->tcpOutDataSegs);
2388 	prval("tcpOutDataBytes",	tcp->tcpOutDataBytes);
2389 	prval("tcpRetransSegs",		tcp->tcpRetransSegs);
2390 	prval("tcpRetransBytes",	tcp->tcpRetransBytes);
2391 	prval("tcpOutAck",		tcp->tcpOutAck);
2392 	prval("tcpOutAckDelayed",	tcp->tcpOutAckDelayed);
2393 	prval("tcpOutUrg",		tcp->tcpOutUrg);
2394 	prval("tcpOutWinUpdate",	tcp->tcpOutWinUpdate);
2395 	prval("tcpOutWinProbe",		tcp->tcpOutWinProbe);
2396 	prval("tcpOutControl",		tcp->tcpOutControl);
2397 	prval("tcpOutRsts",		tcp->tcpOutRsts);
2398 	prval("tcpOutFastRetrans",	tcp->tcpOutFastRetrans);
2399 	prval64("tcpInSegs",		tcp->tcpHCInSegs);
2400 	prval_end();
2401 	prval("tcpInAckSegs",		tcp->tcpInAckSegs);
2402 	prval("tcpInAckBytes",		tcp->tcpInAckBytes);
2403 	prval("tcpInDupAck",		tcp->tcpInDupAck);
2404 	prval("tcpInAckUnsent",		tcp->tcpInAckUnsent);
2405 	prval("tcpInInorderSegs",	tcp->tcpInDataInorderSegs);
2406 	prval("tcpInInorderBytes",	tcp->tcpInDataInorderBytes);
2407 	prval("tcpInUnorderSegs",	tcp->tcpInDataUnorderSegs);
2408 	prval("tcpInUnorderBytes",	tcp->tcpInDataUnorderBytes);
2409 	prval("tcpInDupSegs",		tcp->tcpInDataDupSegs);
2410 	prval("tcpInDupBytes",		tcp->tcpInDataDupBytes);
2411 	prval("tcpInPartDupSegs",	tcp->tcpInDataPartDupSegs);
2412 	prval("tcpInPartDupBytes",	tcp->tcpInDataPartDupBytes);
2413 	prval("tcpInPastWinSegs",	tcp->tcpInDataPastWinSegs);
2414 	prval("tcpInPastWinBytes",	tcp->tcpInDataPastWinBytes);
2415 	prval("tcpInWinProbe",		tcp->tcpInWinProbe);
2416 	prval("tcpInWinUpdate",		tcp->tcpInWinUpdate);
2417 	prval("tcpInClosed",		tcp->tcpInClosed);
2418 	prval("tcpRttNoUpdate",		tcp->tcpRttNoUpdate);
2419 	prval("tcpRttUpdate",		tcp->tcpRttUpdate);
2420 	prval("tcpTimRetrans",		tcp->tcpTimRetrans);
2421 	prval("tcpTimRetransDrop",	tcp->tcpTimRetransDrop);
2422 	prval("tcpTimKeepalive",	tcp->tcpTimKeepalive);
2423 	prval("tcpTimKeepaliveProbe",	tcp->tcpTimKeepaliveProbe);
2424 	prval("tcpTimKeepaliveDrop",	tcp->tcpTimKeepaliveDrop);
2425 	prval("tcpListenDrop",		tcp->tcpListenDrop);
2426 	prval("tcpListenDropQ0",	tcp->tcpListenDropQ0);
2427 	prval("tcpHalfOpenDrop",	tcp->tcpHalfOpenDrop);
2428 	prval("tcpOutSackRetrans",	tcp->tcpOutSackRetransSegs);
2429 	prval_end();
2430 
2431 }
2432 
2433 static void
2434 print_udp_stats(mib2_udp_t *udp)
2435 {
2436 	prval_init();
2437 	prval64("udpInDatagrams",	udp->udpHCInDatagrams);
2438 	prval("udpInErrors",		udp->udpInErrors);
2439 	prval64("udpOutDatagrams",	udp->udpHCOutDatagrams);
2440 	prval("udpOutErrors",		udp->udpOutErrors);
2441 	prval_end();
2442 }
2443 
2444 static void
2445 print_rawip_stats(mib2_rawip_t *rawip)
2446 {
2447 	prval_init();
2448 	prval("rawipInDatagrams",	rawip->rawipInDatagrams);
2449 	prval("rawipInErrors",		rawip->rawipInErrors);
2450 	prval("rawipInCksumErrs",	rawip->rawipInCksumErrs);
2451 	prval("rawipOutDatagrams",	rawip->rawipOutDatagrams);
2452 	prval("rawipOutErrors",		rawip->rawipOutErrors);
2453 	prval_end();
2454 }
2455 
2456 void
2457 print_igmp_stats(struct igmpstat *igps)
2458 {
2459 	(void) printf(" %10u message%s received\n",
2460 	    igps->igps_rcv_total, PLURAL(igps->igps_rcv_total));
2461 	(void) printf(" %10u message%s received with too few bytes\n",
2462 	    igps->igps_rcv_tooshort, PLURAL(igps->igps_rcv_tooshort));
2463 	(void) printf(" %10u message%s received with bad checksum\n",
2464 	    igps->igps_rcv_badsum, PLURAL(igps->igps_rcv_badsum));
2465 	(void) printf(" %10u membership quer%s received\n",
2466 	    igps->igps_rcv_queries, PLURALY(igps->igps_rcv_queries));
2467 	(void) printf(" %10u membership quer%s received with invalid "
2468 	    "field(s)\n",
2469 	    igps->igps_rcv_badqueries, PLURALY(igps->igps_rcv_badqueries));
2470 	(void) printf(" %10u membership report%s received\n",
2471 	    igps->igps_rcv_reports, PLURAL(igps->igps_rcv_reports));
2472 	(void) printf(" %10u membership report%s received with invalid "
2473 	    "field(s)\n",
2474 	    igps->igps_rcv_badreports, PLURAL(igps->igps_rcv_badreports));
2475 	(void) printf(" %10u membership report%s received for groups to "
2476 	    "which we belong\n",
2477 	    igps->igps_rcv_ourreports, PLURAL(igps->igps_rcv_ourreports));
2478 	(void) printf(" %10u membership report%s sent\n",
2479 	    igps->igps_snd_reports, PLURAL(igps->igps_snd_reports));
2480 }
2481 
2482 static void
2483 print_mrt_stats(struct mrtstat *mrts)
2484 {
2485 	(void) puts("DVMRP multicast routing:");
2486 	(void) printf(" %10u hit%s - kernel forwarding cache hits\n",
2487 	    mrts->mrts_mfc_hits, PLURAL(mrts->mrts_mfc_hits));
2488 	(void) printf(" %10u miss%s - kernel forwarding cache misses\n",
2489 	    mrts->mrts_mfc_misses, PLURALES(mrts->mrts_mfc_misses));
2490 	(void) printf(" %10u packet%s potentially forwarded\n",
2491 	    mrts->mrts_fwd_in, PLURAL(mrts->mrts_fwd_in));
2492 	(void) printf(" %10u packet%s actually sent out\n",
2493 	    mrts->mrts_fwd_out, PLURAL(mrts->mrts_fwd_out));
2494 	(void) printf(" %10u upcall%s - upcalls made to mrouted\n",
2495 	    mrts->mrts_upcalls, PLURAL(mrts->mrts_upcalls));
2496 	(void) printf(" %10u packet%s not sent out due to lack of resources\n",
2497 	    mrts->mrts_fwd_drop, PLURAL(mrts->mrts_fwd_drop));
2498 	(void) printf(" %10u datagram%s with malformed tunnel options\n",
2499 	    mrts->mrts_bad_tunnel, PLURAL(mrts->mrts_bad_tunnel));
2500 	(void) printf(" %10u datagram%s with no room for tunnel options\n",
2501 	    mrts->mrts_cant_tunnel, PLURAL(mrts->mrts_cant_tunnel));
2502 	(void) printf(" %10u datagram%s arrived on wrong interface\n",
2503 	    mrts->mrts_wrong_if, PLURAL(mrts->mrts_wrong_if));
2504 	(void) printf(" %10u datagram%s dropped due to upcall Q overflow\n",
2505 	    mrts->mrts_upq_ovflw, PLURAL(mrts->mrts_upq_ovflw));
2506 	(void) printf(" %10u datagram%s cleaned up by the cache\n",
2507 	    mrts->mrts_cache_cleanups, PLURAL(mrts->mrts_cache_cleanups));
2508 	(void) printf(" %10u datagram%s dropped selectively by ratelimiter\n",
2509 	    mrts->mrts_drop_sel, PLURAL(mrts->mrts_drop_sel));
2510 	(void) printf(" %10u datagram%s dropped - bucket Q overflow\n",
2511 	    mrts->mrts_q_overflow, PLURAL(mrts->mrts_q_overflow));
2512 	(void) printf(" %10u datagram%s dropped - larger than bkt size\n",
2513 	    mrts->mrts_pkt2large, PLURAL(mrts->mrts_pkt2large));
2514 	(void) printf("\nPIM multicast routing:\n");
2515 	(void) printf(" %10u datagram%s dropped - bad version number\n",
2516 	    mrts->mrts_pim_badversion, PLURAL(mrts->mrts_pim_badversion));
2517 	(void) printf(" %10u datagram%s dropped - bad checksum\n",
2518 	    mrts->mrts_pim_rcv_badcsum, PLURAL(mrts->mrts_pim_rcv_badcsum));
2519 	(void) printf(" %10u datagram%s dropped - bad register packets\n",
2520 	    mrts->mrts_pim_badregisters, PLURAL(mrts->mrts_pim_badregisters));
2521 	(void) printf(
2522 	    " %10u datagram%s potentially forwarded - register packets\n",
2523 	    mrts->mrts_pim_regforwards, PLURAL(mrts->mrts_pim_regforwards));
2524 	(void) printf(" %10u datagram%s dropped - register send drops\n",
2525 	    mrts->mrts_pim_regsend_drops, PLURAL(mrts->mrts_pim_regsend_drops));
2526 	(void) printf(" %10u datagram%s dropped - packet malformed\n",
2527 	    mrts->mrts_pim_malformed, PLURAL(mrts->mrts_pim_malformed));
2528 	(void) printf(" %10u datagram%s dropped - no memory to forward\n",
2529 	    mrts->mrts_pim_nomemory, PLURAL(mrts->mrts_pim_nomemory));
2530 }
2531 
2532 static void
2533 sum_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6, mib2_ipv6IfStatsEntry_t *sum6)
2534 {
2535 	/* First few are not additive */
2536 	sum6->ipv6Forwarding = ip6->ipv6Forwarding;
2537 	sum6->ipv6DefaultHopLimit = ip6->ipv6DefaultHopLimit;
2538 
2539 	sum6->ipv6InReceives += ip6->ipv6InReceives;
2540 	sum6->ipv6InHdrErrors += ip6->ipv6InHdrErrors;
2541 	sum6->ipv6InTooBigErrors += ip6->ipv6InTooBigErrors;
2542 	sum6->ipv6InNoRoutes += ip6->ipv6InNoRoutes;
2543 	sum6->ipv6InAddrErrors += ip6->ipv6InAddrErrors;
2544 	sum6->ipv6InUnknownProtos += ip6->ipv6InUnknownProtos;
2545 	sum6->ipv6InTruncatedPkts += ip6->ipv6InTruncatedPkts;
2546 	sum6->ipv6InDiscards += ip6->ipv6InDiscards;
2547 	sum6->ipv6InDelivers += ip6->ipv6InDelivers;
2548 	sum6->ipv6OutForwDatagrams += ip6->ipv6OutForwDatagrams;
2549 	sum6->ipv6OutRequests += ip6->ipv6OutRequests;
2550 	sum6->ipv6OutDiscards += ip6->ipv6OutDiscards;
2551 	sum6->ipv6OutFragOKs += ip6->ipv6OutFragOKs;
2552 	sum6->ipv6OutFragFails += ip6->ipv6OutFragFails;
2553 	sum6->ipv6OutFragCreates += ip6->ipv6OutFragCreates;
2554 	sum6->ipv6ReasmReqds += ip6->ipv6ReasmReqds;
2555 	sum6->ipv6ReasmOKs += ip6->ipv6ReasmOKs;
2556 	sum6->ipv6ReasmFails += ip6->ipv6ReasmFails;
2557 	sum6->ipv6InMcastPkts += ip6->ipv6InMcastPkts;
2558 	sum6->ipv6OutMcastPkts += ip6->ipv6OutMcastPkts;
2559 	sum6->ipv6OutNoRoutes += ip6->ipv6OutNoRoutes;
2560 	sum6->ipv6ReasmDuplicates += ip6->ipv6ReasmDuplicates;
2561 	sum6->ipv6ReasmPartDups += ip6->ipv6ReasmPartDups;
2562 	sum6->ipv6ForwProhibits += ip6->ipv6ForwProhibits;
2563 	sum6->udpInCksumErrs += ip6->udpInCksumErrs;
2564 	sum6->udpInOverflows += ip6->udpInOverflows;
2565 	sum6->rawipInOverflows += ip6->rawipInOverflows;
2566 }
2567 
2568 static void
2569 sum_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6, mib2_ipv6IfIcmpEntry_t *sum6)
2570 {
2571 	sum6->ipv6IfIcmpInMsgs += icmp6->ipv6IfIcmpInMsgs;
2572 	sum6->ipv6IfIcmpInErrors += icmp6->ipv6IfIcmpInErrors;
2573 	sum6->ipv6IfIcmpInDestUnreachs += icmp6->ipv6IfIcmpInDestUnreachs;
2574 	sum6->ipv6IfIcmpInAdminProhibs += icmp6->ipv6IfIcmpInAdminProhibs;
2575 	sum6->ipv6IfIcmpInTimeExcds += icmp6->ipv6IfIcmpInTimeExcds;
2576 	sum6->ipv6IfIcmpInParmProblems += icmp6->ipv6IfIcmpInParmProblems;
2577 	sum6->ipv6IfIcmpInPktTooBigs += icmp6->ipv6IfIcmpInPktTooBigs;
2578 	sum6->ipv6IfIcmpInEchos += icmp6->ipv6IfIcmpInEchos;
2579 	sum6->ipv6IfIcmpInEchoReplies += icmp6->ipv6IfIcmpInEchoReplies;
2580 	sum6->ipv6IfIcmpInRouterSolicits += icmp6->ipv6IfIcmpInRouterSolicits;
2581 	sum6->ipv6IfIcmpInRouterAdvertisements +=
2582 	    icmp6->ipv6IfIcmpInRouterAdvertisements;
2583 	sum6->ipv6IfIcmpInNeighborSolicits +=
2584 	    icmp6->ipv6IfIcmpInNeighborSolicits;
2585 	sum6->ipv6IfIcmpInNeighborAdvertisements +=
2586 	    icmp6->ipv6IfIcmpInNeighborAdvertisements;
2587 	sum6->ipv6IfIcmpInRedirects += icmp6->ipv6IfIcmpInRedirects;
2588 	sum6->ipv6IfIcmpInGroupMembQueries +=
2589 	    icmp6->ipv6IfIcmpInGroupMembQueries;
2590 	sum6->ipv6IfIcmpInGroupMembResponses +=
2591 	    icmp6->ipv6IfIcmpInGroupMembResponses;
2592 	sum6->ipv6IfIcmpInGroupMembReductions +=
2593 	    icmp6->ipv6IfIcmpInGroupMembReductions;
2594 	sum6->ipv6IfIcmpOutMsgs += icmp6->ipv6IfIcmpOutMsgs;
2595 	sum6->ipv6IfIcmpOutErrors += icmp6->ipv6IfIcmpOutErrors;
2596 	sum6->ipv6IfIcmpOutDestUnreachs += icmp6->ipv6IfIcmpOutDestUnreachs;
2597 	sum6->ipv6IfIcmpOutAdminProhibs += icmp6->ipv6IfIcmpOutAdminProhibs;
2598 	sum6->ipv6IfIcmpOutTimeExcds += icmp6->ipv6IfIcmpOutTimeExcds;
2599 	sum6->ipv6IfIcmpOutParmProblems += icmp6->ipv6IfIcmpOutParmProblems;
2600 	sum6->ipv6IfIcmpOutPktTooBigs += icmp6->ipv6IfIcmpOutPktTooBigs;
2601 	sum6->ipv6IfIcmpOutEchos += icmp6->ipv6IfIcmpOutEchos;
2602 	sum6->ipv6IfIcmpOutEchoReplies += icmp6->ipv6IfIcmpOutEchoReplies;
2603 	sum6->ipv6IfIcmpOutRouterSolicits +=
2604 	    icmp6->ipv6IfIcmpOutRouterSolicits;
2605 	sum6->ipv6IfIcmpOutRouterAdvertisements +=
2606 	    icmp6->ipv6IfIcmpOutRouterAdvertisements;
2607 	sum6->ipv6IfIcmpOutNeighborSolicits +=
2608 	    icmp6->ipv6IfIcmpOutNeighborSolicits;
2609 	sum6->ipv6IfIcmpOutNeighborAdvertisements +=
2610 	    icmp6->ipv6IfIcmpOutNeighborAdvertisements;
2611 	sum6->ipv6IfIcmpOutRedirects += icmp6->ipv6IfIcmpOutRedirects;
2612 	sum6->ipv6IfIcmpOutGroupMembQueries +=
2613 	    icmp6->ipv6IfIcmpOutGroupMembQueries;
2614 	sum6->ipv6IfIcmpOutGroupMembResponses +=
2615 	    icmp6->ipv6IfIcmpOutGroupMembResponses;
2616 	sum6->ipv6IfIcmpOutGroupMembReductions +=
2617 	    icmp6->ipv6IfIcmpOutGroupMembReductions;
2618 	sum6->ipv6IfIcmpInOverflows += icmp6->ipv6IfIcmpInOverflows;
2619 }
2620 
2621 /* ----------------------------- MRT_STAT_REPORT --------------------------- */
2622 
2623 static void
2624 mrt_stat_report(mib_item_t *curritem)
2625 {
2626 	int	jtemp = 0;
2627 	mib_item_t *tempitem;
2628 
2629 	if (!(family_selected(AF_INET)))
2630 		return;
2631 
2632 	(void) putchar('\n');
2633 	/* 'for' loop 1: */
2634 	for (tempitem = curritem;
2635 	    tempitem;
2636 	    tempitem = tempitem->next_item) {
2637 		if (Xflag) {
2638 			(void) printf("\n--- Entry %d ---\n", ++jtemp);
2639 			(void) printf("Group = %d, mib_id = %d, "
2640 			    "length = %d, valp = 0x%p\n",
2641 			    tempitem->group, tempitem->mib_id,
2642 			    tempitem->length, tempitem->valp);
2643 		}
2644 
2645 		if (tempitem->mib_id == 0) {
2646 			switch (tempitem->group) {
2647 			case EXPER_DVMRP: {
2648 				struct mrtstat	*mrts;
2649 				mrts = (struct mrtstat *)tempitem->valp;
2650 
2651 				if (!(family_selected(AF_INET)))
2652 					continue; /* 'for' loop 1 */
2653 
2654 				print_mrt_stats(mrts);
2655 				break;
2656 			}
2657 			}
2658 		}
2659 	} /* 'for' loop 1 ends */
2660 	(void) putchar('\n');
2661 	(void) fflush(stdout);
2662 }
2663 
2664 /*
2665  * if_stat_total() - Computes totals for interface statistics
2666  *                   and returns result by updating sumstats.
2667  */
2668 static void
2669 if_stat_total(struct ifstat *oldstats, struct ifstat *newstats,
2670     struct ifstat *sumstats)
2671 {
2672 	sumstats->ipackets += newstats->ipackets - oldstats->ipackets;
2673 	sumstats->opackets += newstats->opackets - oldstats->opackets;
2674 	sumstats->ierrors += newstats->ierrors - oldstats->ierrors;
2675 	sumstats->oerrors += newstats->oerrors - oldstats->oerrors;
2676 	sumstats->collisions += newstats->collisions - oldstats->collisions;
2677 }
2678 
2679 /* --------------------- IF_REPORT (netstat -i)  -------------------------- */
2680 
2681 static struct	ifstat	zerostat = {
2682 	0LL, 0LL, 0LL, 0LL, 0LL
2683 };
2684 
2685 static void
2686 if_report(mib_item_t *item, char *matchname,
2687     int Iflag_only, boolean_t once_only)
2688 {
2689 	static boolean_t	reentry = B_FALSE;
2690 	boolean_t		alreadydone = B_FALSE;
2691 	int			jtemp = 0;
2692 	uint32_t		ifindex_v4 = 0;
2693 	uint32_t		ifindex_v6 = 0;
2694 	boolean_t		first_header = B_TRUE;
2695 
2696 	/* 'for' loop 1: */
2697 	for (; item; item = item->next_item) {
2698 		if (Xflag) {
2699 			(void) printf("\n--- Entry %d ---\n", ++jtemp);
2700 			(void) printf("Group = %d, mib_id = %d, "
2701 			    "length = %d, valp = 0x%p\n",
2702 			    item->group, item->mib_id, item->length,
2703 			    item->valp);
2704 		}
2705 
2706 		switch (item->group) {
2707 		case MIB2_IP:
2708 		if (item->mib_id != MIB2_IP_ADDR ||
2709 		    !family_selected(AF_INET))
2710 			continue; /* 'for' loop 1 */
2711 		{
2712 			static struct ifstat	old = {0L, 0L, 0L, 0L, 0L};
2713 			static struct ifstat	new = {0L, 0L, 0L, 0L, 0L};
2714 			struct ifstat		sum;
2715 			struct iflist		*newlist = NULL;
2716 			static struct iflist	*oldlist = NULL;
2717 			kstat_t	 *ksp;
2718 
2719 			if (once_only) {
2720 				char    ifname[LIFNAMSIZ + 1];
2721 				char    logintname[LIFNAMSIZ + 1];
2722 				mib2_ipAddrEntry_t *ap;
2723 				struct ifstat	stat = {0L, 0L, 0L, 0L, 0L};
2724 				boolean_t	first = B_TRUE;
2725 				uint32_t	new_ifindex;
2726 
2727 				if (Xflag)
2728 					(void) printf("if_report: %d items\n",
2729 					    (item->length)
2730 					    / sizeof (mib2_ipAddrEntry_t));
2731 
2732 				/* 'for' loop 2a: */
2733 				for (ap = (mib2_ipAddrEntry_t *)item->valp;
2734 				    (char *)ap < (char *)item->valp
2735 				    + item->length;
2736 				    ap++) {
2737 					(void) octetstr(&ap->ipAdEntIfIndex,
2738 					    'a', logintname,
2739 					    sizeof (logintname));
2740 					(void) strcpy(ifname, logintname);
2741 					(void) strtok(ifname, ":");
2742 					if (matchname != NULL &&
2743 					    strcmp(matchname, ifname) != 0 &&
2744 					    strcmp(matchname, logintname) != 0)
2745 						continue; /* 'for' loop 2a */
2746 					new_ifindex =
2747 					    if_nametoindex(logintname);
2748 					/*
2749 					 * First lookup the "link" kstats in
2750 					 * case the link is renamed. Then
2751 					 * fallback to the legacy kstats for
2752 					 * those non-GLDv3 links.
2753 					 */
2754 					if (new_ifindex != ifindex_v4 &&
2755 					    (((ksp = kstat_lookup(kc, "link", 0,
2756 					    ifname)) != NULL) ||
2757 					    ((ksp = kstat_lookup(kc, NULL, -1,
2758 					    ifname)) != NULL))) {
2759 						(void) safe_kstat_read(kc, ksp,
2760 						    NULL);
2761 						stat.ipackets =
2762 						    kstat_named_value(ksp,
2763 						    "ipackets");
2764 						stat.ierrors =
2765 						    kstat_named_value(ksp,
2766 						    "ierrors");
2767 						stat.opackets =
2768 						    kstat_named_value(ksp,
2769 						    "opackets");
2770 						stat.oerrors =
2771 						    kstat_named_value(ksp,
2772 						    "oerrors");
2773 						stat.collisions =
2774 						    kstat_named_value(ksp,
2775 						    "collisions");
2776 						if (first) {
2777 							if (!first_header)
2778 							(void) putchar('\n');
2779 							first_header = B_FALSE;
2780 						(void) printf(
2781 						    "%-5.5s %-5.5s%-13.13s "
2782 						    "%-14.14s %-6.6s %-5.5s "
2783 						    "%-6.6s %-5.5s %-6.6s "
2784 						    "%-6.6s\n",
2785 						    "Name", "Mtu", "Net/Dest",
2786 						    "Address", "Ipkts",
2787 						    "Ierrs", "Opkts", "Oerrs",
2788 						    "Collis", "Queue");
2789 
2790 						first = B_FALSE;
2791 						}
2792 						if_report_ip4(ap, ifname,
2793 						    logintname, &stat, B_TRUE);
2794 						ifindex_v4 = new_ifindex;
2795 					} else {
2796 						if_report_ip4(ap, ifname,
2797 						    logintname, &stat, B_FALSE);
2798 					}
2799 				} /* 'for' loop 2a ends */
2800 			} else if (!alreadydone) {
2801 				char    ifname[LIFNAMSIZ + 1];
2802 				char    buf[LIFNAMSIZ + 1];
2803 				mib2_ipAddrEntry_t *ap;
2804 				struct ifstat   t;
2805 				struct iflist	*tlp = NULL;
2806 				struct iflist	**nextnew = &newlist;
2807 				struct iflist	*walkold;
2808 				struct iflist	*cleanlist;
2809 				boolean_t	found_if = B_FALSE;
2810 
2811 				alreadydone = B_TRUE; /* ignore other case */
2812 
2813 				/*
2814 				 * Check if there is anything to do.
2815 				 */
2816 				if (item->length <
2817 				    sizeof (mib2_ipAddrEntry_t)) {
2818 					fail(0, "No compatible interfaces");
2819 				}
2820 
2821 				/*
2822 				 * 'for' loop 2b: find the "right" entry:
2823 				 * If an interface name to match has been
2824 				 * supplied then try and find it, otherwise
2825 				 * match the first non-loopback interface found.
2826 				 * Use lo0 if all else fails.
2827 				 */
2828 				for (ap = (mib2_ipAddrEntry_t *)item->valp;
2829 				    (char *)ap < (char *)item->valp
2830 				    + item->length;
2831 				    ap++) {
2832 					(void) octetstr(&ap->ipAdEntIfIndex,
2833 					    'a', ifname, sizeof (ifname));
2834 					(void) strtok(ifname, ":");
2835 
2836 					if (matchname) {
2837 						if (strcmp(matchname,
2838 						    ifname) == 0) {
2839 							/* 'for' loop 2b */
2840 							found_if = B_TRUE;
2841 							break;
2842 						}
2843 					} else if (strcmp(ifname, "lo0") != 0)
2844 						break; /* 'for' loop 2b */
2845 				} /* 'for' loop 2b ends */
2846 
2847 				if (matchname == NULL) {
2848 					matchname = ifname;
2849 				} else {
2850 					if (!found_if)
2851 						fail(0, "-I: %s no such "
2852 						    "interface.", matchname);
2853 				}
2854 
2855 				if (Iflag_only == 0 || !reentry) {
2856 					(void) printf("    input   %-6.6s    "
2857 					    "output	",
2858 					    matchname);
2859 					(void) printf("   input  (Total)    "
2860 					"output\n");
2861 					(void) printf("%-7.7s %-5.5s %-7.7s "
2862 					    "%-5.5s %-6.6s ",
2863 					    "packets", "errs", "packets",
2864 					    "errs", "colls");
2865 					(void) printf("%-7.7s %-5.5s %-7.7s "
2866 					    "%-5.5s %-6.6s\n",
2867 					    "packets", "errs", "packets",
2868 					    "errs", "colls");
2869 				}
2870 
2871 				sum = zerostat;
2872 
2873 				/* 'for' loop 2c: */
2874 				for (ap = (mib2_ipAddrEntry_t *)item->valp;
2875 				    (char *)ap < (char *)item->valp
2876 				    + item->length;
2877 				    ap++) {
2878 					(void) octetstr(&ap->ipAdEntIfIndex,
2879 					    'a', buf, sizeof (buf));
2880 					(void) strtok(buf, ":");
2881 
2882 					/*
2883 					 * We have reduced the IP interface
2884 					 * name, which could have been a
2885 					 * logical, down to a name suitable
2886 					 * for use with kstats.
2887 					 * We treat this name as unique and
2888 					 * only collate statistics for it once
2889 					 * per pass. This is to avoid falsely
2890 					 * amplifying these statistics by the
2891 					 * the number of logical instances.
2892 					 */
2893 					if ((tlp != NULL) &&
2894 					    ((strcmp(buf, tlp->ifname) == 0))) {
2895 						continue;
2896 					}
2897 
2898 					/*
2899 					 * First lookup the "link" kstats in
2900 					 * case the link is renamed. Then
2901 					 * fallback to the legacy kstats for
2902 					 * those non-GLDv3 links.
2903 					 */
2904 					if (((ksp = kstat_lookup(kc, "link",
2905 					    0, buf)) != NULL ||
2906 					    (ksp = kstat_lookup(kc, NULL, -1,
2907 					    buf)) != NULL) && (ksp->ks_type ==
2908 					    KSTAT_TYPE_NAMED)) {
2909 						(void) safe_kstat_read(kc, ksp,
2910 						    NULL);
2911 					}
2912 
2913 					t.ipackets = kstat_named_value(ksp,
2914 					    "ipackets");
2915 					t.ierrors = kstat_named_value(ksp,
2916 					    "ierrors");
2917 					t.opackets = kstat_named_value(ksp,
2918 					    "opackets");
2919 					t.oerrors = kstat_named_value(ksp,
2920 					    "oerrors");
2921 					t.collisions = kstat_named_value(ksp,
2922 					    "collisions");
2923 
2924 					if (strcmp(buf, matchname) == 0)
2925 						new = t;
2926 
2927 					/* Build the interface list */
2928 
2929 					tlp = malloc(sizeof (struct iflist));
2930 					(void) strlcpy(tlp->ifname, buf,
2931 					    sizeof (tlp->ifname));
2932 					tlp->tot = t;
2933 					*nextnew = tlp;
2934 					nextnew = &tlp->next_if;
2935 
2936 					/*
2937 					 * First time through.
2938 					 * Just add up the interface stats.
2939 					 */
2940 
2941 					if (oldlist == NULL) {
2942 						if_stat_total(&zerostat,
2943 						    &t, &sum);
2944 						continue;
2945 					}
2946 
2947 					/*
2948 					 * Walk old list for the interface.
2949 					 *
2950 					 * If found, add difference to total.
2951 					 *
2952 					 * If not, an interface has been plumbed
2953 					 * up.  In this case, we will simply
2954 					 * ignore the new interface until the
2955 					 * next interval; as there's no easy way
2956 					 * to acquire statistics between time
2957 					 * of the plumb and the next interval
2958 					 * boundary.  This results in inaccurate
2959 					 * total values for current interval.
2960 					 *
2961 					 * Note the case when an interface is
2962 					 * unplumbed; as similar problems exist.
2963 					 * The unplumbed interface is not in the
2964 					 * current list, and there's no easy way
2965 					 * to account for the statistics between
2966 					 * the previous interval and time of the
2967 					 * unplumb.  Therefore, we (in a sense)
2968 					 * ignore the removed interface by only
2969 					 * involving "current" interfaces when
2970 					 * computing the total statistics.
2971 					 * Unfortunately, this also results in
2972 					 * inaccurate values for interval total.
2973 					 */
2974 
2975 					for (walkold = oldlist;
2976 					    walkold != NULL;
2977 					    walkold = walkold->next_if) {
2978 						if (strcmp(walkold->ifname,
2979 						    buf) == 0) {
2980 							if_stat_total(
2981 							    &walkold->tot,
2982 							    &t, &sum);
2983 							break;
2984 						}
2985 					}
2986 
2987 				} /* 'for' loop 2c ends */
2988 
2989 				*nextnew = NULL;
2990 
2991 				(void) printf("%-7llu %-5llu %-7llu "
2992 				    "%-5llu %-6llu ",
2993 				    new.ipackets - old.ipackets,
2994 				    new.ierrors - old.ierrors,
2995 				    new.opackets - old.opackets,
2996 				    new.oerrors - old.oerrors,
2997 				    new.collisions - old.collisions);
2998 
2999 				(void) printf("%-7llu %-5llu %-7llu "
3000 				    "%-5llu %-6llu\n", sum.ipackets,
3001 				    sum.ierrors, sum.opackets,
3002 				    sum.oerrors, sum.collisions);
3003 
3004 				/*
3005 				 * Tidy things up once finished.
3006 				 */
3007 
3008 				old = new;
3009 				cleanlist = oldlist;
3010 				oldlist = newlist;
3011 				while (cleanlist != NULL) {
3012 					tlp = cleanlist->next_if;
3013 					free(cleanlist);
3014 					cleanlist = tlp;
3015 				}
3016 			}
3017 			break;
3018 		}
3019 		case MIB2_IP6:
3020 		if (item->mib_id != MIB2_IP6_ADDR ||
3021 		    !family_selected(AF_INET6))
3022 			continue; /* 'for' loop 1 */
3023 		{
3024 			static struct ifstat	old6 = {0L, 0L, 0L, 0L, 0L};
3025 			static struct ifstat	new6 = {0L, 0L, 0L, 0L, 0L};
3026 			struct ifstat		sum6;
3027 			struct iflist		*newlist6 = NULL;
3028 			static struct iflist	*oldlist6 = NULL;
3029 			kstat_t	 *ksp;
3030 
3031 			if (once_only) {
3032 				char    ifname[LIFNAMSIZ + 1];
3033 				char    logintname[LIFNAMSIZ + 1];
3034 				mib2_ipv6AddrEntry_t *ap6;
3035 				struct ifstat	stat = {0L, 0L, 0L, 0L, 0L};
3036 				boolean_t	first = B_TRUE;
3037 				uint32_t	new_ifindex;
3038 
3039 				if (Xflag)
3040 					(void) printf("if_report: %d items\n",
3041 					    (item->length)
3042 					    / sizeof (mib2_ipv6AddrEntry_t));
3043 				/* 'for' loop 2d: */
3044 				for (ap6 = (mib2_ipv6AddrEntry_t *)item->valp;
3045 				    (char *)ap6 < (char *)item->valp
3046 				    + item->length;
3047 				    ap6++) {
3048 					(void) octetstr(&ap6->ipv6AddrIfIndex,
3049 					    'a', logintname,
3050 					    sizeof (logintname));
3051 					(void) strcpy(ifname, logintname);
3052 					(void) strtok(ifname, ":");
3053 					if (matchname != NULL &&
3054 					    strcmp(matchname, ifname) != 0 &&
3055 					    strcmp(matchname, logintname) != 0)
3056 						continue; /* 'for' loop 2d */
3057 					new_ifindex =
3058 					    if_nametoindex(logintname);
3059 
3060 					/*
3061 					 * First lookup the "link" kstats in
3062 					 * case the link is renamed. Then
3063 					 * fallback to the legacy kstats for
3064 					 * those non-GLDv3 links.
3065 					 */
3066 					if (new_ifindex != ifindex_v6 &&
3067 					    ((ksp = kstat_lookup(kc, "link", 0,
3068 					    ifname)) != NULL ||
3069 					    (ksp = kstat_lookup(kc, NULL, -1,
3070 					    ifname)) != NULL)) {
3071 						(void) safe_kstat_read(kc, ksp,
3072 						    NULL);
3073 						stat.ipackets =
3074 						    kstat_named_value(ksp,
3075 						    "ipackets");
3076 						stat.ierrors =
3077 						    kstat_named_value(ksp,
3078 						    "ierrors");
3079 						stat.opackets =
3080 						    kstat_named_value(ksp,
3081 						    "opackets");
3082 						stat.oerrors =
3083 						    kstat_named_value(ksp,
3084 						    "oerrors");
3085 						stat.collisions =
3086 						    kstat_named_value(ksp,
3087 						    "collisions");
3088 						if (first) {
3089 							if (!first_header)
3090 							(void) putchar('\n');
3091 							first_header = B_FALSE;
3092 							(void) printf(
3093 							    "%-5.5s %-5.5s%"
3094 							    "-27.27s %-27.27s "
3095 							    "%-6.6s %-5.5s "
3096 							    "%-6.6s %-5.5s "
3097 							    "%-6.6s\n",
3098 							    "Name", "Mtu",
3099 							    "Net/Dest",
3100 							    "Address", "Ipkts",
3101 							    "Ierrs", "Opkts",
3102 							    "Oerrs", "Collis");
3103 							first = B_FALSE;
3104 						}
3105 						if_report_ip6(ap6, ifname,
3106 						    logintname, &stat, B_TRUE);
3107 						ifindex_v6 = new_ifindex;
3108 					} else {
3109 						if_report_ip6(ap6, ifname,
3110 						    logintname, &stat, B_FALSE);
3111 					}
3112 				} /* 'for' loop 2d ends */
3113 			} else if (!alreadydone) {
3114 				char    ifname[LIFNAMSIZ + 1];
3115 				char    buf[IFNAMSIZ + 1];
3116 				mib2_ipv6AddrEntry_t *ap6;
3117 				struct ifstat   t;
3118 				struct iflist	*tlp = NULL;
3119 				struct iflist	**nextnew = &newlist6;
3120 				struct iflist	*walkold;
3121 				struct iflist	*cleanlist;
3122 				boolean_t	found_if = B_FALSE;
3123 
3124 				alreadydone = B_TRUE; /* ignore other case */
3125 
3126 				/*
3127 				 * Check if there is anything to do.
3128 				 */
3129 				if (item->length <
3130 				    sizeof (mib2_ipv6AddrEntry_t)) {
3131 					fail(0, "No compatible interfaces");
3132 				}
3133 
3134 				/*
3135 				 * 'for' loop 2e: find the "right" entry:
3136 				 * If an interface name to match has been
3137 				 * supplied then try and find it, otherwise
3138 				 * match the first non-loopback interface found.
3139 				 * Use lo0 if all else fails.
3140 				 */
3141 				for (ap6 = (mib2_ipv6AddrEntry_t *)item->valp;
3142 				    (char *)ap6 < (char *)item->valp
3143 				    + item->length;
3144 				    ap6++) {
3145 					(void) octetstr(&ap6->ipv6AddrIfIndex,
3146 					    'a', ifname, sizeof (ifname));
3147 					(void) strtok(ifname, ":");
3148 
3149 					if (matchname) {
3150 						if (strcmp(matchname,
3151 						    ifname) == 0) {
3152 							/* 'for' loop 2e */
3153 							found_if = B_TRUE;
3154 							break;
3155 						}
3156 					} else if (strcmp(ifname, "lo0") != 0)
3157 						break; /* 'for' loop 2e */
3158 				} /* 'for' loop 2e ends */
3159 
3160 				if (matchname == NULL) {
3161 					matchname = ifname;
3162 				} else {
3163 					if (!found_if)
3164 						fail(0, "-I: %s no such "
3165 						    "interface.", matchname);
3166 				}
3167 
3168 				if (Iflag_only == 0 || !reentry) {
3169 					(void) printf(
3170 					    "    input   %-6.6s"
3171 					    "    output	",
3172 					    matchname);
3173 					(void) printf("   input  (Total)"
3174 					    "    output\n");
3175 					(void) printf("%-7.7s %-5.5s %-7.7s "
3176 					    "%-5.5s %-6.6s ",
3177 					    "packets", "errs", "packets",
3178 					    "errs", "colls");
3179 					(void) printf("%-7.7s %-5.5s %-7.7s "
3180 					    "%-5.5s %-6.6s\n",
3181 					    "packets", "errs", "packets",
3182 					    "errs", "colls");
3183 				}
3184 
3185 				sum6 = zerostat;
3186 
3187 				/* 'for' loop 2f: */
3188 				for (ap6 = (mib2_ipv6AddrEntry_t *)item->valp;
3189 				    (char *)ap6 < (char *)item->valp
3190 				    + item->length;
3191 				    ap6++) {
3192 					(void) octetstr(&ap6->ipv6AddrIfIndex,
3193 					    'a', buf, sizeof (buf));
3194 					(void) strtok(buf, ":");
3195 
3196 					/*
3197 					 * We have reduced the IP interface
3198 					 * name, which could have been a
3199 					 * logical, down to a name suitable
3200 					 * for use with kstats.
3201 					 * We treat this name as unique and
3202 					 * only collate statistics for it once
3203 					 * per pass. This is to avoid falsely
3204 					 * amplifying these statistics by the
3205 					 * the number of logical instances.
3206 					 */
3207 
3208 					if ((tlp != NULL) &&
3209 					    ((strcmp(buf, tlp->ifname) == 0))) {
3210 						continue;
3211 					}
3212 
3213 					/*
3214 					 * First lookup the "link" kstats in
3215 					 * case the link is renamed. Then
3216 					 * fallback to the legacy kstats for
3217 					 * those non-GLDv3 links.
3218 					 */
3219 					if (((ksp = kstat_lookup(kc, "link",
3220 					    0, buf)) != NULL ||
3221 					    (ksp = kstat_lookup(kc, NULL, -1,
3222 					    buf)) != NULL) && (ksp->ks_type ==
3223 					    KSTAT_TYPE_NAMED)) {
3224 						(void) safe_kstat_read(kc,
3225 						    ksp, NULL);
3226 					}
3227 
3228 					t.ipackets = kstat_named_value(ksp,
3229 					    "ipackets");
3230 					t.ierrors = kstat_named_value(ksp,
3231 					    "ierrors");
3232 					t.opackets = kstat_named_value(ksp,
3233 					    "opackets");
3234 					t.oerrors = kstat_named_value(ksp,
3235 					    "oerrors");
3236 					t.collisions = kstat_named_value(ksp,
3237 					    "collisions");
3238 
3239 					if (strcmp(buf, matchname) == 0)
3240 						new6 = t;
3241 
3242 					/* Build the interface list */
3243 
3244 					tlp = malloc(sizeof (struct iflist));
3245 					(void) strlcpy(tlp->ifname, buf,
3246 					    sizeof (tlp->ifname));
3247 					tlp->tot = t;
3248 					*nextnew = tlp;
3249 					nextnew = &tlp->next_if;
3250 
3251 					/*
3252 					 * First time through.
3253 					 * Just add up the interface stats.
3254 					 */
3255 
3256 					if (oldlist6 == NULL) {
3257 						if_stat_total(&zerostat,
3258 						    &t, &sum6);
3259 						continue;
3260 					}
3261 
3262 					/*
3263 					 * Walk old list for the interface.
3264 					 *
3265 					 * If found, add difference to total.
3266 					 *
3267 					 * If not, an interface has been plumbed
3268 					 * up.  In this case, we will simply
3269 					 * ignore the new interface until the
3270 					 * next interval; as there's no easy way
3271 					 * to acquire statistics between time
3272 					 * of the plumb and the next interval
3273 					 * boundary.  This results in inaccurate
3274 					 * total values for current interval.
3275 					 *
3276 					 * Note the case when an interface is
3277 					 * unplumbed; as similar problems exist.
3278 					 * The unplumbed interface is not in the
3279 					 * current list, and there's no easy way
3280 					 * to account for the statistics between
3281 					 * the previous interval and time of the
3282 					 * unplumb.  Therefore, we (in a sense)
3283 					 * ignore the removed interface by only
3284 					 * involving "current" interfaces when
3285 					 * computing the total statistics.
3286 					 * Unfortunately, this also results in
3287 					 * inaccurate values for interval total.
3288 					 */
3289 
3290 					for (walkold = oldlist6;
3291 					    walkold != NULL;
3292 					    walkold = walkold->next_if) {
3293 						if (strcmp(walkold->ifname,
3294 						    buf) == 0) {
3295 							if_stat_total(
3296 							    &walkold->tot,
3297 							    &t, &sum6);
3298 							break;
3299 						}
3300 					}
3301 
3302 				} /* 'for' loop 2f ends */
3303 
3304 				*nextnew = NULL;
3305 
3306 				(void) printf("%-7llu %-5llu %-7llu "
3307 				    "%-5llu %-6llu ",
3308 				    new6.ipackets - old6.ipackets,
3309 				    new6.ierrors - old6.ierrors,
3310 				    new6.opackets - old6.opackets,
3311 				    new6.oerrors - old6.oerrors,
3312 				    new6.collisions - old6.collisions);
3313 
3314 				(void) printf("%-7llu %-5llu %-7llu "
3315 				    "%-5llu %-6llu\n", sum6.ipackets,
3316 				    sum6.ierrors, sum6.opackets,
3317 				    sum6.oerrors, sum6.collisions);
3318 
3319 				/*
3320 				 * Tidy things up once finished.
3321 				 */
3322 
3323 				old6 = new6;
3324 				cleanlist = oldlist6;
3325 				oldlist6 = newlist6;
3326 				while (cleanlist != NULL) {
3327 					tlp = cleanlist->next_if;
3328 					free(cleanlist);
3329 					cleanlist = tlp;
3330 				}
3331 			}
3332 			break;
3333 		}
3334 		}
3335 		(void) fflush(stdout);
3336 	} /* 'for' loop 1 ends */
3337 	if ((Iflag_only == 0) && (!once_only))
3338 		(void) putchar('\n');
3339 	reentry = B_TRUE;
3340 }
3341 
3342 static void
3343 if_report_ip4(mib2_ipAddrEntry_t *ap,
3344     char ifname[], char logintname[], struct ifstat *statptr,
3345     boolean_t ksp_not_null)
3346 {
3347 
3348 	char abuf[MAXHOSTNAMELEN + 4];	/* Include /<num> for CIDR-printing. */
3349 	char dstbuf[MAXHOSTNAMELEN + 1];
3350 
3351 	if (ksp_not_null) {
3352 		(void) printf("%-5s %-4u ",
3353 		    ifname, ap->ipAdEntInfo.ae_mtu);
3354 		if (ap->ipAdEntInfo.ae_flags & IFF_POINTOPOINT)
3355 			(void) pr_addr(ap->ipAdEntInfo.ae_pp_dst_addr,
3356 			    abuf, sizeof (abuf));
3357 		else
3358 			(void) pr_netaddr(ap->ipAdEntAddr,
3359 			    ap->ipAdEntNetMask, abuf, sizeof (abuf));
3360 		(void) printf("%-13s %-14s %-6llu %-5llu %-6llu %-5llu "
3361 		    "%-6llu %-6llu\n",
3362 		    abuf, pr_addr(ap->ipAdEntAddr, dstbuf, sizeof (dstbuf)),
3363 		    statptr->ipackets, statptr->ierrors,
3364 		    statptr->opackets, statptr->oerrors,
3365 		    statptr->collisions, 0LL);
3366 	}
3367 	/*
3368 	 * Print logical interface info if Aflag set (including logical unit 0)
3369 	 */
3370 	if (Aflag) {
3371 		*statptr = zerostat;
3372 		statptr->ipackets = ap->ipAdEntInfo.ae_ibcnt;
3373 		statptr->opackets = ap->ipAdEntInfo.ae_obcnt;
3374 
3375 		(void) printf("%-5s %-4u ", logintname, ap->ipAdEntInfo.ae_mtu);
3376 		if (ap->ipAdEntInfo.ae_flags & IFF_POINTOPOINT)
3377 			(void) pr_addr(ap->ipAdEntInfo.ae_pp_dst_addr, abuf,
3378 			    sizeof (abuf));
3379 		else
3380 			(void) pr_netaddr(ap->ipAdEntAddr, ap->ipAdEntNetMask,
3381 			    abuf, sizeof (abuf));
3382 
3383 		(void) printf("%-13s %-14s %-6llu %-5s %-6s "
3384 		    "%-5s %-6s %-6llu\n", abuf,
3385 		    pr_addr(ap->ipAdEntAddr, dstbuf, sizeof (dstbuf)),
3386 		    statptr->ipackets, "N/A", "N/A", "N/A", "N/A",
3387 		    0LL);
3388 	}
3389 }
3390 
3391 static void
3392 if_report_ip6(mib2_ipv6AddrEntry_t *ap6,
3393     char ifname[], char logintname[], struct ifstat *statptr,
3394     boolean_t ksp_not_null)
3395 {
3396 
3397 	char abuf[MAXHOSTNAMELEN + 1];
3398 	char dstbuf[MAXHOSTNAMELEN + 1];
3399 
3400 	if (ksp_not_null) {
3401 		(void) printf("%-5s %-4u ", ifname, ap6->ipv6AddrInfo.ae_mtu);
3402 		if (ap6->ipv6AddrInfo.ae_flags &
3403 		    IFF_POINTOPOINT) {
3404 			(void) pr_addr6(&ap6->ipv6AddrInfo.ae_pp_dst_addr,
3405 			    abuf, sizeof (abuf));
3406 		} else {
3407 			(void) pr_prefix6(&ap6->ipv6AddrAddress,
3408 			    ap6->ipv6AddrPfxLength, abuf,
3409 			    sizeof (abuf));
3410 		}
3411 		(void) printf("%-27s %-27s %-6llu %-5llu "
3412 		    "%-6llu %-5llu %-6llu\n",
3413 		    abuf, pr_addr6(&ap6->ipv6AddrAddress, dstbuf,
3414 		    sizeof (dstbuf)),
3415 		    statptr->ipackets, statptr->ierrors, statptr->opackets,
3416 		    statptr->oerrors, statptr->collisions);
3417 	}
3418 	/*
3419 	 * Print logical interface info if Aflag set (including logical unit 0)
3420 	 */
3421 	if (Aflag) {
3422 		*statptr = zerostat;
3423 		statptr->ipackets = ap6->ipv6AddrInfo.ae_ibcnt;
3424 		statptr->opackets = ap6->ipv6AddrInfo.ae_obcnt;
3425 
3426 		(void) printf("%-5s %-4u ", logintname,
3427 		    ap6->ipv6AddrInfo.ae_mtu);
3428 		if (ap6->ipv6AddrInfo.ae_flags & IFF_POINTOPOINT)
3429 			(void) pr_addr6(&ap6->ipv6AddrInfo.ae_pp_dst_addr,
3430 			    abuf, sizeof (abuf));
3431 		else
3432 			(void) pr_prefix6(&ap6->ipv6AddrAddress,
3433 			    ap6->ipv6AddrPfxLength, abuf, sizeof (abuf));
3434 		(void) printf("%-27s %-27s %-6llu %-5s %-6s %-5s %-6s\n",
3435 		    abuf, pr_addr6(&ap6->ipv6AddrAddress, dstbuf,
3436 		    sizeof (dstbuf)),
3437 		    statptr->ipackets, "N/A", "N/A", "N/A", "N/A");
3438 	}
3439 }
3440 
3441 /* --------------------- DHCP_REPORT  (netstat -D) ------------------------- */
3442 
3443 static boolean_t
3444 dhcp_do_ipc(dhcp_ipc_type_t type, const char *ifname, boolean_t printed_one)
3445 {
3446 	dhcp_ipc_request_t	*request;
3447 	dhcp_ipc_reply_t	*reply;
3448 	int			error;
3449 
3450 	request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE);
3451 	if (request == NULL)
3452 		fail(0, "dhcp_do_ipc: out of memory");
3453 
3454 	error = dhcp_ipc_make_request(request, &reply, DHCP_IPC_WAIT_DEFAULT);
3455 	if (error != 0) {
3456 		free(request);
3457 		fail(0, "dhcp_do_ipc: %s", dhcp_ipc_strerror(error));
3458 	}
3459 
3460 	free(request);
3461 	error = reply->return_code;
3462 	if (error == DHCP_IPC_E_UNKIF) {
3463 		free(reply);
3464 		return (printed_one);
3465 	}
3466 	if (error != 0) {
3467 		free(reply);
3468 		fail(0, "dhcp_do_ipc: %s", dhcp_ipc_strerror(error));
3469 	}
3470 
3471 	if (timestamp_fmt != NODATE)
3472 		print_timestamp(timestamp_fmt);
3473 
3474 	if (!printed_one)
3475 		(void) printf("%s", dhcp_status_hdr_string());
3476 
3477 	(void) printf("%s", dhcp_status_reply_to_string(reply));
3478 	free(reply);
3479 	return (B_TRUE);
3480 }
3481 
3482 /*
3483  * dhcp_walk_interfaces: walk the list of interfaces for a given address
3484  * family (af).  For each, print out the DHCP status using dhcp_do_ipc.
3485  */
3486 static boolean_t
3487 dhcp_walk_interfaces(int af, boolean_t printed_one)
3488 {
3489 	struct lifnum	lifn;
3490 	struct lifconf	lifc;
3491 	int		n_ifs, i, sock_fd;
3492 
3493 	sock_fd = socket(af, SOCK_DGRAM, 0);
3494 	if (sock_fd == -1)
3495 		return (printed_one);
3496 
3497 	/*
3498 	 * SIOCGLIFNUM is just an estimate.  If the ioctl fails, we don't care;
3499 	 * just drive on and use SIOCGLIFCONF with increasing buffer sizes, as
3500 	 * is traditional.
3501 	 */
3502 	(void) memset(&lifn, 0, sizeof (lifn));
3503 	lifn.lifn_family = af;
3504 	lifn.lifn_flags = LIFC_ALLZONES | LIFC_NOXMIT | LIFC_UNDER_IPMP;
3505 	if (ioctl(sock_fd, SIOCGLIFNUM, &lifn) == -1)
3506 		n_ifs = LIFN_GUARD_VALUE;
3507 	else
3508 		n_ifs = lifn.lifn_count + LIFN_GUARD_VALUE;
3509 
3510 	(void) memset(&lifc, 0, sizeof (lifc));
3511 	lifc.lifc_family = af;
3512 	lifc.lifc_flags = lifn.lifn_flags;
3513 	lifc.lifc_len = n_ifs * sizeof (struct lifreq);
3514 	lifc.lifc_buf = malloc(lifc.lifc_len);
3515 	if (lifc.lifc_buf != NULL) {
3516 
3517 		if (ioctl(sock_fd, SIOCGLIFCONF, &lifc) == -1) {
3518 			(void) close(sock_fd);
3519 			free(lifc.lifc_buf);
3520 			return (NULL);
3521 		}
3522 
3523 		n_ifs = lifc.lifc_len / sizeof (struct lifreq);
3524 
3525 		for (i = 0; i < n_ifs; i++) {
3526 			printed_one = dhcp_do_ipc(DHCP_STATUS |
3527 			    (af == AF_INET6 ? DHCP_V6 : 0),
3528 			    lifc.lifc_req[i].lifr_name, printed_one);
3529 		}
3530 	}
3531 	(void) close(sock_fd);
3532 	free(lifc.lifc_buf);
3533 	return (printed_one);
3534 }
3535 
3536 static void
3537 dhcp_report(char *ifname)
3538 {
3539 	boolean_t printed_one;
3540 
3541 	if (!family_selected(AF_INET) && !family_selected(AF_INET6))
3542 		return;
3543 
3544 	printed_one = B_FALSE;
3545 	if (ifname != NULL) {
3546 		if (family_selected(AF_INET)) {
3547 			printed_one = dhcp_do_ipc(DHCP_STATUS, ifname,
3548 			    printed_one);
3549 		}
3550 		if (family_selected(AF_INET6)) {
3551 			printed_one = dhcp_do_ipc(DHCP_STATUS | DHCP_V6,
3552 			    ifname, printed_one);
3553 		}
3554 		if (!printed_one) {
3555 			fail(0, "%s: %s", ifname,
3556 			    dhcp_ipc_strerror(DHCP_IPC_E_UNKIF));
3557 		}
3558 	} else {
3559 		if (family_selected(AF_INET)) {
3560 			printed_one = dhcp_walk_interfaces(AF_INET,
3561 			    printed_one);
3562 		}
3563 		if (family_selected(AF_INET6))
3564 			(void) dhcp_walk_interfaces(AF_INET6, printed_one);
3565 	}
3566 }
3567 
3568 /* --------------------- GROUP_REPORT (netstat -g) ------------------------- */
3569 
3570 static void
3571 group_report(mib_item_t *item)
3572 {
3573 	mib_item_t	*v4grp = NULL, *v4src = NULL;
3574 	mib_item_t	*v6grp = NULL, *v6src = NULL;
3575 	int		jtemp = 0;
3576 	char		ifname[LIFNAMSIZ + 1];
3577 	char		abuf[MAXHOSTNAMELEN + 1];
3578 	ip_member_t	*ipmp;
3579 	ip_grpsrc_t	*ips;
3580 	ipv6_member_t	*ipmp6;
3581 	ipv6_grpsrc_t	*ips6;
3582 	boolean_t	first, first_src;
3583 
3584 	/* 'for' loop 1: */
3585 	for (; item; item = item->next_item) {
3586 		if (Xflag) {
3587 			(void) printf("\n--- Entry %d ---\n", ++jtemp);
3588 			(void) printf("Group = %d, mib_id = %d, "
3589 			    "length = %d, valp = 0x%p\n",
3590 			    item->group, item->mib_id, item->length,
3591 			    item->valp);
3592 		}
3593 		if (item->group == MIB2_IP && family_selected(AF_INET)) {
3594 			switch (item->mib_id) {
3595 			case EXPER_IP_GROUP_MEMBERSHIP:
3596 				v4grp = item;
3597 				if (Xflag)
3598 					(void) printf("item is v4grp info\n");
3599 				break;
3600 			case EXPER_IP_GROUP_SOURCES:
3601 				v4src = item;
3602 				if (Xflag)
3603 					(void) printf("item is v4src info\n");
3604 				break;
3605 			default:
3606 				continue;
3607 			}
3608 			continue;
3609 		}
3610 		if (item->group == MIB2_IP6 && family_selected(AF_INET6)) {
3611 			switch (item->mib_id) {
3612 			case EXPER_IP6_GROUP_MEMBERSHIP:
3613 				v6grp = item;
3614 				if (Xflag)
3615 					(void) printf("item is v6grp info\n");
3616 				break;
3617 			case EXPER_IP6_GROUP_SOURCES:
3618 				v6src = item;
3619 				if (Xflag)
3620 					(void) printf("item is v6src info\n");
3621 				break;
3622 			default:
3623 				continue;
3624 			}
3625 		}
3626 	}
3627 
3628 	if (family_selected(AF_INET) && v4grp != NULL) {
3629 		if (Xflag)
3630 			(void) printf("%u records for ipGroupMember:\n",
3631 			    v4grp->length / sizeof (ip_member_t));
3632 
3633 		first = B_TRUE;
3634 		for (ipmp = (ip_member_t *)v4grp->valp;
3635 		    (char *)ipmp < (char *)v4grp->valp + v4grp->length;
3636 		    /* LINTED: (note 1) */
3637 		    ipmp = (ip_member_t *)((char *)ipmp + ipMemberEntrySize)) {
3638 			if (first) {
3639 				(void) puts(v4compat ?
3640 				    "Group Memberships" :
3641 				    "Group Memberships: IPv4");
3642 				(void) puts("Interface "
3643 				    "Group                RefCnt");
3644 				(void) puts("--------- "
3645 				    "-------------------- ------");
3646 				first = B_FALSE;
3647 			}
3648 
3649 			(void) printf("%-9s %-20s %6u\n",
3650 			    octetstr(&ipmp->ipGroupMemberIfIndex, 'a',
3651 			    ifname, sizeof (ifname)),
3652 			    pr_addr(ipmp->ipGroupMemberAddress,
3653 			    abuf, sizeof (abuf)),
3654 			    ipmp->ipGroupMemberRefCnt);
3655 
3656 
3657 			if (!Vflag || v4src == NULL)
3658 				continue;
3659 
3660 			if (Xflag)
3661 				(void) printf("scanning %u ipGroupSource "
3662 				    "records...\n",
3663 				    v4src->length/sizeof (ip_grpsrc_t));
3664 
3665 			first_src = B_TRUE;
3666 			for (ips = (ip_grpsrc_t *)v4src->valp;
3667 			    (char *)ips < (char *)v4src->valp + v4src->length;
3668 			    /* LINTED: (note 1) */
3669 			    ips = (ip_grpsrc_t *)((char *)ips +
3670 			    ipGroupSourceEntrySize)) {
3671 				/*
3672 				 * We assume that all source addrs for a given
3673 				 * interface/group pair are contiguous, so on
3674 				 * the first non-match after we've found at
3675 				 * least one, we bail.
3676 				 */
3677 				if ((ipmp->ipGroupMemberAddress !=
3678 				    ips->ipGroupSourceGroup) ||
3679 				    (!octetstrmatch(&ipmp->ipGroupMemberIfIndex,
3680 				    &ips->ipGroupSourceIfIndex))) {
3681 					if (first_src)
3682 						continue;
3683 					else
3684 						break;
3685 				}
3686 				if (first_src) {
3687 					(void) printf("\t%s:    %s\n",
3688 					    fmodestr(
3689 					    ipmp->ipGroupMemberFilterMode),
3690 					    pr_addr(ips->ipGroupSourceAddress,
3691 					    abuf, sizeof (abuf)));
3692 					first_src = B_FALSE;
3693 					continue;
3694 				}
3695 
3696 				(void) printf("\t            %s\n",
3697 				    pr_addr(ips->ipGroupSourceAddress, abuf,
3698 				    sizeof (abuf)));
3699 			}
3700 		}
3701 		(void) putchar('\n');
3702 	}
3703 
3704 	if (family_selected(AF_INET6) && v6grp != NULL) {
3705 		if (Xflag)
3706 			(void) printf("%u records for ipv6GroupMember:\n",
3707 			    v6grp->length / sizeof (ipv6_member_t));
3708 
3709 		first = B_TRUE;
3710 		for (ipmp6 = (ipv6_member_t *)v6grp->valp;
3711 		    (char *)ipmp6 < (char *)v6grp->valp + v6grp->length;
3712 		    /* LINTED: (note 1) */
3713 		    ipmp6 = (ipv6_member_t *)((char *)ipmp6 +
3714 		    ipv6MemberEntrySize)) {
3715 			if (first) {
3716 				(void) puts("Group Memberships: "
3717 				    "IPv6");
3718 				(void) puts(" If       "
3719 				    "Group                   RefCnt");
3720 				(void) puts("----- "
3721 				    "--------------------------- ------");
3722 				first = B_FALSE;
3723 			}
3724 
3725 			(void) printf("%-5s %-27s %5u\n",
3726 			    ifindex2str(ipmp6->ipv6GroupMemberIfIndex, ifname),
3727 			    pr_addr6(&ipmp6->ipv6GroupMemberAddress,
3728 			    abuf, sizeof (abuf)),
3729 			    ipmp6->ipv6GroupMemberRefCnt);
3730 
3731 			if (!Vflag || v6src == NULL)
3732 				continue;
3733 
3734 			if (Xflag)
3735 				(void) printf("scanning %u ipv6GroupSource "
3736 				    "records...\n",
3737 				    v6src->length/sizeof (ipv6_grpsrc_t));
3738 
3739 			first_src = B_TRUE;
3740 			for (ips6 = (ipv6_grpsrc_t *)v6src->valp;
3741 			    (char *)ips6 < (char *)v6src->valp + v6src->length;
3742 			    /* LINTED: (note 1) */
3743 			    ips6 = (ipv6_grpsrc_t *)((char *)ips6 +
3744 			    ipv6GroupSourceEntrySize)) {
3745 				/* same assumption as in the v4 case above */
3746 				if ((ipmp6->ipv6GroupMemberIfIndex !=
3747 				    ips6->ipv6GroupSourceIfIndex) ||
3748 				    (!IN6_ARE_ADDR_EQUAL(
3749 				    &ipmp6->ipv6GroupMemberAddress,
3750 				    &ips6->ipv6GroupSourceGroup))) {
3751 					if (first_src)
3752 						continue;
3753 					else
3754 						break;
3755 				}
3756 				if (first_src) {
3757 					(void) printf("\t%s:    %s\n",
3758 					    fmodestr(
3759 					    ipmp6->ipv6GroupMemberFilterMode),
3760 					    pr_addr6(
3761 					    &ips6->ipv6GroupSourceAddress,
3762 					    abuf, sizeof (abuf)));
3763 					first_src = B_FALSE;
3764 					continue;
3765 				}
3766 
3767 				(void) printf("\t            %s\n",
3768 				    pr_addr6(&ips6->ipv6GroupSourceAddress,
3769 				    abuf, sizeof (abuf)));
3770 			}
3771 		}
3772 		(void) putchar('\n');
3773 	}
3774 
3775 	(void) putchar('\n');
3776 	(void) fflush(stdout);
3777 }
3778 
3779 /* --------------------- DCE_REPORT (netstat -d) ------------------------- */
3780 
3781 #define	FLBUFSIZE	8
3782 
3783 /* Assumes flbuf is at least 5 characters; callers use FLBUFSIZE */
3784 static char *
3785 dceflags2str(uint32_t flags, char *flbuf)
3786 {
3787 	char *str = flbuf;
3788 
3789 	if (flags & DCEF_DEFAULT)
3790 		*str++ = 'D';
3791 	if (flags & DCEF_PMTU)
3792 		*str++ = 'P';
3793 	if (flags & DCEF_UINFO)
3794 		*str++ = 'U';
3795 	if (flags & DCEF_TOO_SMALL_PMTU)
3796 		*str++ = 'S';
3797 	*str++ = '\0';
3798 	return (flbuf);
3799 }
3800 
3801 static void
3802 dce_report(mib_item_t *item)
3803 {
3804 	mib_item_t	*v4dce = NULL;
3805 	mib_item_t	*v6dce = NULL;
3806 	int		jtemp = 0;
3807 	char		ifname[LIFNAMSIZ + 1];
3808 	char		abuf[MAXHOSTNAMELEN + 1];
3809 	char		flbuf[FLBUFSIZE];
3810 	boolean_t	first;
3811 	dest_cache_entry_t *dce;
3812 
3813 	/* 'for' loop 1: */
3814 	for (; item; item = item->next_item) {
3815 		if (Xflag) {
3816 			(void) printf("\n--- Entry %d ---\n", ++jtemp);
3817 			(void) printf("Group = %d, mib_id = %d, "
3818 			    "length = %d, valp = 0x%p\n",
3819 			    item->group, item->mib_id, item->length,
3820 			    item->valp);
3821 		}
3822 		if (item->group == MIB2_IP && family_selected(AF_INET) &&
3823 		    item->mib_id == EXPER_IP_DCE) {
3824 			v4dce = item;
3825 			if (Xflag)
3826 				(void) printf("item is v4dce info\n");
3827 		}
3828 		if (item->group == MIB2_IP6 && family_selected(AF_INET6) &&
3829 		    item->mib_id == EXPER_IP_DCE) {
3830 			v6dce = item;
3831 			if (Xflag)
3832 				(void) printf("item is v6dce info\n");
3833 		}
3834 	}
3835 
3836 	if (family_selected(AF_INET) && v4dce != NULL) {
3837 		if (Xflag)
3838 			(void) printf("%u records for DestCacheEntry:\n",
3839 			    v4dce->length / ipDestEntrySize);
3840 
3841 		first = B_TRUE;
3842 		for (dce = (dest_cache_entry_t *)v4dce->valp;
3843 		    (char *)dce < (char *)v4dce->valp + v4dce->length;
3844 		    /* LINTED: (note 1) */
3845 		    dce = (dest_cache_entry_t *)((char *)dce +
3846 		    ipDestEntrySize)) {
3847 			if (first) {
3848 				(void) putchar('\n');
3849 				(void) puts("Destination Cache Entries: IPv4");
3850 				(void) puts(
3851 				    "Address               PMTU   Age  Flags");
3852 				(void) puts(
3853 				    "-------------------- ------ ----- -----");
3854 				first = B_FALSE;
3855 			}
3856 
3857 			(void) printf("%-20s %6u %5u %-5s\n",
3858 			    pr_addr(dce->DestIpv4Address, abuf, sizeof (abuf)),
3859 			    dce->DestPmtu, dce->DestAge,
3860 			    dceflags2str(dce->DestFlags, flbuf));
3861 		}
3862 	}
3863 
3864 	if (family_selected(AF_INET6) && v6dce != NULL) {
3865 		if (Xflag)
3866 			(void) printf("%u records for DestCacheEntry:\n",
3867 			    v6dce->length / ipDestEntrySize);
3868 
3869 		first = B_TRUE;
3870 		for (dce = (dest_cache_entry_t *)v6dce->valp;
3871 		    (char *)dce < (char *)v6dce->valp + v6dce->length;
3872 		    /* LINTED: (note 1) */
3873 		    dce = (dest_cache_entry_t *)((char *)dce +
3874 		    ipDestEntrySize)) {
3875 			if (first) {
3876 				(void) putchar('\n');
3877 				(void) puts("Destination Cache Entries: IPv6");
3878 				(void) puts(
3879 				    "Address                      PMTU  "
3880 				    " Age Flags If ");
3881 				(void) puts(
3882 				    "--------------------------- ------ "
3883 				    "----- ----- ---");
3884 				first = B_FALSE;
3885 			}
3886 
3887 			(void) printf("%-27s %6u %5u %-5s %s\n",
3888 			    pr_addr6(&dce->DestIpv6Address, abuf,
3889 			    sizeof (abuf)),
3890 			    dce->DestPmtu, dce->DestAge,
3891 			    dceflags2str(dce->DestFlags, flbuf),
3892 			    dce->DestIfindex == 0 ? "" :
3893 			    ifindex2str(dce->DestIfindex, ifname));
3894 		}
3895 	}
3896 	(void) fflush(stdout);
3897 }
3898 
3899 /* --------------------- ARP_REPORT (netstat -p) -------------------------- */
3900 
3901 static void
3902 arp_report(mib_item_t *item)
3903 {
3904 	int		jtemp = 0;
3905 	char		ifname[LIFNAMSIZ + 1];
3906 	char		abuf[MAXHOSTNAMELEN + 1];
3907 	char		maskbuf[STR_EXPAND * OCTET_LENGTH + 1];
3908 	char		flbuf[32];	/* ACE_F_ flags */
3909 	char		xbuf[STR_EXPAND * OCTET_LENGTH + 1];
3910 	mib2_ipNetToMediaEntry_t	*np;
3911 	int		flags;
3912 	boolean_t	first;
3913 
3914 	if (!(family_selected(AF_INET)))
3915 		return;
3916 
3917 	/* 'for' loop 1: */
3918 	for (; item; item = item->next_item) {
3919 		if (Xflag) {
3920 			(void) printf("\n--- Entry %d ---\n", ++jtemp);
3921 			(void) printf("Group = %d, mib_id = %d, "
3922 			    "length = %d, valp = 0x%p\n",
3923 			    item->group, item->mib_id, item->length,
3924 			    item->valp);
3925 		}
3926 		if (!(item->group == MIB2_IP && item->mib_id == MIB2_IP_MEDIA))
3927 			continue; /* 'for' loop 1 */
3928 
3929 		if (Xflag)
3930 			(void) printf("%u records for "
3931 			    "ipNetToMediaEntryTable:\n",
3932 			    item->length/sizeof (mib2_ipNetToMediaEntry_t));
3933 
3934 		first = B_TRUE;
3935 		/* 'for' loop 2: */
3936 		for (np = (mib2_ipNetToMediaEntry_t *)item->valp;
3937 		    (char *)np < (char *)item->valp + item->length;
3938 		    /* LINTED: (note 1) */
3939 		    np = (mib2_ipNetToMediaEntry_t *)((char *)np +
3940 		    ipNetToMediaEntrySize)) {
3941 			if (first) {
3942 				(void) puts(v4compat ?
3943 				    "Net to Media Table" :
3944 				    "Net to Media Table: IPv4");
3945 				(void) puts("Device "
3946 				    "  IP Address               Mask      "
3947 				    "Flags      Phys Addr");
3948 				(void) puts("------ "
3949 				    "-------------------- --------------- "
3950 				    "-------- ---------------");
3951 				first = B_FALSE;
3952 			}
3953 
3954 			flbuf[0] = '\0';
3955 			flags = np->ipNetToMediaInfo.ntm_flags;
3956 			/*
3957 			 * Note that not all flags are possible at the same
3958 			 * time.  Patterns: SPLAy DUo
3959 			 */
3960 			if (flags & ACE_F_PERMANENT)
3961 				(void) strcat(flbuf, "S");
3962 			if (flags & ACE_F_PUBLISH)
3963 				(void) strcat(flbuf, "P");
3964 			if (flags & ACE_F_DYING)
3965 				(void) strcat(flbuf, "D");
3966 			if (!(flags & ACE_F_RESOLVED))
3967 				(void) strcat(flbuf, "U");
3968 			if (flags & ACE_F_MAPPING)
3969 				(void) strcat(flbuf, "M");
3970 			if (flags & ACE_F_MYADDR)
3971 				(void) strcat(flbuf, "L");
3972 			if (flags & ACE_F_UNVERIFIED)
3973 				(void) strcat(flbuf, "d");
3974 			if (flags & ACE_F_AUTHORITY)
3975 				(void) strcat(flbuf, "A");
3976 			if (flags & ACE_F_OLD)
3977 				(void) strcat(flbuf, "o");
3978 			if (flags & ACE_F_DELAYED)
3979 				(void) strcat(flbuf, "y");
3980 			(void) printf("%-6s %-20s %-15s %-8s %s\n",
3981 			    octetstr(&np->ipNetToMediaIfIndex, 'a',
3982 			    ifname, sizeof (ifname)),
3983 			    pr_addr(np->ipNetToMediaNetAddress,
3984 			    abuf, sizeof (abuf)),
3985 			    octetstr(&np->ipNetToMediaInfo.ntm_mask, 'd',
3986 			    maskbuf, sizeof (maskbuf)),
3987 			    flbuf,
3988 			    octetstr(&np->ipNetToMediaPhysAddress, 'h',
3989 			    xbuf, sizeof (xbuf)));
3990 		} /* 'for' loop 2 ends */
3991 	} /* 'for' loop 1 ends */
3992 	(void) fflush(stdout);
3993 }
3994 
3995 /* --------------------- NDP_REPORT (netstat -p) -------------------------- */
3996 
3997 static void
3998 ndp_report(mib_item_t *item)
3999 {
4000 	int		jtemp = 0;
4001 	char		abuf[MAXHOSTNAMELEN + 1];
4002 	char		*state;
4003 	char		*type;
4004 	char		xbuf[STR_EXPAND * OCTET_LENGTH + 1];
4005 	mib2_ipv6NetToMediaEntry_t	*np6;
4006 	char		ifname[LIFNAMSIZ + 1];
4007 	boolean_t	first;
4008 
4009 	if (!(family_selected(AF_INET6)))
4010 		return;
4011 
4012 	/* 'for' loop 1: */
4013 	for (; item; item = item->next_item) {
4014 		if (Xflag) {
4015 			(void) printf("\n--- Entry %d ---\n", ++jtemp);
4016 			(void) printf("Group = %d, mib_id = %d, "
4017 			    "length = %d, valp = 0x%p\n",
4018 			    item->group, item->mib_id, item->length,
4019 			    item->valp);
4020 		}
4021 		if (!(item->group == MIB2_IP6 &&
4022 		    item->mib_id == MIB2_IP6_MEDIA))
4023 			continue; /* 'for' loop 1 */
4024 
4025 		first = B_TRUE;
4026 		/* 'for' loop 2: */
4027 		for (np6 = (mib2_ipv6NetToMediaEntry_t *)item->valp;
4028 		    (char *)np6 < (char *)item->valp + item->length;
4029 		    /* LINTED: (note 1) */
4030 		    np6 = (mib2_ipv6NetToMediaEntry_t *)((char *)np6 +
4031 		    ipv6NetToMediaEntrySize)) {
4032 			if (first) {
4033 				(void) puts("\nNet to Media Table: IPv6");
4034 				(void) puts(" If   Physical Address   "
4035 				    " Type      State      Destination/Mask");
4036 				(void) puts("----- -----------------  "
4037 				    "------- ------------ "
4038 				    "---------------------------");
4039 				first = B_FALSE;
4040 			}
4041 
4042 			switch (np6->ipv6NetToMediaState) {
4043 			case ND_INCOMPLETE:
4044 				state = "INCOMPLETE";
4045 				break;
4046 			case ND_REACHABLE:
4047 				state = "REACHABLE";
4048 				break;
4049 			case ND_STALE:
4050 				state = "STALE";
4051 				break;
4052 			case ND_DELAY:
4053 				state = "DELAY";
4054 				break;
4055 			case ND_PROBE:
4056 				state = "PROBE";
4057 				break;
4058 			case ND_UNREACHABLE:
4059 				state = "UNREACHABLE";
4060 				break;
4061 			default:
4062 				state = "UNKNOWN";
4063 			}
4064 
4065 			switch (np6->ipv6NetToMediaType) {
4066 			case 1:
4067 				type = "other";
4068 				break;
4069 			case 2:
4070 				type = "dynamic";
4071 				break;
4072 			case 3:
4073 				type = "static";
4074 				break;
4075 			case 4:
4076 				type = "local";
4077 				break;
4078 			}
4079 			(void) printf("%-5s %-17s  %-7s %-12s %-27s\n",
4080 			    ifindex2str(np6->ipv6NetToMediaIfIndex, ifname),
4081 			    octetstr(&np6->ipv6NetToMediaPhysAddress, 'h',
4082 			    xbuf, sizeof (xbuf)),
4083 			    type,
4084 			    state,
4085 			    pr_addr6(&np6->ipv6NetToMediaNetAddress,
4086 			    abuf, sizeof (abuf)));
4087 		} /* 'for' loop 2 ends */
4088 	} /* 'for' loop 1 ends */
4089 	(void) putchar('\n');
4090 	(void) fflush(stdout);
4091 }
4092 
4093 /* ------------------------- ire_report (netstat -r) ------------------------ */
4094 
4095 typedef struct sec_attr_list_s {
4096 	struct sec_attr_list_s *sal_next;
4097 	const mib2_ipAttributeEntry_t *sal_attr;
4098 } sec_attr_list_t;
4099 
4100 static boolean_t ire_report_item_v4(const mib2_ipRouteEntry_t *, boolean_t,
4101     const sec_attr_list_t *);
4102 static boolean_t ire_report_item_v6(const mib2_ipv6RouteEntry_t *, boolean_t,
4103     const sec_attr_list_t *);
4104 static const char *pr_secattr(const sec_attr_list_t *);
4105 
4106 static void
4107 ire_report(const mib_item_t *item)
4108 {
4109 	int			jtemp = 0;
4110 	boolean_t		print_hdr_once_v4 = B_TRUE;
4111 	boolean_t		print_hdr_once_v6 = B_TRUE;
4112 	mib2_ipRouteEntry_t	*rp;
4113 	mib2_ipv6RouteEntry_t	*rp6;
4114 	sec_attr_list_t		**v4_attrs, **v4a;
4115 	sec_attr_list_t		**v6_attrs, **v6a;
4116 	sec_attr_list_t		*all_attrs, *aptr;
4117 	const mib_item_t	*iptr;
4118 	int			ipv4_route_count, ipv6_route_count;
4119 	int			route_attrs_count;
4120 
4121 	/*
4122 	 * Preparation pass: the kernel returns separate entries for IP routing
4123 	 * table entries and security attributes.  We loop through the
4124 	 * attributes first and link them into lists.
4125 	 */
4126 	ipv4_route_count = ipv6_route_count = route_attrs_count = 0;
4127 	for (iptr = item; iptr != NULL; iptr = iptr->next_item) {
4128 		if (iptr->group == MIB2_IP6 && iptr->mib_id == MIB2_IP6_ROUTE)
4129 			ipv6_route_count += iptr->length / ipv6RouteEntrySize;
4130 		if (iptr->group == MIB2_IP && iptr->mib_id == MIB2_IP_ROUTE)
4131 			ipv4_route_count += iptr->length / ipRouteEntrySize;
4132 		if ((iptr->group == MIB2_IP || iptr->group == MIB2_IP6) &&
4133 		    iptr->mib_id == EXPER_IP_RTATTR)
4134 			route_attrs_count += iptr->length /
4135 			    ipRouteAttributeSize;
4136 	}
4137 	v4_attrs = v6_attrs = NULL;
4138 	all_attrs = NULL;
4139 	if (family_selected(AF_INET) && ipv4_route_count > 0) {
4140 		v4_attrs = calloc(ipv4_route_count, sizeof (*v4_attrs));
4141 		if (v4_attrs == NULL) {
4142 			perror("ire_report calloc v4_attrs failed");
4143 			return;
4144 		}
4145 	}
4146 	if (family_selected(AF_INET6) && ipv6_route_count > 0) {
4147 		v6_attrs = calloc(ipv6_route_count, sizeof (*v6_attrs));
4148 		if (v6_attrs == NULL) {
4149 			perror("ire_report calloc v6_attrs failed");
4150 			goto ire_report_done;
4151 		}
4152 	}
4153 	if (route_attrs_count > 0) {
4154 		all_attrs = malloc(route_attrs_count * sizeof (*all_attrs));
4155 		if (all_attrs == NULL) {
4156 			perror("ire_report malloc all_attrs failed");
4157 			goto ire_report_done;
4158 		}
4159 	}
4160 	aptr = all_attrs;
4161 	for (iptr = item; iptr != NULL; iptr = iptr->next_item) {
4162 		mib2_ipAttributeEntry_t *iae;
4163 		sec_attr_list_t **alp;
4164 
4165 		if (v4_attrs != NULL && iptr->group == MIB2_IP &&
4166 		    iptr->mib_id == EXPER_IP_RTATTR) {
4167 			alp = v4_attrs;
4168 		} else if (v6_attrs != NULL && iptr->group == MIB2_IP6 &&
4169 		    iptr->mib_id == EXPER_IP_RTATTR) {
4170 			alp = v6_attrs;
4171 		} else {
4172 			continue;
4173 		}
4174 		for (iae = iptr->valp;
4175 		    (char *)iae < (char *)iptr->valp + iptr->length;
4176 		    /* LINTED: (note 1) */
4177 		    iae = (mib2_ipAttributeEntry_t *)((char *)iae +
4178 		    ipRouteAttributeSize)) {
4179 			aptr->sal_next = alp[iae->iae_routeidx];
4180 			aptr->sal_attr = iae;
4181 			alp[iae->iae_routeidx] = aptr++;
4182 		}
4183 	}
4184 
4185 	/* 'for' loop 1: */
4186 	v4a = v4_attrs;
4187 	v6a = v6_attrs;
4188 	for (; item != NULL; item = item->next_item) {
4189 		if (Xflag) {
4190 			(void) printf("\n--- Entry %d ---\n", ++jtemp);
4191 			(void) printf("Group = %d, mib_id = %d, "
4192 			    "length = %d, valp = 0x%p\n",
4193 			    item->group, item->mib_id,
4194 			    item->length, item->valp);
4195 		}
4196 		if (!((item->group == MIB2_IP &&
4197 		    item->mib_id == MIB2_IP_ROUTE) ||
4198 		    (item->group == MIB2_IP6 &&
4199 		    item->mib_id == MIB2_IP6_ROUTE)))
4200 			continue; /* 'for' loop 1 */
4201 
4202 		if (item->group == MIB2_IP && !family_selected(AF_INET))
4203 			continue; /* 'for' loop 1 */
4204 		else if (item->group == MIB2_IP6 && !family_selected(AF_INET6))
4205 			continue; /* 'for' loop 1 */
4206 
4207 		if (Xflag) {
4208 			if (item->group == MIB2_IP) {
4209 				(void) printf("%u records for "
4210 				    "ipRouteEntryTable:\n",
4211 				    item->length/sizeof (mib2_ipRouteEntry_t));
4212 			} else {
4213 				(void) printf("%u records for "
4214 				    "ipv6RouteEntryTable:\n",
4215 				    item->length/
4216 				    sizeof (mib2_ipv6RouteEntry_t));
4217 			}
4218 		}
4219 
4220 		if (item->group == MIB2_IP) {
4221 			for (rp = (mib2_ipRouteEntry_t *)item->valp;
4222 			    (char *)rp < (char *)item->valp + item->length;
4223 			    /* LINTED: (note 1) */
4224 			    rp = (mib2_ipRouteEntry_t *)((char *)rp +
4225 			    ipRouteEntrySize)) {
4226 				aptr = v4a == NULL ? NULL : *v4a++;
4227 				print_hdr_once_v4 = ire_report_item_v4(rp,
4228 				    print_hdr_once_v4, aptr);
4229 			}
4230 		} else {
4231 			for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp;
4232 			    (char *)rp6 < (char *)item->valp + item->length;
4233 			    /* LINTED: (note 1) */
4234 			    rp6 = (mib2_ipv6RouteEntry_t *)((char *)rp6 +
4235 			    ipv6RouteEntrySize)) {
4236 				aptr = v6a == NULL ? NULL : *v6a++;
4237 				print_hdr_once_v6 = ire_report_item_v6(rp6,
4238 				    print_hdr_once_v6, aptr);
4239 			}
4240 		}
4241 	} /* 'for' loop 1 ends */
4242 	(void) fflush(stdout);
4243 ire_report_done:
4244 	if (v4_attrs != NULL)
4245 		free(v4_attrs);
4246 	if (v6_attrs != NULL)
4247 		free(v6_attrs);
4248 	if (all_attrs != NULL)
4249 		free(all_attrs);
4250 }
4251 
4252 /*
4253  * Match a user-supplied device name.  We do this by string because
4254  * the MIB2 interface gives us interface name strings rather than
4255  * ifIndex numbers.  The "none" rule matches only routes with no
4256  * interface.  The "any" rule matches routes with any non-blank
4257  * interface.  A base name ("hme0") matches all aliases as well
4258  * ("hme0:1").
4259  */
4260 static boolean_t
4261 dev_name_match(const DeviceName *devnam, const char *ifname)
4262 {
4263 	int iflen;
4264 
4265 	if (ifname == NULL)
4266 		return (devnam->o_length == 0);		/* "none" */
4267 	if (*ifname == '\0')
4268 		return (devnam->o_length != 0);		/* "any" */
4269 	iflen = strlen(ifname);
4270 	/* The check for ':' here supports interface aliases. */
4271 	if (iflen > devnam->o_length ||
4272 	    (iflen < devnam->o_length && devnam->o_bytes[iflen] != ':'))
4273 		return (B_FALSE);
4274 	return (strncmp(ifname, devnam->o_bytes, iflen) == 0);
4275 }
4276 
4277 /*
4278  * Match a user-supplied IP address list.  The "any" rule matches any
4279  * non-zero address.  The "none" rule matches only the zero address.
4280  * IPv6 addresses supplied by the user are ignored.  If the user
4281  * supplies a subnet mask, then match routes that are at least that
4282  * specific (use the user's mask).  If the user supplies only an
4283  * address, then select any routes that would match (use the route's
4284  * mask).
4285  */
4286 static boolean_t
4287 v4_addr_match(IpAddress addr, IpAddress mask, const filter_t *fp)
4288 {
4289 	char **app;
4290 	char *aptr;
4291 	in_addr_t faddr, fmask;
4292 
4293 	if (fp->u.a.f_address == NULL) {
4294 		if (IN6_IS_ADDR_UNSPECIFIED(&fp->u.a.f_mask))
4295 			return (addr != INADDR_ANY);	/* "any" */
4296 		else
4297 			return (addr == INADDR_ANY);	/* "none" */
4298 	}
4299 	if (!IN6_IS_V4MASK(fp->u.a.f_mask))
4300 		return (B_FALSE);
4301 	IN6_V4MAPPED_TO_IPADDR(&fp->u.a.f_mask, fmask);
4302 	if (fmask != IP_HOST_MASK) {
4303 		if (fmask > mask)
4304 			return (B_FALSE);
4305 		mask = fmask;
4306 	}
4307 	for (app = fp->u.a.f_address->h_addr_list; (aptr = *app) != NULL; app++)
4308 		/* LINTED: (note 1) */
4309 		if (IN6_IS_ADDR_V4MAPPED((in6_addr_t *)aptr)) {
4310 			/* LINTED: (note 1) */
4311 			IN6_V4MAPPED_TO_IPADDR((in6_addr_t *)aptr, faddr);
4312 			if (((faddr ^ addr) & mask) == 0)
4313 				return (B_TRUE);
4314 		}
4315 	return (B_FALSE);
4316 }
4317 
4318 /*
4319  * Run through the filter list for an IPv4 MIB2 route entry.  If all
4320  * filters of a given type fail to match, then the route is filtered
4321  * out (not displayed).  If no filter is given or at least one filter
4322  * of each type matches, then display the route.
4323  */
4324 static boolean_t
4325 ire_filter_match_v4(const mib2_ipRouteEntry_t *rp, uint_t flag_b)
4326 {
4327 	filter_t *fp;
4328 	int idx;
4329 
4330 	/* 'for' loop 1: */
4331 	for (idx = 0; idx < NFILTERKEYS; idx++)
4332 		if ((fp = filters[idx]) != NULL) {
4333 			/* 'for' loop 2: */
4334 			for (; fp != NULL; fp = fp->f_next) {
4335 				switch (idx) {
4336 				case FK_AF:
4337 					if (fp->u.f_family != AF_INET)
4338 						continue; /* 'for' loop 2 */
4339 					break;
4340 				case FK_OUTIF:
4341 					if (!dev_name_match(&rp->ipRouteIfIndex,
4342 					    fp->u.f_ifname))
4343 						continue; /* 'for' loop 2 */
4344 					break;
4345 				case FK_DST:
4346 					if (!v4_addr_match(rp->ipRouteDest,
4347 					    rp->ipRouteMask, fp))
4348 						continue; /* 'for' loop 2 */
4349 					break;
4350 				case FK_FLAGS:
4351 					if ((flag_b & fp->u.f.f_flagset) !=
4352 					    fp->u.f.f_flagset ||
4353 					    (flag_b & fp->u.f.f_flagclear))
4354 						continue; /* 'for' loop 2 */
4355 					break;
4356 				}
4357 				break;
4358 			} /* 'for' loop 2 ends */
4359 			if (fp == NULL)
4360 				return (B_FALSE);
4361 		}
4362 	/* 'for' loop 1 ends */
4363 	return (B_TRUE);
4364 }
4365 
4366 /*
4367  * Given an IPv4 MIB2 route entry, form the list of flags for the
4368  * route.
4369  */
4370 static uint_t
4371 form_v4_route_flags(const mib2_ipRouteEntry_t *rp, char *flags)
4372 {
4373 	uint_t flag_b;
4374 
4375 	flag_b = FLF_U;
4376 	(void) strcpy(flags, "U");
4377 	/* RTF_INDIRECT wins over RTF_GATEWAY - don't display both */
4378 	if (rp->ipRouteInfo.re_flags & RTF_INDIRECT) {
4379 		(void) strcat(flags, "I");
4380 		flag_b |= FLF_I;
4381 	} else if (rp->ipRouteInfo.re_ire_type & IRE_OFFLINK) {
4382 		(void) strcat(flags, "G");
4383 		flag_b |= FLF_G;
4384 	}
4385 	/* IRE_IF_CLONE wins over RTF_HOST - don't display both */
4386 	if (rp->ipRouteInfo.re_ire_type & IRE_IF_CLONE) {
4387 		(void) strcat(flags, "C");
4388 		flag_b |= FLF_C;
4389 	} else if (rp->ipRouteMask == IP_HOST_MASK) {
4390 		(void) strcat(flags, "H");
4391 		flag_b |= FLF_H;
4392 	}
4393 	if (rp->ipRouteInfo.re_flags & RTF_DYNAMIC) {
4394 		(void) strcat(flags, "D");
4395 		flag_b |= FLF_D;
4396 	}
4397 	if (rp->ipRouteInfo.re_ire_type == IRE_BROADCAST) {	/* Broadcast */
4398 		(void) strcat(flags, "b");
4399 		flag_b |= FLF_b;
4400 	}
4401 	if (rp->ipRouteInfo.re_ire_type == IRE_LOCAL) {		/* Local */
4402 		(void) strcat(flags, "L");
4403 		flag_b |= FLF_L;
4404 	}
4405 	if (rp->ipRouteInfo.re_flags & RTF_MULTIRT) {
4406 		(void) strcat(flags, "M");			/* Multiroute */
4407 		flag_b |= FLF_M;
4408 	}
4409 	if (rp->ipRouteInfo.re_flags & RTF_SETSRC) {
4410 		(void) strcat(flags, "S");			/* Setsrc */
4411 		flag_b |= FLF_S;
4412 	}
4413 	if (rp->ipRouteInfo.re_flags & RTF_REJECT) {
4414 		(void) strcat(flags, "R");
4415 		flag_b |= FLF_R;
4416 	}
4417 	if (rp->ipRouteInfo.re_flags & RTF_BLACKHOLE) {
4418 		(void) strcat(flags, "B");
4419 		flag_b |= FLF_B;
4420 	}
4421 	if (rp->ipRouteInfo.re_flags & RTF_ZONE) {
4422 		(void) strcat(flags, "Z");
4423 		flag_b |= FLF_Z;
4424 	}
4425 	return (flag_b);
4426 }
4427 
4428 static const char ire_hdr_v4[] =
4429 "\n%s Table: IPv4\n";
4430 static const char ire_hdr_v4_compat[] =
4431 "\n%s Table:\n";
4432 static const char ire_hdr_v4_verbose[] =
4433 "  Destination             Mask           Gateway          Device "
4434 " MTU  Ref Flg  Out  In/Fwd %s\n"
4435 "-------------------- --------------- -------------------- ------ "
4436 "----- --- --- ----- ------ %s\n";
4437 
4438 static const char ire_hdr_v4_normal[] =
4439 "  Destination           Gateway           Flags  Ref     Use     Interface"
4440 " %s\n-------------------- -------------------- ----- ----- ---------- "
4441 "--------- %s\n";
4442 
4443 static boolean_t
4444 ire_report_item_v4(const mib2_ipRouteEntry_t *rp, boolean_t first,
4445     const sec_attr_list_t *attrs)
4446 {
4447 	char			dstbuf[MAXHOSTNAMELEN + 4]; /* + "/<num>" */
4448 	char			maskbuf[MAXHOSTNAMELEN + 1];
4449 	char			gwbuf[MAXHOSTNAMELEN + 1];
4450 	char			ifname[LIFNAMSIZ + 1];
4451 	char			flags[10];	/* RTF_ flags */
4452 	uint_t			flag_b;
4453 
4454 	if (!(Aflag || (rp->ipRouteInfo.re_ire_type != IRE_IF_CLONE &&
4455 	    rp->ipRouteInfo.re_ire_type != IRE_BROADCAST &&
4456 	    rp->ipRouteInfo.re_ire_type != IRE_MULTICAST &&
4457 	    rp->ipRouteInfo.re_ire_type != IRE_NOROUTE &&
4458 	    rp->ipRouteInfo.re_ire_type != IRE_LOCAL))) {
4459 		return (first);
4460 	}
4461 
4462 	flag_b = form_v4_route_flags(rp, flags);
4463 
4464 	if (!ire_filter_match_v4(rp, flag_b))
4465 		return (first);
4466 
4467 	if (first) {
4468 		(void) printf(v4compat ? ire_hdr_v4_compat : ire_hdr_v4,
4469 		    Vflag ? "IRE" : "Routing");
4470 		(void) printf(Vflag ? ire_hdr_v4_verbose : ire_hdr_v4_normal,
4471 		    RSECflag ? "  Gateway security attributes  " : "",
4472 		    RSECflag ? "-------------------------------" : "");
4473 		first = B_FALSE;
4474 	}
4475 
4476 	if (flag_b & FLF_H) {
4477 		(void) pr_addr(rp->ipRouteDest, dstbuf, sizeof (dstbuf));
4478 	} else {
4479 		(void) pr_net(rp->ipRouteDest, rp->ipRouteMask,
4480 		    dstbuf, sizeof (dstbuf));
4481 	}
4482 	if (Vflag) {
4483 		(void) printf("%-20s %-15s %-20s %-6s %5u %3u "
4484 		    "%-4s%6u %6u %s\n",
4485 		    dstbuf,
4486 		    pr_mask(rp->ipRouteMask, maskbuf, sizeof (maskbuf)),
4487 		    pr_addrnz(rp->ipRouteNextHop, gwbuf, sizeof (gwbuf)),
4488 		    octetstr(&rp->ipRouteIfIndex, 'a', ifname, sizeof (ifname)),
4489 		    rp->ipRouteInfo.re_max_frag,
4490 		    rp->ipRouteInfo.re_ref,
4491 		    flags,
4492 		    rp->ipRouteInfo.re_obpkt,
4493 		    rp->ipRouteInfo.re_ibpkt,
4494 		    pr_secattr(attrs));
4495 	} else {
4496 		(void) printf("%-20s %-20s %-5s  %4u %10u %-9s %s\n",
4497 		    dstbuf,
4498 		    pr_addrnz(rp->ipRouteNextHop, gwbuf, sizeof (gwbuf)),
4499 		    flags,
4500 		    rp->ipRouteInfo.re_ref,
4501 		    rp->ipRouteInfo.re_obpkt + rp->ipRouteInfo.re_ibpkt,
4502 		    octetstr(&rp->ipRouteIfIndex, 'a',
4503 		    ifname, sizeof (ifname)),
4504 		    pr_secattr(attrs));
4505 	}
4506 	return (first);
4507 }
4508 
4509 /*
4510  * Match a user-supplied IP address list against an IPv6 route entry.
4511  * If the user specified "any," then any non-zero address matches.  If
4512  * the user specified "none," then only the zero address matches.  If
4513  * the user specified a subnet mask length, then use that in matching
4514  * routes (select routes that are at least as specific).  If the user
4515  * specified only an address, then use the route's mask (select routes
4516  * that would match that address).  IPv4 addresses are ignored.
4517  */
4518 static boolean_t
4519 v6_addr_match(const Ip6Address *addr, int masklen, const filter_t *fp)
4520 {
4521 	const uint8_t *ucp;
4522 	int fmasklen;
4523 	int i;
4524 	char **app;
4525 	const uint8_t *aptr;
4526 
4527 	if (fp->u.a.f_address == NULL) {
4528 		if (IN6_IS_ADDR_UNSPECIFIED(&fp->u.a.f_mask))	/* any */
4529 			return (!IN6_IS_ADDR_UNSPECIFIED(addr));
4530 		return (IN6_IS_ADDR_UNSPECIFIED(addr));		/* "none" */
4531 	}
4532 	fmasklen = 0;
4533 	/* 'for' loop 1a: */
4534 	for (ucp = fp->u.a.f_mask.s6_addr;
4535 	    ucp < fp->u.a.f_mask.s6_addr + sizeof (fp->u.a.f_mask.s6_addr);
4536 	    ucp++) {
4537 		if (*ucp != 0xff) {
4538 			if (*ucp != 0)
4539 				fmasklen += 9 - ffs(*ucp);
4540 			break; /* 'for' loop 1a */
4541 		}
4542 		fmasklen += 8;
4543 	} /* 'for' loop 1a ends */
4544 	if (fmasklen != IPV6_ABITS) {
4545 		if (fmasklen > masklen)
4546 			return (B_FALSE);
4547 		masklen = fmasklen;
4548 	}
4549 	/* 'for' loop 1b: */
4550 	for (app = fp->u.a.f_address->h_addr_list;
4551 	    (aptr = (uint8_t *)*app) != NULL; app++) {
4552 		/* LINTED: (note 1) */
4553 		if (IN6_IS_ADDR_V4MAPPED((in6_addr_t *)aptr))
4554 			continue; /* 'for' loop 1b */
4555 		ucp = addr->s6_addr;
4556 		for (i = masklen; i >= 8; i -= 8)
4557 			if (*ucp++ != *aptr++)
4558 				break; /* 'for' loop 1b */
4559 		if (i == 0 ||
4560 		    (i < 8 && ((*ucp ^ *aptr) & ~(0xff >> i)) == 0))
4561 			return (B_TRUE);
4562 	} /* 'for' loop 1b ends */
4563 	return (B_FALSE);
4564 }
4565 
4566 /*
4567  * Run through the filter list for an IPv6 MIB2 IRE.  For a given
4568  * type, if there's at least one filter and all filters of that type
4569  * fail to match, then the route doesn't match and isn't displayed.
4570  * If at least one matches, or none are specified, for each of the
4571  * types, then the route is selected and displayed.
4572  */
4573 static boolean_t
4574 ire_filter_match_v6(const mib2_ipv6RouteEntry_t *rp6, uint_t flag_b)
4575 {
4576 	filter_t *fp;
4577 	int idx;
4578 
4579 	/* 'for' loop 1: */
4580 	for (idx = 0; idx < NFILTERKEYS; idx++)
4581 		if ((fp = filters[idx]) != NULL) {
4582 			/* 'for' loop 2: */
4583 			for (; fp != NULL; fp = fp->f_next) {
4584 				switch (idx) {
4585 				case FK_AF:
4586 					if (fp->u.f_family != AF_INET6)
4587 						/* 'for' loop 2 */
4588 						continue;
4589 					break;
4590 				case FK_OUTIF:
4591 					if (!dev_name_match(&rp6->
4592 					    ipv6RouteIfIndex, fp->u.f_ifname))
4593 						/* 'for' loop 2 */
4594 						continue;
4595 					break;
4596 				case FK_DST:
4597 					if (!v6_addr_match(&rp6->ipv6RouteDest,
4598 					    rp6->ipv6RoutePfxLength, fp))
4599 						/* 'for' loop 2 */
4600 						continue;
4601 					break;
4602 				case FK_FLAGS:
4603 					if ((flag_b & fp->u.f.f_flagset) !=
4604 					    fp->u.f.f_flagset ||
4605 					    (flag_b & fp->u.f.f_flagclear))
4606 						/* 'for' loop 2 */
4607 						continue;
4608 					break;
4609 				}
4610 				break;
4611 			} /* 'for' loop 2 ends */
4612 			if (fp == NULL)
4613 				return (B_FALSE);
4614 		}
4615 	/* 'for' loop 1 ends */
4616 	return (B_TRUE);
4617 }
4618 
4619 /*
4620  * Given an IPv6 MIB2 route entry, form the list of flags for the
4621  * route.
4622  */
4623 static uint_t
4624 form_v6_route_flags(const mib2_ipv6RouteEntry_t *rp6, char *flags)
4625 {
4626 	uint_t flag_b;
4627 
4628 	flag_b = FLF_U;
4629 	(void) strcpy(flags, "U");
4630 	/* RTF_INDIRECT wins over RTF_GATEWAY - don't display both */
4631 	if (rp6->ipv6RouteInfo.re_flags & RTF_INDIRECT) {
4632 		(void) strcat(flags, "I");
4633 		flag_b |= FLF_I;
4634 	} else if (rp6->ipv6RouteInfo.re_ire_type & IRE_OFFLINK) {
4635 		(void) strcat(flags, "G");
4636 		flag_b |= FLF_G;
4637 	}
4638 
4639 	/* IRE_IF_CLONE wins over RTF_HOST - don't display both */
4640 	if (rp6->ipv6RouteInfo.re_ire_type & IRE_IF_CLONE) {
4641 		(void) strcat(flags, "C");
4642 		flag_b |= FLF_C;
4643 	} else if (rp6->ipv6RoutePfxLength == IPV6_ABITS) {
4644 		(void) strcat(flags, "H");
4645 		flag_b |= FLF_H;
4646 	}
4647 
4648 	if (rp6->ipv6RouteInfo.re_flags & RTF_DYNAMIC) {
4649 		(void) strcat(flags, "D");
4650 		flag_b |= FLF_D;
4651 	}
4652 	if (rp6->ipv6RouteInfo.re_ire_type == IRE_LOCAL) {	/* Local */
4653 		(void) strcat(flags, "L");
4654 		flag_b |= FLF_L;
4655 	}
4656 	if (rp6->ipv6RouteInfo.re_flags & RTF_MULTIRT) {
4657 		(void) strcat(flags, "M");			/* Multiroute */
4658 		flag_b |= FLF_M;
4659 	}
4660 	if (rp6->ipv6RouteInfo.re_flags & RTF_SETSRC) {
4661 		(void) strcat(flags, "S");			/* Setsrc */
4662 		flag_b |= FLF_S;
4663 	}
4664 	if (rp6->ipv6RouteInfo.re_flags & RTF_REJECT) {
4665 		(void) strcat(flags, "R");
4666 		flag_b |= FLF_R;
4667 	}
4668 	if (rp6->ipv6RouteInfo.re_flags & RTF_BLACKHOLE) {
4669 		(void) strcat(flags, "B");
4670 		flag_b |= FLF_B;
4671 	}
4672 	if (rp6->ipv6RouteInfo.re_flags & RTF_ZONE) {
4673 		(void) strcat(flags, "Z");
4674 		flag_b |= FLF_Z;
4675 	}
4676 	return (flag_b);
4677 }
4678 
4679 static const char ire_hdr_v6[] =
4680 "\n%s Table: IPv6\n";
4681 static const char ire_hdr_v6_verbose[] =
4682 "  Destination/Mask            Gateway                    If    MTU  "
4683 "Ref Flags  Out   In/Fwd %s\n"
4684 "--------------------------- --------------------------- ----- ----- "
4685 "--- ----- ------ ------ %s\n";
4686 static const char ire_hdr_v6_normal[] =
4687 "  Destination/Mask            Gateway                   Flags Ref   Use  "
4688 "  If   %s\n"
4689 "--------------------------- --------------------------- ----- --- ------- "
4690 "----- %s\n";
4691 
4692 static boolean_t
4693 ire_report_item_v6(const mib2_ipv6RouteEntry_t *rp6, boolean_t first,
4694     const sec_attr_list_t *attrs)
4695 {
4696 	char			dstbuf[MAXHOSTNAMELEN + 1];
4697 	char			gwbuf[MAXHOSTNAMELEN + 1];
4698 	char			ifname[LIFNAMSIZ + 1];
4699 	char			flags[10];	/* RTF_ flags */
4700 	uint_t			flag_b;
4701 
4702 	if (!(Aflag || (rp6->ipv6RouteInfo.re_ire_type != IRE_IF_CLONE &&
4703 	    rp6->ipv6RouteInfo.re_ire_type != IRE_MULTICAST &&
4704 	    rp6->ipv6RouteInfo.re_ire_type != IRE_NOROUTE &&
4705 	    rp6->ipv6RouteInfo.re_ire_type != IRE_LOCAL))) {
4706 		return (first);
4707 	}
4708 
4709 	flag_b = form_v6_route_flags(rp6, flags);
4710 
4711 	if (!ire_filter_match_v6(rp6, flag_b))
4712 		return (first);
4713 
4714 	if (first) {
4715 		(void) printf(ire_hdr_v6, Vflag ? "IRE" : "Routing");
4716 		(void) printf(Vflag ? ire_hdr_v6_verbose : ire_hdr_v6_normal,
4717 		    RSECflag ? "  Gateway security attributes  " : "",
4718 		    RSECflag ? "-------------------------------" : "");
4719 		first = B_FALSE;
4720 	}
4721 
4722 	if (Vflag) {
4723 		(void) printf("%-27s %-27s %-5s %5u %3u "
4724 		    "%-5s %6u %6u %s\n",
4725 		    pr_prefix6(&rp6->ipv6RouteDest,
4726 		    rp6->ipv6RoutePfxLength, dstbuf, sizeof (dstbuf)),
4727 		    IN6_IS_ADDR_UNSPECIFIED(&rp6->ipv6RouteNextHop) ?
4728 		    "    --" :
4729 		    pr_addr6(&rp6->ipv6RouteNextHop, gwbuf, sizeof (gwbuf)),
4730 		    octetstr(&rp6->ipv6RouteIfIndex, 'a',
4731 		    ifname, sizeof (ifname)),
4732 		    rp6->ipv6RouteInfo.re_max_frag,
4733 		    rp6->ipv6RouteInfo.re_ref,
4734 		    flags,
4735 		    rp6->ipv6RouteInfo.re_obpkt,
4736 		    rp6->ipv6RouteInfo.re_ibpkt,
4737 		    pr_secattr(attrs));
4738 	} else {
4739 		(void) printf("%-27s %-27s %-5s %3u %7u %-5s %s\n",
4740 		    pr_prefix6(&rp6->ipv6RouteDest,
4741 		    rp6->ipv6RoutePfxLength, dstbuf, sizeof (dstbuf)),
4742 		    IN6_IS_ADDR_UNSPECIFIED(&rp6->ipv6RouteNextHop) ?
4743 		    "    --" :
4744 		    pr_addr6(&rp6->ipv6RouteNextHop, gwbuf, sizeof (gwbuf)),
4745 		    flags,
4746 		    rp6->ipv6RouteInfo.re_ref,
4747 		    rp6->ipv6RouteInfo.re_obpkt + rp6->ipv6RouteInfo.re_ibpkt,
4748 		    octetstr(&rp6->ipv6RouteIfIndex, 'a',
4749 		    ifname, sizeof (ifname)),
4750 		    pr_secattr(attrs));
4751 	}
4752 	return (first);
4753 }
4754 
4755 /*
4756  * Common attribute-gathering routine for all transports.
4757  */
4758 static mib2_transportMLPEntry_t **
4759 gather_attrs(const mib_item_t *item, int group, int mib_id, int esize)
4760 {
4761 	int transport_count = 0;
4762 	const mib_item_t *iptr;
4763 	mib2_transportMLPEntry_t **attrs, *tme;
4764 
4765 	for (iptr = item; iptr != NULL; iptr = iptr->next_item) {
4766 		if (iptr->group == group && iptr->mib_id == mib_id)
4767 			transport_count += iptr->length / esize;
4768 	}
4769 	if (transport_count <= 0)
4770 		return (NULL);
4771 	attrs = calloc(transport_count, sizeof (*attrs));
4772 	if (attrs == NULL) {
4773 		perror("gather_attrs calloc failed");
4774 		return (NULL);
4775 	}
4776 	for (iptr = item; iptr != NULL; iptr = iptr->next_item) {
4777 		if (iptr->group == group && iptr->mib_id == EXPER_XPORT_MLP) {
4778 			for (tme = iptr->valp;
4779 			    (char *)tme < (char *)iptr->valp + iptr->length;
4780 			    /* LINTED: (note 1) */
4781 			    tme = (mib2_transportMLPEntry_t *)((char *)tme +
4782 			    transportMLPSize)) {
4783 				attrs[tme->tme_connidx] = tme;
4784 			}
4785 		}
4786 	}
4787 	return (attrs);
4788 }
4789 
4790 static void
4791 print_transport_label(const mib2_transportMLPEntry_t *attr)
4792 {
4793 	if (!RSECflag || attr == NULL ||
4794 	    !(attr->tme_flags & MIB2_TMEF_IS_LABELED))
4795 		return;
4796 
4797 	if (bisinvalid(&attr->tme_label)) {
4798 		(void) printf("   INVALID\n");
4799 	} else if (!blequal(&attr->tme_label, zone_security_label)) {
4800 		char *sl_str;
4801 
4802 		sl_str = sl_to_str(&attr->tme_label);
4803 		(void) printf("   %s\n", sl_str);
4804 		free(sl_str);
4805 	}
4806 }
4807 
4808 /* ------------------------------ TCP_REPORT------------------------------- */
4809 
4810 static const char tcp_hdr_v4[] =
4811 "\nTCP: IPv4\n";
4812 static const char tcp_hdr_v4_compat[] =
4813 "\nTCP\n";
4814 static const char tcp_hdr_v4_verbose[] =
4815 "Local/Remote Address Swind  Snext     Suna   Rwind  Rnext     Rack   "
4816 " Rto   Mss     State\n"
4817 "-------------------- ----- -------- -------- ----- -------- -------- "
4818 "----- ----- -----------\n";
4819 static const char tcp_hdr_v4_normal[] =
4820 "   Local Address        Remote Address    Swind Send-Q Rwind Recv-Q "
4821 "   State\n"
4822 "-------------------- -------------------- ----- ------ ----- ------ "
4823 "-----------\n";
4824 
4825 static const char tcp_hdr_v6[] =
4826 "\nTCP: IPv6\n";
4827 static const char tcp_hdr_v6_verbose[] =
4828 "Local/Remote Address              Swind  Snext     Suna   Rwind  Rnext   "
4829 "  Rack    Rto   Mss    State      If\n"
4830 "--------------------------------- ----- -------- -------- ----- -------- "
4831 "-------- ----- ----- ----------- -----\n";
4832 static const char tcp_hdr_v6_normal[] =
4833 "   Local Address                     Remote Address                 "
4834 "Swind Send-Q Rwind Recv-Q   State      If\n"
4835 "--------------------------------- --------------------------------- "
4836 "----- ------ ----- ------ ----------- -----\n";
4837 
4838 static boolean_t tcp_report_item_v4(const mib2_tcpConnEntry_t *,
4839     boolean_t first, const mib2_transportMLPEntry_t *);
4840 static boolean_t tcp_report_item_v6(const mib2_tcp6ConnEntry_t *,
4841     boolean_t first, const mib2_transportMLPEntry_t *);
4842 
4843 static void
4844 tcp_report(const mib_item_t *item)
4845 {
4846 	int			jtemp = 0;
4847 	boolean_t		print_hdr_once_v4 = B_TRUE;
4848 	boolean_t		print_hdr_once_v6 = B_TRUE;
4849 	mib2_tcpConnEntry_t	*tp;
4850 	mib2_tcp6ConnEntry_t	*tp6;
4851 	mib2_transportMLPEntry_t **v4_attrs, **v6_attrs;
4852 	mib2_transportMLPEntry_t **v4a, **v6a;
4853 	mib2_transportMLPEntry_t *aptr;
4854 
4855 	if (!protocol_selected(IPPROTO_TCP))
4856 		return;
4857 
4858 	/*
4859 	 * Preparation pass: the kernel returns separate entries for TCP
4860 	 * connection table entries and Multilevel Port attributes.  We loop
4861 	 * through the attributes first and set up an array for each address
4862 	 * family.
4863 	 */
4864 	v4_attrs = family_selected(AF_INET) && RSECflag ?
4865 	    gather_attrs(item, MIB2_TCP, MIB2_TCP_CONN, tcpConnEntrySize) :
4866 	    NULL;
4867 	v6_attrs = family_selected(AF_INET6) && RSECflag ?
4868 	    gather_attrs(item, MIB2_TCP6, MIB2_TCP6_CONN, tcp6ConnEntrySize) :
4869 	    NULL;
4870 
4871 	/* 'for' loop 1: */
4872 	v4a = v4_attrs;
4873 	v6a = v6_attrs;
4874 	for (; item != NULL; item = item->next_item) {
4875 		if (Xflag) {
4876 			(void) printf("\n--- Entry %d ---\n", ++jtemp);
4877 			(void) printf("Group = %d, mib_id = %d, "
4878 			    "length = %d, valp = 0x%p\n",
4879 			    item->group, item->mib_id,
4880 			    item->length, item->valp);
4881 		}
4882 
4883 		if (!((item->group == MIB2_TCP &&
4884 		    item->mib_id == MIB2_TCP_CONN) ||
4885 		    (item->group == MIB2_TCP6 &&
4886 		    item->mib_id == MIB2_TCP6_CONN)))
4887 			continue; /* 'for' loop 1 */
4888 
4889 		if (item->group == MIB2_TCP && !family_selected(AF_INET))
4890 			continue; /* 'for' loop 1 */
4891 		else if (item->group == MIB2_TCP6 && !family_selected(AF_INET6))
4892 			continue; /* 'for' loop 1 */
4893 
4894 		if (item->group == MIB2_TCP) {
4895 			for (tp = (mib2_tcpConnEntry_t *)item->valp;
4896 			    (char *)tp < (char *)item->valp + item->length;
4897 			    /* LINTED: (note 1) */
4898 			    tp = (mib2_tcpConnEntry_t *)((char *)tp +
4899 			    tcpConnEntrySize)) {
4900 				aptr = v4a == NULL ? NULL : *v4a++;
4901 				print_hdr_once_v4 = tcp_report_item_v4(tp,
4902 				    print_hdr_once_v4, aptr);
4903 			}
4904 		} else {
4905 			for (tp6 = (mib2_tcp6ConnEntry_t *)item->valp;
4906 			    (char *)tp6 < (char *)item->valp + item->length;
4907 			    /* LINTED: (note 1) */
4908 			    tp6 = (mib2_tcp6ConnEntry_t *)((char *)tp6 +
4909 			    tcp6ConnEntrySize)) {
4910 				aptr = v6a == NULL ? NULL : *v6a++;
4911 				print_hdr_once_v6 = tcp_report_item_v6(tp6,
4912 				    print_hdr_once_v6, aptr);
4913 			}
4914 		}
4915 	} /* 'for' loop 1 ends */
4916 	(void) fflush(stdout);
4917 
4918 	if (v4_attrs != NULL)
4919 		free(v4_attrs);
4920 	if (v6_attrs != NULL)
4921 		free(v6_attrs);
4922 }
4923 
4924 static boolean_t
4925 tcp_report_item_v4(const mib2_tcpConnEntry_t *tp, boolean_t first,
4926     const mib2_transportMLPEntry_t *attr)
4927 {
4928 	/*
4929 	 * lname and fname below are for the hostname as well as the portname
4930 	 * There is no limit on portname length so we assume MAXHOSTNAMELEN
4931 	 * as the limit
4932 	 */
4933 	char	lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4934 	char	fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4935 
4936 	if (!(Aflag || tp->tcpConnEntryInfo.ce_state >= TCPS_ESTABLISHED))
4937 		return (first); /* Nothing to print */
4938 
4939 	if (first) {
4940 		(void) printf(v4compat ? tcp_hdr_v4_compat : tcp_hdr_v4);
4941 		(void) printf(Vflag ? tcp_hdr_v4_verbose : tcp_hdr_v4_normal);
4942 	}
4943 
4944 	if (Vflag) {
4945 		(void) printf("%-20s\n%-20s %5u %08x %08x %5u %08x %08x "
4946 		    "%5u %5u %s\n",
4947 		    pr_ap(tp->tcpConnLocalAddress,
4948 		    tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
4949 		    pr_ap(tp->tcpConnRemAddress,
4950 		    tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
4951 		    tp->tcpConnEntryInfo.ce_swnd,
4952 		    tp->tcpConnEntryInfo.ce_snxt,
4953 		    tp->tcpConnEntryInfo.ce_suna,
4954 		    tp->tcpConnEntryInfo.ce_rwnd,
4955 		    tp->tcpConnEntryInfo.ce_rnxt,
4956 		    tp->tcpConnEntryInfo.ce_rack,
4957 		    tp->tcpConnEntryInfo.ce_rto,
4958 		    tp->tcpConnEntryInfo.ce_mss,
4959 		    mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
4960 	} else {
4961 		int sq = (int)tp->tcpConnEntryInfo.ce_snxt -
4962 		    (int)tp->tcpConnEntryInfo.ce_suna - 1;
4963 		int rq = (int)tp->tcpConnEntryInfo.ce_rnxt -
4964 		    (int)tp->tcpConnEntryInfo.ce_rack;
4965 
4966 		(void) printf("%-20s %-20s %5u %6d %5u %6d %s\n",
4967 		    pr_ap(tp->tcpConnLocalAddress,
4968 		    tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
4969 		    pr_ap(tp->tcpConnRemAddress,
4970 		    tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
4971 		    tp->tcpConnEntryInfo.ce_swnd,
4972 		    (sq >= 0) ? sq : 0,
4973 		    tp->tcpConnEntryInfo.ce_rwnd,
4974 		    (rq >= 0) ? rq : 0,
4975 		    mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
4976 	}
4977 
4978 	print_transport_label(attr);
4979 
4980 	return (B_FALSE);
4981 }
4982 
4983 static boolean_t
4984 tcp_report_item_v6(const mib2_tcp6ConnEntry_t *tp6, boolean_t first,
4985     const mib2_transportMLPEntry_t *attr)
4986 {
4987 	/*
4988 	 * lname and fname below are for the hostname as well as the portname
4989 	 * There is no limit on portname length so we assume MAXHOSTNAMELEN
4990 	 * as the limit
4991 	 */
4992 	char	lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4993 	char	fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4994 	char	ifname[LIFNAMSIZ + 1];
4995 	char	*ifnamep;
4996 
4997 	if (!(Aflag || tp6->tcp6ConnEntryInfo.ce_state >= TCPS_ESTABLISHED))
4998 		return (first); /* Nothing to print */
4999 
5000 	if (first) {
5001 		(void) printf(tcp_hdr_v6);
5002 		(void) printf(Vflag ? tcp_hdr_v6_verbose : tcp_hdr_v6_normal);
5003 	}
5004 
5005 	ifnamep = (tp6->tcp6ConnIfIndex != 0) ?
5006 	    if_indextoname(tp6->tcp6ConnIfIndex, ifname) : NULL;
5007 	if (ifnamep == NULL)
5008 		ifnamep = "";
5009 
5010 	if (Vflag) {
5011 		(void) printf("%-33s\n%-33s %5u %08x %08x %5u %08x %08x "
5012 		    "%5u %5u %-11s %s\n",
5013 		    pr_ap6(&tp6->tcp6ConnLocalAddress,
5014 		    tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5015 		    pr_ap6(&tp6->tcp6ConnRemAddress,
5016 		    tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5017 		    tp6->tcp6ConnEntryInfo.ce_swnd,
5018 		    tp6->tcp6ConnEntryInfo.ce_snxt,
5019 		    tp6->tcp6ConnEntryInfo.ce_suna,
5020 		    tp6->tcp6ConnEntryInfo.ce_rwnd,
5021 		    tp6->tcp6ConnEntryInfo.ce_rnxt,
5022 		    tp6->tcp6ConnEntryInfo.ce_rack,
5023 		    tp6->tcp6ConnEntryInfo.ce_rto,
5024 		    tp6->tcp6ConnEntryInfo.ce_mss,
5025 		    mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5026 		    ifnamep);
5027 	} else {
5028 		int sq = (int)tp6->tcp6ConnEntryInfo.ce_snxt -
5029 		    (int)tp6->tcp6ConnEntryInfo.ce_suna - 1;
5030 		int rq = (int)tp6->tcp6ConnEntryInfo.ce_rnxt -
5031 		    (int)tp6->tcp6ConnEntryInfo.ce_rack;
5032 
5033 		(void) printf("%-33s %-33s %5u %6d %5u %6d %-11s %s\n",
5034 		    pr_ap6(&tp6->tcp6ConnLocalAddress,
5035 		    tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5036 		    pr_ap6(&tp6->tcp6ConnRemAddress,
5037 		    tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5038 		    tp6->tcp6ConnEntryInfo.ce_swnd,
5039 		    (sq >= 0) ? sq : 0,
5040 		    tp6->tcp6ConnEntryInfo.ce_rwnd,
5041 		    (rq >= 0) ? rq : 0,
5042 		    mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5043 		    ifnamep);
5044 	}
5045 
5046 	print_transport_label(attr);
5047 
5048 	return (B_FALSE);
5049 }
5050 
5051 /* ------------------------------- UDP_REPORT------------------------------- */
5052 
5053 static boolean_t udp_report_item_v4(const mib2_udpEntry_t *ude,
5054     boolean_t first, const mib2_transportMLPEntry_t *attr);
5055 static boolean_t udp_report_item_v6(const mib2_udp6Entry_t *ude6,
5056     boolean_t first, const mib2_transportMLPEntry_t *attr);
5057 
5058 static const char udp_hdr_v4[] =
5059 "   Local Address        Remote Address      State\n"
5060 "-------------------- -------------------- ----------\n";
5061 
5062 static const char udp_hdr_v6[] =
5063 "   Local Address                     Remote Address                 "
5064 "  State      If\n"
5065 "--------------------------------- --------------------------------- "
5066 "---------- -----\n";
5067 
5068 static void
5069 udp_report(const mib_item_t *item)
5070 {
5071 	int			jtemp = 0;
5072 	boolean_t		print_hdr_once_v4 = B_TRUE;
5073 	boolean_t		print_hdr_once_v6 = B_TRUE;
5074 	mib2_udpEntry_t		*ude;
5075 	mib2_udp6Entry_t	*ude6;
5076 	mib2_transportMLPEntry_t **v4_attrs, **v6_attrs;
5077 	mib2_transportMLPEntry_t **v4a, **v6a;
5078 	mib2_transportMLPEntry_t *aptr;
5079 
5080 	if (!protocol_selected(IPPROTO_UDP))
5081 		return;
5082 
5083 	/*
5084 	 * Preparation pass: the kernel returns separate entries for UDP
5085 	 * connection table entries and Multilevel Port attributes.  We loop
5086 	 * through the attributes first and set up an array for each address
5087 	 * family.
5088 	 */
5089 	v4_attrs = family_selected(AF_INET) && RSECflag ?
5090 	    gather_attrs(item, MIB2_UDP, MIB2_UDP_ENTRY, udpEntrySize) : NULL;
5091 	v6_attrs = family_selected(AF_INET6) && RSECflag ?
5092 	    gather_attrs(item, MIB2_UDP6, MIB2_UDP6_ENTRY, udp6EntrySize) :
5093 	    NULL;
5094 
5095 	v4a = v4_attrs;
5096 	v6a = v6_attrs;
5097 	/* 'for' loop 1: */
5098 	for (; item; item = item->next_item) {
5099 		if (Xflag) {
5100 			(void) printf("\n--- Entry %d ---\n", ++jtemp);
5101 			(void) printf("Group = %d, mib_id = %d, "
5102 			    "length = %d, valp = 0x%p\n",
5103 			    item->group, item->mib_id,
5104 			    item->length, item->valp);
5105 		}
5106 		if (!((item->group == MIB2_UDP &&
5107 		    item->mib_id == MIB2_UDP_ENTRY) ||
5108 		    (item->group == MIB2_UDP6 &&
5109 		    item->mib_id == MIB2_UDP6_ENTRY)))
5110 			continue; /* 'for' loop 1 */
5111 
5112 		if (item->group == MIB2_UDP && !family_selected(AF_INET))
5113 			continue; /* 'for' loop 1 */
5114 		else if (item->group == MIB2_UDP6 && !family_selected(AF_INET6))
5115 			continue; /* 'for' loop 1 */
5116 
5117 		/*	xxx.xxx.xxx.xxx,pppp  sss... */
5118 		if (item->group == MIB2_UDP) {
5119 			for (ude = (mib2_udpEntry_t *)item->valp;
5120 			    (char *)ude < (char *)item->valp + item->length;
5121 			    /* LINTED: (note 1) */
5122 			    ude = (mib2_udpEntry_t *)((char *)ude +
5123 			    udpEntrySize)) {
5124 				aptr = v4a == NULL ? NULL : *v4a++;
5125 				print_hdr_once_v4 = udp_report_item_v4(ude,
5126 				    print_hdr_once_v4, aptr);
5127 			}
5128 		} else {
5129 			for (ude6 = (mib2_udp6Entry_t *)item->valp;
5130 			    (char *)ude6 < (char *)item->valp + item->length;
5131 			    /* LINTED: (note 1) */
5132 			    ude6 = (mib2_udp6Entry_t *)((char *)ude6 +
5133 			    udp6EntrySize)) {
5134 				aptr = v6a == NULL ? NULL : *v6a++;
5135 				print_hdr_once_v6 = udp_report_item_v6(ude6,
5136 				    print_hdr_once_v6, aptr);
5137 			}
5138 		}
5139 	} /* 'for' loop 1 ends */
5140 	(void) fflush(stdout);
5141 
5142 	if (v4_attrs != NULL)
5143 		free(v4_attrs);
5144 	if (v6_attrs != NULL)
5145 		free(v6_attrs);
5146 }
5147 
5148 static boolean_t
5149 udp_report_item_v4(const mib2_udpEntry_t *ude, boolean_t first,
5150     const mib2_transportMLPEntry_t *attr)
5151 {
5152 	char	lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5153 			/* hostname + portname */
5154 
5155 	if (!(Aflag || ude->udpEntryInfo.ue_state >= MIB2_UDP_connected))
5156 		return (first); /* Nothing to print */
5157 
5158 	if (first) {
5159 		(void) printf(v4compat ? "\nUDP\n" : "\nUDP: IPv4\n");
5160 		(void) printf(udp_hdr_v4);
5161 		first = B_FALSE;
5162 	}
5163 
5164 	(void) printf("%-20s ",
5165 	    pr_ap(ude->udpLocalAddress, ude->udpLocalPort, "udp",
5166 	    lname, sizeof (lname)));
5167 	(void) printf("%-20s %s\n",
5168 	    ude->udpEntryInfo.ue_state == MIB2_UDP_connected ?
5169 	    pr_ap(ude->udpEntryInfo.ue_RemoteAddress,
5170 	    ude->udpEntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
5171 	    "",
5172 	    miudp_state(ude->udpEntryInfo.ue_state, attr));
5173 
5174 	print_transport_label(attr);
5175 
5176 	return (first);
5177 }
5178 
5179 static boolean_t
5180 udp_report_item_v6(const mib2_udp6Entry_t *ude6, boolean_t first,
5181     const mib2_transportMLPEntry_t *attr)
5182 {
5183 	char	lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5184 			/* hostname + portname */
5185 	char	ifname[LIFNAMSIZ + 1];
5186 	const char *ifnamep;
5187 
5188 	if (!(Aflag || ude6->udp6EntryInfo.ue_state >= MIB2_UDP_connected))
5189 		return (first); /* Nothing to print */
5190 
5191 	if (first) {
5192 		(void) printf("\nUDP: IPv6\n");
5193 		(void) printf(udp_hdr_v6);
5194 		first = B_FALSE;
5195 	}
5196 
5197 	ifnamep = (ude6->udp6IfIndex != 0) ?
5198 	    if_indextoname(ude6->udp6IfIndex, ifname) : NULL;
5199 
5200 	(void) printf("%-33s ",
5201 	    pr_ap6(&ude6->udp6LocalAddress,
5202 	    ude6->udp6LocalPort, "udp", lname, sizeof (lname)));
5203 	(void) printf("%-33s %-10s %s\n",
5204 	    ude6->udp6EntryInfo.ue_state == MIB2_UDP_connected ?
5205 	    pr_ap6(&ude6->udp6EntryInfo.ue_RemoteAddress,
5206 	    ude6->udp6EntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
5207 	    "",
5208 	    miudp_state(ude6->udp6EntryInfo.ue_state, attr),
5209 	    ifnamep == NULL ? "" : ifnamep);
5210 
5211 	print_transport_label(attr);
5212 
5213 	return (first);
5214 }
5215 
5216 /* ------------------------------ SCTP_REPORT------------------------------- */
5217 
5218 static const char sctp_hdr[] =
5219 "\nSCTP:";
5220 static const char sctp_hdr_normal[] =
5221 "        Local Address                   Remote Address          "
5222 "Swind  Send-Q Rwind  Recv-Q StrsI/O  State\n"
5223 "------------------------------- ------------------------------- "
5224 "------ ------ ------ ------ ------- -----------";
5225 
5226 static const char *
5227 nssctp_state(int state, const mib2_transportMLPEntry_t *attr)
5228 {
5229 	static char sctpsbuf[50];
5230 	const char *cp;
5231 
5232 	switch (state) {
5233 	case MIB2_SCTP_closed:
5234 		cp = "CLOSED";
5235 		break;
5236 	case MIB2_SCTP_cookieWait:
5237 		cp = "COOKIE_WAIT";
5238 		break;
5239 	case MIB2_SCTP_cookieEchoed:
5240 		cp = "COOKIE_ECHOED";
5241 		break;
5242 	case MIB2_SCTP_established:
5243 		cp = "ESTABLISHED";
5244 		break;
5245 	case MIB2_SCTP_shutdownPending:
5246 		cp = "SHUTDOWN_PENDING";
5247 		break;
5248 	case MIB2_SCTP_shutdownSent:
5249 		cp = "SHUTDOWN_SENT";
5250 		break;
5251 	case MIB2_SCTP_shutdownReceived:
5252 		cp = "SHUTDOWN_RECEIVED";
5253 		break;
5254 	case MIB2_SCTP_shutdownAckSent:
5255 		cp = "SHUTDOWN_ACK_SENT";
5256 		break;
5257 	case MIB2_SCTP_listen:
5258 		cp = "LISTEN";
5259 		break;
5260 	default:
5261 		(void) snprintf(sctpsbuf, sizeof (sctpsbuf),
5262 		    "UNKNOWN STATE(%d)", state);
5263 		cp = sctpsbuf;
5264 		break;
5265 	}
5266 
5267 	if (RSECflag && attr != NULL && attr->tme_flags != 0) {
5268 		if (cp != sctpsbuf) {
5269 			(void) strlcpy(sctpsbuf, cp, sizeof (sctpsbuf));
5270 			cp = sctpsbuf;
5271 		}
5272 		if (attr->tme_flags & MIB2_TMEF_PRIVATE)
5273 			(void) strlcat(sctpsbuf, " P", sizeof (sctpsbuf));
5274 		if (attr->tme_flags & MIB2_TMEF_SHARED)
5275 			(void) strlcat(sctpsbuf, " S", sizeof (sctpsbuf));
5276 	}
5277 
5278 	return (cp);
5279 }
5280 
5281 static const mib2_sctpConnRemoteEntry_t *
5282 sctp_getnext_rem(const mib_item_t **itemp,
5283     const mib2_sctpConnRemoteEntry_t *current, uint32_t associd)
5284 {
5285 	const mib_item_t *item = *itemp;
5286 	const mib2_sctpConnRemoteEntry_t	*sre;
5287 
5288 	for (; item != NULL; item = item->next_item, current = NULL) {
5289 		if (!(item->group == MIB2_SCTP &&
5290 		    item->mib_id == MIB2_SCTP_CONN_REMOTE)) {
5291 			continue;
5292 		}
5293 
5294 		if (current != NULL) {
5295 			/* LINTED: (note 1) */
5296 			sre = (const mib2_sctpConnRemoteEntry_t *)
5297 			    ((const char *)current + sctpRemoteEntrySize);
5298 		} else {
5299 			sre = item->valp;
5300 		}
5301 		for (; (char *)sre < (char *)item->valp + item->length;
5302 		    /* LINTED: (note 1) */
5303 		    sre = (const mib2_sctpConnRemoteEntry_t *)
5304 		    ((const char *)sre + sctpRemoteEntrySize)) {
5305 			if (sre->sctpAssocId != associd) {
5306 				continue;
5307 			}
5308 			*itemp = item;
5309 			return (sre);
5310 		}
5311 	}
5312 	*itemp = NULL;
5313 	return (NULL);
5314 }
5315 
5316 static const mib2_sctpConnLocalEntry_t *
5317 sctp_getnext_local(const mib_item_t **itemp,
5318     const mib2_sctpConnLocalEntry_t *current, uint32_t associd)
5319 {
5320 	const mib_item_t *item = *itemp;
5321 	const mib2_sctpConnLocalEntry_t	*sle;
5322 
5323 	for (; item != NULL; item = item->next_item, current = NULL) {
5324 		if (!(item->group == MIB2_SCTP &&
5325 		    item->mib_id == MIB2_SCTP_CONN_LOCAL)) {
5326 			continue;
5327 		}
5328 
5329 		if (current != NULL) {
5330 			/* LINTED: (note 1) */
5331 			sle = (const mib2_sctpConnLocalEntry_t *)
5332 			    ((const char *)current + sctpLocalEntrySize);
5333 		} else {
5334 			sle = item->valp;
5335 		}
5336 		for (; (char *)sle < (char *)item->valp + item->length;
5337 		    /* LINTED: (note 1) */
5338 		    sle = (const mib2_sctpConnLocalEntry_t *)
5339 		    ((const char *)sle + sctpLocalEntrySize)) {
5340 			if (sle->sctpAssocId != associd) {
5341 				continue;
5342 			}
5343 			*itemp = item;
5344 			return (sle);
5345 		}
5346 	}
5347 	*itemp = NULL;
5348 	return (NULL);
5349 }
5350 
5351 static void
5352 sctp_pr_addr(int type, char *name, int namelen, const in6_addr_t *addr,
5353     int port)
5354 {
5355 	ipaddr_t	v4addr;
5356 	in6_addr_t	v6addr;
5357 
5358 	/*
5359 	 * Address is either a v4 mapped or v6 addr. If
5360 	 * it's a v4 mapped, convert to v4 before
5361 	 * displaying.
5362 	 */
5363 	switch (type) {
5364 	case MIB2_SCTP_ADDR_V4:
5365 		/* v4 */
5366 		v6addr = *addr;
5367 
5368 		IN6_V4MAPPED_TO_IPADDR(&v6addr, v4addr);
5369 		if (port > 0) {
5370 			(void) pr_ap(v4addr, port, "sctp", name, namelen);
5371 		} else {
5372 			(void) pr_addr(v4addr, name, namelen);
5373 		}
5374 		break;
5375 
5376 	case MIB2_SCTP_ADDR_V6:
5377 		/* v6 */
5378 		if (port > 0) {
5379 			(void) pr_ap6(addr, port, "sctp", name, namelen);
5380 		} else {
5381 			(void) pr_addr6(addr, name, namelen);
5382 		}
5383 		break;
5384 
5385 	default:
5386 		(void) snprintf(name, namelen, "<unknown addr type>");
5387 		break;
5388 	}
5389 }
5390 
5391 static void
5392 sctp_conn_report_item(const mib_item_t *head, const mib2_sctpConnEntry_t *sp,
5393     const mib2_transportMLPEntry_t *attr)
5394 {
5395 	char		lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5396 	char		fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5397 	const mib2_sctpConnRemoteEntry_t	*sre = NULL;
5398 	const mib2_sctpConnLocalEntry_t	*sle = NULL;
5399 	const mib_item_t *local = head;
5400 	const mib_item_t *remote = head;
5401 	uint32_t	id = sp->sctpAssocId;
5402 	boolean_t	printfirst = B_TRUE;
5403 
5404 	sctp_pr_addr(sp->sctpAssocRemPrimAddrType, fname, sizeof (fname),
5405 	    &sp->sctpAssocRemPrimAddr, sp->sctpAssocRemPort);
5406 	sctp_pr_addr(sp->sctpAssocRemPrimAddrType, lname, sizeof (lname),
5407 	    &sp->sctpAssocLocPrimAddr, sp->sctpAssocLocalPort);
5408 
5409 	(void) printf("%-31s %-31s %6u %6d %6u %6d %3d/%-3d %s\n",
5410 	    lname, fname,
5411 	    sp->sctpConnEntryInfo.ce_swnd,
5412 	    sp->sctpConnEntryInfo.ce_sendq,
5413 	    sp->sctpConnEntryInfo.ce_rwnd,
5414 	    sp->sctpConnEntryInfo.ce_recvq,
5415 	    sp->sctpAssocInStreams, sp->sctpAssocOutStreams,
5416 	    nssctp_state(sp->sctpAssocState, attr));
5417 
5418 	print_transport_label(attr);
5419 
5420 	if (!Vflag) {
5421 		return;
5422 	}
5423 
5424 	/* Print remote addresses/local addresses on following lines */
5425 	while ((sre = sctp_getnext_rem(&remote, sre, id)) != NULL) {
5426 		if (!IN6_ARE_ADDR_EQUAL(&sre->sctpAssocRemAddr,
5427 		    &sp->sctpAssocRemPrimAddr)) {
5428 			if (printfirst == B_TRUE) {
5429 				(void) fputs("\t<Remote: ", stdout);
5430 				printfirst = B_FALSE;
5431 			} else {
5432 				(void) fputs(", ", stdout);
5433 			}
5434 			sctp_pr_addr(sre->sctpAssocRemAddrType, fname,
5435 			    sizeof (fname), &sre->sctpAssocRemAddr, -1);
5436 			if (sre->sctpAssocRemAddrActive == MIB2_SCTP_ACTIVE) {
5437 				(void) fputs(fname, stdout);
5438 			} else {
5439 				(void) printf("(%s)", fname);
5440 			}
5441 		}
5442 	}
5443 	if (printfirst == B_FALSE) {
5444 		(void) puts(">");
5445 		printfirst = B_TRUE;
5446 	}
5447 	while ((sle = sctp_getnext_local(&local, sle, id)) != NULL) {
5448 		if (!IN6_ARE_ADDR_EQUAL(&sle->sctpAssocLocalAddr,
5449 		    &sp->sctpAssocLocPrimAddr)) {
5450 			if (printfirst == B_TRUE) {
5451 				(void) fputs("\t<Local: ", stdout);
5452 				printfirst = B_FALSE;
5453 			} else {
5454 				(void) fputs(", ", stdout);
5455 			}
5456 			sctp_pr_addr(sle->sctpAssocLocalAddrType, lname,
5457 			    sizeof (lname), &sle->sctpAssocLocalAddr, -1);
5458 			(void) fputs(lname, stdout);
5459 		}
5460 	}
5461 	if (printfirst == B_FALSE) {
5462 		(void) puts(">");
5463 	}
5464 }
5465 
5466 static void
5467 sctp_report(const mib_item_t *item)
5468 {
5469 	const mib_item_t		*head;
5470 	const mib2_sctpConnEntry_t	*sp;
5471 	boolean_t		first = B_TRUE;
5472 	mib2_transportMLPEntry_t **attrs, **aptr;
5473 	mib2_transportMLPEntry_t *attr;
5474 
5475 	/*
5476 	 * Preparation pass: the kernel returns separate entries for SCTP
5477 	 * connection table entries and Multilevel Port attributes.  We loop
5478 	 * through the attributes first and set up an array for each address
5479 	 * family.
5480 	 */
5481 	attrs = RSECflag ?
5482 	    gather_attrs(item, MIB2_SCTP, MIB2_SCTP_CONN, sctpEntrySize) :
5483 	    NULL;
5484 
5485 	aptr = attrs;
5486 	head = item;
5487 	for (; item != NULL; item = item->next_item) {
5488 
5489 		if (!(item->group == MIB2_SCTP &&
5490 		    item->mib_id == MIB2_SCTP_CONN))
5491 			continue;
5492 
5493 		for (sp = item->valp;
5494 		    (char *)sp < (char *)item->valp + item->length;
5495 		    /* LINTED: (note 1) */
5496 		    sp = (mib2_sctpConnEntry_t *)((char *)sp + sctpEntrySize)) {
5497 			attr = aptr == NULL ? NULL : *aptr++;
5498 			if (Aflag ||
5499 			    sp->sctpAssocState >= MIB2_SCTP_established) {
5500 				if (first == B_TRUE) {
5501 					(void) puts(sctp_hdr);
5502 					(void) puts(sctp_hdr_normal);
5503 					first = B_FALSE;
5504 				}
5505 				sctp_conn_report_item(head, sp, attr);
5506 			}
5507 		}
5508 	}
5509 	if (attrs != NULL)
5510 		free(attrs);
5511 }
5512 
5513 static char *
5514 plural(int n)
5515 {
5516 	return (n != 1 ? "s" : "");
5517 }
5518 
5519 static char *
5520 pluraly(int n)
5521 {
5522 	return (n != 1 ? "ies" : "y");
5523 }
5524 
5525 static char *
5526 plurales(int n)
5527 {
5528 	return (n != 1 ? "es" : "");
5529 }
5530 
5531 static char *
5532 pktscale(int n)
5533 {
5534 	static char buf[6];
5535 	char t;
5536 
5537 	if (n < 1024) {
5538 		t = ' ';
5539 	} else if (n < 1024 * 1024) {
5540 		t = 'k';
5541 		n /= 1024;
5542 	} else if (n < 1024 * 1024 * 1024) {
5543 		t = 'm';
5544 		n /= 1024 * 1024;
5545 	} else {
5546 		t = 'g';
5547 		n /= 1024 * 1024 * 1024;
5548 	}
5549 
5550 	(void) snprintf(buf, sizeof (buf), "%4u%c", n, t);
5551 	return (buf);
5552 }
5553 
5554 /* --------------------- mrt_report (netstat -m) -------------------------- */
5555 
5556 static void
5557 mrt_report(mib_item_t *item)
5558 {
5559 	int		jtemp = 0;
5560 	struct vifctl	*vip;
5561 	vifi_t		vifi;
5562 	struct mfcctl	*mfccp;
5563 	int		numvifs = 0;
5564 	int		nmfc = 0;
5565 	char		abuf[MAXHOSTNAMELEN + 4]; /* Include CIDR /<num>. */
5566 
5567 	if (!(family_selected(AF_INET)))
5568 		return;
5569 
5570 	/* 'for' loop 1: */
5571 	for (; item; item = item->next_item) {
5572 		if (Xflag) {
5573 			(void) printf("\n--- Entry %d ---\n", ++jtemp);
5574 			(void) printf("Group = %d, mib_id = %d, "
5575 			    "length = %d, valp = 0x%p\n",
5576 			    item->group, item->mib_id, item->length,
5577 			    item->valp);
5578 		}
5579 		if (item->group != EXPER_DVMRP)
5580 			continue; /* 'for' loop 1 */
5581 
5582 		switch (item->mib_id) {
5583 
5584 		case EXPER_DVMRP_VIF:
5585 			if (Xflag)
5586 				(void) printf("%u records for ipVifTable:\n",
5587 				    item->length/sizeof (struct vifctl));
5588 			if (item->length/sizeof (struct vifctl) == 0) {
5589 				(void) puts("\nVirtual Interface Table is "
5590 				    "empty");
5591 				break;
5592 			}
5593 
5594 			(void) puts("\nVirtual Interface Table\n"
5595 			    " Vif Threshold Rate_Limit Local-Address"
5596 			    "   Remote-Address     Pkt_in   Pkt_out");
5597 
5598 			/* 'for' loop 2: */
5599 			for (vip = (struct vifctl *)item->valp;
5600 			    (char *)vip < (char *)item->valp + item->length;
5601 			    /* LINTED: (note 1) */
5602 			    vip = (struct vifctl *)((char *)vip +
5603 			    vifctlSize)) {
5604 				if (vip->vifc_lcl_addr.s_addr == 0)
5605 					continue; /* 'for' loop 2 */
5606 				/* numvifs = vip->vifc_vifi; */
5607 
5608 				numvifs++;
5609 				(void) printf("  %2u       %3u       "
5610 				    "%4u %-15.15s",
5611 				    vip->vifc_vifi,
5612 				    vip->vifc_threshold,
5613 				    vip->vifc_rate_limit,
5614 				    pr_addr(vip->vifc_lcl_addr.s_addr,
5615 				    abuf, sizeof (abuf)));
5616 				(void) printf(" %-15.15s  %8u  %8u\n",
5617 				    (vip->vifc_flags & VIFF_TUNNEL) ?
5618 				    pr_addr(vip->vifc_rmt_addr.s_addr,
5619 				    abuf, sizeof (abuf)) : "",
5620 				    vip->vifc_pkt_in,
5621 				    vip->vifc_pkt_out);
5622 			} /* 'for' loop 2 ends */
5623 
5624 			(void) printf("Numvifs: %d\n", numvifs);
5625 			break;
5626 
5627 		case EXPER_DVMRP_MRT:
5628 			if (Xflag)
5629 				(void) printf("%u records for ipMfcTable:\n",
5630 				    item->length/sizeof (struct vifctl));
5631 			if (item->length/sizeof (struct vifctl) == 0) {
5632 				(void) puts("\nMulticast Forwarding Cache is "
5633 				    "empty");
5634 				break;
5635 			}
5636 
5637 			(void) puts("\nMulticast Forwarding Cache\n"
5638 			    "  Origin-Subnet                 Mcastgroup      "
5639 			    "# Pkts  In-Vif  Out-vifs/Forw-ttl");
5640 
5641 			for (mfccp = (struct mfcctl *)item->valp;
5642 			    (char *)mfccp < (char *)item->valp + item->length;
5643 			    /* LINTED: (note 1) */
5644 			    mfccp = (struct mfcctl *)((char *)mfccp +
5645 			    mfcctlSize)) {
5646 
5647 				nmfc++;
5648 				(void) printf("  %-30.15s",
5649 				    pr_addr(mfccp->mfcc_origin.s_addr,
5650 				    abuf, sizeof (abuf)));
5651 				(void) printf("%-15.15s  %6s  %3u    ",
5652 				    pr_net(mfccp->mfcc_mcastgrp.s_addr,
5653 				    mfccp->mfcc_mcastgrp.s_addr,
5654 				    abuf, sizeof (abuf)),
5655 				    pktscale((int)mfccp->mfcc_pkt_cnt),
5656 				    mfccp->mfcc_parent);
5657 
5658 				for (vifi = 0; vifi < MAXVIFS; ++vifi) {
5659 					if (mfccp->mfcc_ttls[vifi]) {
5660 						(void) printf("      %u (%u)",
5661 						    vifi,
5662 						    mfccp->mfcc_ttls[vifi]);
5663 					}
5664 
5665 				}
5666 				(void) putchar('\n');
5667 			}
5668 			(void) printf("\nTotal no. of entries in cache: %d\n",
5669 			    nmfc);
5670 			break;
5671 		}
5672 	} /* 'for' loop 1 ends */
5673 	(void) putchar('\n');
5674 	(void) fflush(stdout);
5675 }
5676 
5677 /*
5678  * Get the stats for the cache named 'name'.  If prefix != 0, then
5679  * interpret the name as a prefix, and sum up stats for all caches
5680  * named 'name*'.
5681  */
5682 static void
5683 kmem_cache_stats(char *title, char *name, int prefix, int64_t *total_bytes)
5684 {
5685 	int len;
5686 	int alloc;
5687 	int64_t total_alloc = 0;
5688 	int alloc_fail, total_alloc_fail = 0;
5689 	int buf_size = 0;
5690 	int buf_avail;
5691 	int buf_total;
5692 	int buf_max, total_buf_max = 0;
5693 	int buf_inuse, total_buf_inuse = 0;
5694 	kstat_t *ksp;
5695 	char buf[256];
5696 
5697 	len = prefix ? strlen(name) : 256;
5698 
5699 	/* 'for' loop 1: */
5700 	for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
5701 
5702 		if (strcmp(ksp->ks_class, "kmem_cache") != 0)
5703 			continue; /* 'for' loop 1 */
5704 
5705 		/*
5706 		 * Hack alert: because of the way streams messages are
5707 		 * allocated, every constructed free dblk has an associated
5708 		 * mblk.  From the allocator's viewpoint those mblks are
5709 		 * allocated (because they haven't been freed), but from
5710 		 * our viewpoint they're actually free (because they're
5711 		 * not currently in use).  To account for this caching
5712 		 * effect we subtract the total constructed free dblks
5713 		 * from the total allocated mblks to derive mblks in use.
5714 		 */
5715 		if (strcmp(name, "streams_mblk") == 0 &&
5716 		    strncmp(ksp->ks_name, "streams_dblk", 12) == 0) {
5717 			(void) safe_kstat_read(kc, ksp, NULL);
5718 			total_buf_inuse -=
5719 			    kstat_named_value(ksp, "buf_constructed");
5720 			continue; /* 'for' loop 1 */
5721 		}
5722 
5723 		if (strncmp(ksp->ks_name, name, len) != 0)
5724 			continue; /* 'for' loop 1 */
5725 
5726 		(void) safe_kstat_read(kc, ksp, NULL);
5727 
5728 		alloc		= kstat_named_value(ksp, "alloc");
5729 		alloc_fail	= kstat_named_value(ksp, "alloc_fail");
5730 		buf_size	= kstat_named_value(ksp, "buf_size");
5731 		buf_avail	= kstat_named_value(ksp, "buf_avail");
5732 		buf_total	= kstat_named_value(ksp, "buf_total");
5733 		buf_max		= kstat_named_value(ksp, "buf_max");
5734 		buf_inuse	= buf_total - buf_avail;
5735 
5736 		if (Vflag && prefix) {
5737 			(void) snprintf(buf, sizeof (buf), "%s%s", title,
5738 			    ksp->ks_name + len);
5739 			(void) printf("    %-18s %6u %9u %11u %11u\n",
5740 			    buf, buf_inuse, buf_max, alloc, alloc_fail);
5741 		}
5742 
5743 		total_alloc		+= alloc;
5744 		total_alloc_fail	+= alloc_fail;
5745 		total_buf_max		+= buf_max;
5746 		total_buf_inuse		+= buf_inuse;
5747 		*total_bytes		+= (int64_t)buf_inuse * buf_size;
5748 	} /* 'for' loop 1 ends */
5749 
5750 	if (buf_size == 0) {
5751 		(void) printf("%-22s [couldn't find statistics for %s]\n",
5752 		    title, name);
5753 		return;
5754 	}
5755 
5756 	if (Vflag && prefix)
5757 		(void) snprintf(buf, sizeof (buf), "%s_total", title);
5758 	else
5759 		(void) snprintf(buf, sizeof (buf), "%s", title);
5760 
5761 	(void) printf("%-22s %6d %9d %11lld %11d\n", buf,
5762 	    total_buf_inuse, total_buf_max, total_alloc, total_alloc_fail);
5763 }
5764 
5765 static void
5766 m_report(void)
5767 {
5768 	int64_t total_bytes = 0;
5769 
5770 	(void) puts("streams allocation:");
5771 	(void) printf("%63s\n", "cumulative  allocation");
5772 	(void) printf("%63s\n",
5773 	    "current   maximum       total    failures");
5774 
5775 	kmem_cache_stats("streams",
5776 	    "stream_head_cache", 0, &total_bytes);
5777 	kmem_cache_stats("queues", "queue_cache", 0, &total_bytes);
5778 	kmem_cache_stats("mblk", "streams_mblk", 0, &total_bytes);
5779 	kmem_cache_stats("dblk", "streams_dblk", 1, &total_bytes);
5780 	kmem_cache_stats("linkblk", "linkinfo_cache", 0, &total_bytes);
5781 	kmem_cache_stats("syncq", "syncq_cache", 0, &total_bytes);
5782 	kmem_cache_stats("qband", "qband_cache", 0, &total_bytes);
5783 
5784 	(void) printf("\n%lld Kbytes allocated for streams data\n",
5785 	    total_bytes / 1024);
5786 
5787 	(void) putchar('\n');
5788 	(void) fflush(stdout);
5789 }
5790 
5791 /* --------------------------------- */
5792 
5793 /*
5794  * Print an IPv4 address. Remove the matching part of the domain name
5795  * from the returned name.
5796  */
5797 static char *
5798 pr_addr(uint_t addr, char *dst, uint_t dstlen)
5799 {
5800 	char			*cp;
5801 	struct hostent		*hp = NULL;
5802 	static char		domain[MAXHOSTNAMELEN + 1];
5803 	static boolean_t	first = B_TRUE;
5804 	int			error_num;
5805 
5806 	if (first) {
5807 		first = B_FALSE;
5808 		if (sysinfo(SI_HOSTNAME, domain, MAXHOSTNAMELEN) != -1 &&
5809 		    (cp = strchr(domain, '.'))) {
5810 			(void) strncpy(domain, cp + 1, sizeof (domain));
5811 		} else
5812 			domain[0] = 0;
5813 	}
5814 	cp = NULL;
5815 	if (!Nflag) {
5816 		ns_lookup_start();
5817 		hp = getipnodebyaddr((char *)&addr, sizeof (uint_t), AF_INET,
5818 		    &error_num);
5819 		ns_lookup_end();
5820 		if (hp) {
5821 			if ((cp = strchr(hp->h_name, '.')) != NULL &&
5822 			    strcasecmp(cp + 1, domain) == 0)
5823 				*cp = 0;
5824 			cp = hp->h_name;
5825 		}
5826 	}
5827 	if (cp != NULL) {
5828 		(void) strncpy(dst, cp, dstlen);
5829 		dst[dstlen - 1] = 0;
5830 	} else {
5831 		(void) inet_ntop(AF_INET, (char *)&addr, dst, dstlen);
5832 	}
5833 	if (hp != NULL)
5834 		freehostent(hp);
5835 	return (dst);
5836 }
5837 
5838 /*
5839  * Print a non-zero IPv4 address.  Print "    --" if the address is zero.
5840  */
5841 static char *
5842 pr_addrnz(ipaddr_t addr, char *dst, uint_t dstlen)
5843 {
5844 	if (addr == INADDR_ANY) {
5845 		(void) strlcpy(dst, "    --", dstlen);
5846 		return (dst);
5847 	}
5848 	return (pr_addr(addr, dst, dstlen));
5849 }
5850 
5851 /*
5852  * Print an IPv6 address. Remove the matching part of the domain name
5853  * from the returned name.
5854  */
5855 static char *
5856 pr_addr6(const struct in6_addr *addr, char *dst, uint_t dstlen)
5857 {
5858 	char			*cp;
5859 	struct hostent		*hp = NULL;
5860 	static char		domain[MAXHOSTNAMELEN + 1];
5861 	static boolean_t	first = B_TRUE;
5862 	int			error_num;
5863 
5864 	if (first) {
5865 		first = B_FALSE;
5866 		if (sysinfo(SI_HOSTNAME, domain, MAXHOSTNAMELEN) != -1 &&
5867 		    (cp = strchr(domain, '.'))) {
5868 			(void) strncpy(domain, cp + 1, sizeof (domain));
5869 		} else
5870 			domain[0] = 0;
5871 	}
5872 	cp = NULL;
5873 	if (!Nflag) {
5874 		ns_lookup_start();
5875 		hp = getipnodebyaddr((char *)addr,
5876 		    sizeof (struct in6_addr), AF_INET6, &error_num);
5877 		ns_lookup_end();
5878 		if (hp) {
5879 			if ((cp = strchr(hp->h_name, '.')) != NULL &&
5880 			    strcasecmp(cp + 1, domain) == 0)
5881 				*cp = 0;
5882 			cp = hp->h_name;
5883 		}
5884 	}
5885 	if (cp != NULL) {
5886 		(void) strncpy(dst, cp, dstlen);
5887 		dst[dstlen - 1] = 0;
5888 	} else {
5889 		(void) inet_ntop(AF_INET6, (void *)addr, dst, dstlen);
5890 	}
5891 	if (hp != NULL)
5892 		freehostent(hp);
5893 	return (dst);
5894 }
5895 
5896 /* For IPv4 masks */
5897 static char *
5898 pr_mask(uint_t addr, char *dst, uint_t dstlen)
5899 {
5900 	uint8_t	*ip_addr = (uint8_t *)&addr;
5901 
5902 	(void) snprintf(dst, dstlen, "%d.%d.%d.%d",
5903 	    ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3]);
5904 	return (dst);
5905 }
5906 
5907 /*
5908  * For ipv6 masks format is : dest/mask
5909  * Does not print /128 to save space in printout. H flag carries this notion.
5910  */
5911 static char *
5912 pr_prefix6(const struct in6_addr *addr, uint_t prefixlen, char *dst,
5913     uint_t dstlen)
5914 {
5915 	char *cp;
5916 
5917 	if (IN6_IS_ADDR_UNSPECIFIED(addr) && prefixlen == 0) {
5918 		(void) strncpy(dst, "default", dstlen);
5919 		dst[dstlen - 1] = 0;
5920 		return (dst);
5921 	}
5922 
5923 	(void) pr_addr6(addr, dst, dstlen);
5924 	if (prefixlen != IPV6_ABITS) {
5925 		/* How much room is left? */
5926 		cp = strchr(dst, '\0');
5927 		if (dst + dstlen > cp) {
5928 			dstlen -= (cp - dst);
5929 			(void) snprintf(cp, dstlen, "/%d", prefixlen);
5930 		}
5931 	}
5932 	return (dst);
5933 }
5934 
5935 /* Print IPv4 address and port */
5936 static char *
5937 pr_ap(uint_t addr, uint_t port, char *proto,
5938     char *dst, uint_t dstlen)
5939 {
5940 	char *cp;
5941 
5942 	if (addr == INADDR_ANY) {
5943 		(void) strncpy(dst, "      *", dstlen);
5944 		dst[dstlen - 1] = 0;
5945 	} else {
5946 		(void) pr_addr(addr, dst, dstlen);
5947 	}
5948 	/* How much room is left? */
5949 	cp = strchr(dst, '\0');
5950 	if (dst + dstlen > cp + 1) {
5951 		*cp++ = '.';
5952 		dstlen -= (cp - dst);
5953 		dstlen--;
5954 		(void) portname(port, proto, cp, dstlen);
5955 	}
5956 	return (dst);
5957 }
5958 
5959 /* Print IPv6 address and port */
5960 static char *
5961 pr_ap6(const in6_addr_t *addr, uint_t port, char *proto,
5962     char *dst, uint_t dstlen)
5963 {
5964 	char *cp;
5965 
5966 	if (IN6_IS_ADDR_UNSPECIFIED(addr)) {
5967 		(void) strncpy(dst, "      *", dstlen);
5968 		dst[dstlen - 1] = 0;
5969 	} else {
5970 		(void) pr_addr6(addr, dst, dstlen);
5971 	}
5972 	/* How much room is left? */
5973 	cp = strchr(dst, '\0');
5974 	if (dst + dstlen + 1 > cp) {
5975 		*cp++ = '.';
5976 		dstlen -= (cp - dst);
5977 		dstlen--;
5978 		(void) portname(port, proto, cp, dstlen);
5979 	}
5980 	return (dst);
5981 }
5982 
5983 /*
5984  * Returns -2 to indicate a discontiguous mask.  Otherwise returns between
5985  * 0 and 32.
5986  */
5987 static int
5988 v4_cidr_len(uint_t mask)
5989 {
5990 	int rc = 0;
5991 	int i;
5992 
5993 	for (i = 0; i < 32; i++) {
5994 		if (mask & 0x1)
5995 			rc++;
5996 		else if (rc > 0)
5997 			return (-2);	/* Discontiguous IPv4 netmask. */
5998 
5999 		mask >>= 1;
6000 	}
6001 
6002 	return (rc);
6003 }
6004 
6005 static void
6006 append_v4_cidr_len(char *dst, uint_t dstlen, int prefixlen)
6007 {
6008 	char *prefixptr;
6009 
6010 	/* 4 bytes leaves room for '/' 'N' 'N' '\0' */
6011 	if (strlen(dst) <= dstlen - 4) {
6012 		prefixptr = dst + strlen(dst);
6013 	} else {
6014 		/*
6015 		 * Cut off last 3 chars of very-long DNS name.  All callers
6016 		 * should give us enough room, but name services COULD give us
6017 		 * a way-too-big name (see above).
6018 		 */
6019 		prefixptr = dst + strlen(dst) - 3;
6020 	}
6021 	/* At this point "prefixptr" is guaranteed to point to 4 bytes. */
6022 
6023 	if (prefixlen >= 0) {
6024 		if (prefixlen > 32)	/* Shouldn't happen, but... */
6025 			prefixlen = 32;
6026 		(void) snprintf(prefixptr, 4, "/%d", prefixlen);
6027 	} else if (prefixlen == -2) {
6028 		/* "/NM" == Noncontiguous Mask. */
6029 		(void) strcat(prefixptr, "/NM");
6030 	}
6031 	/* Else print nothing extra. */
6032 }
6033 
6034 /*
6035  * Return the name of the network whose address is given. The address is
6036  * assumed to be that of a net or subnet, not a host.
6037  */
6038 static char *
6039 pr_net(uint_t addr, uint_t mask, char *dst, uint_t dstlen)
6040 {
6041 	char		*cp = NULL;
6042 	struct netent	*np = NULL;
6043 	struct hostent	*hp = NULL;
6044 	uint_t		net;
6045 	int		subnetshift;
6046 	int		error_num;
6047 	int		prefixlen = -1;	/* -1 == Don't print prefix! */
6048 					/* -2 == Noncontiguous mask... */
6049 
6050 	if (addr == INADDR_ANY && mask == INADDR_ANY) {
6051 		(void) strlcpy(dst, "default", dstlen);
6052 		return (dst);
6053 	}
6054 
6055 	if (CIDRflag)
6056 		prefixlen = v4_cidr_len(ntohl(mask));
6057 
6058 	if (!Nflag && addr) {
6059 		if (mask == 0) {
6060 			if (IN_CLASSA(addr)) {
6061 				mask = (uint_t)IN_CLASSA_NET;
6062 				subnetshift = 8;
6063 			} else if (IN_CLASSB(addr)) {
6064 				mask = (uint_t)IN_CLASSB_NET;
6065 				subnetshift = 8;
6066 			} else {
6067 				mask = (uint_t)IN_CLASSC_NET;
6068 				subnetshift = 4;
6069 			}
6070 			/*
6071 			 * If there are more bits than the standard mask
6072 			 * would suggest, subnets must be in use. Guess at
6073 			 * the subnet mask, assuming reasonable width subnet
6074 			 * fields.
6075 			 */
6076 			while (addr & ~mask)
6077 				/* compiler doesn't sign extend! */
6078 				mask = (mask | ((int)mask >> subnetshift));
6079 			if (CIDRflag)
6080 				prefixlen = v4_cidr_len(mask);
6081 		}
6082 		net = addr & mask;
6083 		while ((mask & 1) == 0)
6084 			mask >>= 1, net >>= 1;
6085 		ns_lookup_start();
6086 		np = getnetbyaddr(net, AF_INET);
6087 		ns_lookup_end();
6088 		if (np && np->n_net == net)
6089 			cp = np->n_name;
6090 		else {
6091 			/*
6092 			 * Look for subnets in hosts map.
6093 			 */
6094 			ns_lookup_start();
6095 			hp = getipnodebyaddr((char *)&addr, sizeof (uint_t),
6096 			    AF_INET, &error_num);
6097 			ns_lookup_end();
6098 			if (hp)
6099 				cp = hp->h_name;
6100 		}
6101 	}
6102 	if (cp != NULL) {
6103 		(void) strlcpy(dst, cp, dstlen);
6104 	} else {
6105 		(void) inet_ntop(AF_INET, (char *)&addr, dst, dstlen);
6106 	}
6107 
6108 	append_v4_cidr_len(dst, dstlen, prefixlen);
6109 
6110 	if (hp != NULL)
6111 		freehostent(hp);
6112 	return (dst);
6113 }
6114 
6115 /*
6116  * Return the name of the network whose address is given.
6117  * The address is assumed to be a host address.
6118  */
6119 static char *
6120 pr_netaddr(uint_t addr, uint_t mask, char *dst, uint_t dstlen)
6121 {
6122 	char		*cp = NULL;
6123 	struct netent	*np = NULL;
6124 	struct hostent	*hp = NULL;
6125 	uint_t		net;
6126 	uint_t		netshifted;
6127 	int		subnetshift;
6128 	struct in_addr in;
6129 	int		error_num;
6130 	uint_t		nbo_addr = addr;	/* network byte order */
6131 	int		prefixlen = -1;	/* -1 == Don't print prefix! */
6132 					/* -2 == Noncontiguous mask... */
6133 
6134 	addr = ntohl(addr);
6135 	mask = ntohl(mask);
6136 	if (addr == INADDR_ANY && mask == INADDR_ANY) {
6137 		(void) strlcpy(dst, "default", dstlen);
6138 		return (dst);
6139 	}
6140 
6141 	if (CIDRflag)
6142 		prefixlen = v4_cidr_len(mask);
6143 
6144 	/* Figure out network portion of address (with host portion = 0) */
6145 	if (addr) {
6146 		/* Try figuring out mask if unknown (all 0s). */
6147 		if (mask == 0) {
6148 			if (IN_CLASSA(addr)) {
6149 				mask = (uint_t)IN_CLASSA_NET;
6150 				subnetshift = 8;
6151 			} else if (IN_CLASSB(addr)) {
6152 				mask = (uint_t)IN_CLASSB_NET;
6153 				subnetshift = 8;
6154 			} else {
6155 				mask = (uint_t)IN_CLASSC_NET;
6156 				subnetshift = 4;
6157 			}
6158 			/*
6159 			 * If there are more bits than the standard mask
6160 			 * would suggest, subnets must be in use. Guess at
6161 			 * the subnet mask, assuming reasonable width subnet
6162 			 * fields.
6163 			 */
6164 			while (addr & ~mask)
6165 				/* compiler doesn't sign extend! */
6166 				mask = (mask | ((int)mask >> subnetshift));
6167 			if (CIDRflag)
6168 				prefixlen = v4_cidr_len(mask);
6169 		}
6170 		net = netshifted = addr & mask;
6171 		while ((mask & 1) == 0)
6172 			mask >>= 1, netshifted >>= 1;
6173 	}
6174 	else
6175 		net = netshifted = 0;
6176 
6177 	/* Try looking up name unless -n was specified. */
6178 	if (!Nflag) {
6179 		ns_lookup_start();
6180 		np = getnetbyaddr(netshifted, AF_INET);
6181 		ns_lookup_end();
6182 		if (np && np->n_net == netshifted)
6183 			cp = np->n_name;
6184 		else {
6185 			/*
6186 			 * Look for subnets in hosts map.
6187 			 */
6188 			ns_lookup_start();
6189 			hp = getipnodebyaddr((char *)&nbo_addr, sizeof (uint_t),
6190 			    AF_INET, &error_num);
6191 			ns_lookup_end();
6192 			if (hp)
6193 				cp = hp->h_name;
6194 		}
6195 
6196 		if (cp != NULL) {
6197 			(void) strlcpy(dst, cp, dstlen);
6198 			append_v4_cidr_len(dst, dstlen, prefixlen);
6199 			if (hp != NULL)
6200 				freehostent(hp);
6201 			return (dst);
6202 		}
6203 		/*
6204 		 * No name found for net: fallthru and return in decimal
6205 		 * dot notation.
6206 		 */
6207 	}
6208 
6209 	in.s_addr = htonl(net);
6210 	(void) inet_ntop(AF_INET, (char *)&in, dst, dstlen);
6211 	append_v4_cidr_len(dst, dstlen, prefixlen);
6212 	if (hp != NULL)
6213 		freehostent(hp);
6214 	return (dst);
6215 }
6216 
6217 /*
6218  * Return the filter mode as a string:
6219  *	1 => "INCLUDE"
6220  *	2 => "EXCLUDE"
6221  *	otherwise "<unknown>"
6222  */
6223 static char *
6224 fmodestr(uint_t fmode)
6225 {
6226 	switch (fmode) {
6227 	case 1:
6228 		return ("INCLUDE");
6229 	case 2:
6230 		return ("EXCLUDE");
6231 	default:
6232 		return ("<unknown>");
6233 	}
6234 }
6235 
6236 #define	MAX_STRING_SIZE	256
6237 
6238 static const char *
6239 pr_secattr(const sec_attr_list_t *attrs)
6240 {
6241 	int i;
6242 	char buf[MAX_STRING_SIZE + 1], *cp;
6243 	static char *sbuf;
6244 	static size_t sbuf_len;
6245 	struct rtsa_s rtsa;
6246 	const sec_attr_list_t *aptr;
6247 
6248 	if (!RSECflag || attrs == NULL)
6249 		return ("");
6250 
6251 	for (aptr = attrs, i = 1; aptr != NULL; aptr = aptr->sal_next)
6252 		i += MAX_STRING_SIZE;
6253 	if (i > sbuf_len) {
6254 		cp = realloc(sbuf, i);
6255 		if (cp == NULL) {
6256 			perror("realloc security attribute buffer");
6257 			return ("");
6258 		}
6259 		sbuf_len = i;
6260 		sbuf = cp;
6261 	}
6262 
6263 	cp = sbuf;
6264 	while (attrs != NULL) {
6265 		const mib2_ipAttributeEntry_t *iae = attrs->sal_attr;
6266 
6267 		/* note: effectively hard-coded in rtsa_keyword */
6268 		rtsa.rtsa_mask = RTSA_CIPSO | RTSA_SLRANGE | RTSA_DOI;
6269 		rtsa.rtsa_slrange = iae->iae_slrange;
6270 		rtsa.rtsa_doi = iae->iae_doi;
6271 
6272 		(void) snprintf(cp, MAX_STRING_SIZE,
6273 		    "<%s>%s ", rtsa_to_str(&rtsa, buf, sizeof (buf)),
6274 		    attrs->sal_next == NULL ? "" : ",");
6275 		cp += strlen(cp);
6276 		attrs = attrs->sal_next;
6277 	}
6278 	*cp = '\0';
6279 
6280 	return (sbuf);
6281 }
6282 
6283 /*
6284  * Pretty print a port number. If the Nflag was
6285  * specified, use numbers instead of names.
6286  */
6287 static char *
6288 portname(uint_t port, char *proto, char *dst, uint_t dstlen)
6289 {
6290 	struct servent *sp = NULL;
6291 
6292 	if (!Nflag && port) {
6293 		ns_lookup_start();
6294 		sp = getservbyport(htons(port), proto);
6295 		ns_lookup_end();
6296 	}
6297 	if (sp || port == 0)
6298 		(void) snprintf(dst, dstlen, "%.*s", MAXHOSTNAMELEN,
6299 		    sp ? sp->s_name : "*");
6300 	else
6301 		(void) snprintf(dst, dstlen, "%d", port);
6302 	dst[dstlen - 1] = 0;
6303 	return (dst);
6304 }
6305 
6306 /*PRINTFLIKE2*/
6307 void
6308 fail(int do_perror, char *message, ...)
6309 {
6310 	va_list args;
6311 
6312 	va_start(args, message);
6313 	(void) fputs("netstat: ", stderr);
6314 	(void) vfprintf(stderr, message, args);
6315 	va_end(args);
6316 	if (do_perror)
6317 		(void) fprintf(stderr, ": %s", strerror(errno));
6318 	(void) fputc('\n', stderr);
6319 	exit(2);
6320 }
6321 
6322 /*
6323  * Return value of named statistic for given kstat_named kstat;
6324  * return 0LL if named statistic is not in list (use "ll" as a
6325  * type qualifier when printing 64-bit int's with printf() )
6326  */
6327 static uint64_t
6328 kstat_named_value(kstat_t *ksp, char *name)
6329 {
6330 	kstat_named_t *knp;
6331 	uint64_t value;
6332 
6333 	if (ksp == NULL)
6334 		return (0LL);
6335 
6336 	knp = kstat_data_lookup(ksp, name);
6337 	if (knp == NULL)
6338 		return (0LL);
6339 
6340 	switch (knp->data_type) {
6341 	case KSTAT_DATA_INT32:
6342 	case KSTAT_DATA_UINT32:
6343 		value = (uint64_t)(knp->value.ui32);
6344 		break;
6345 	case KSTAT_DATA_INT64:
6346 	case KSTAT_DATA_UINT64:
6347 		value = knp->value.ui64;
6348 		break;
6349 	default:
6350 		value = 0LL;
6351 		break;
6352 	}
6353 
6354 	return (value);
6355 }
6356 
6357 kid_t
6358 safe_kstat_read(kstat_ctl_t *kc, kstat_t *ksp, void *data)
6359 {
6360 	kid_t kstat_chain_id = kstat_read(kc, ksp, data);
6361 
6362 	if (kstat_chain_id == -1)
6363 		fail(1, "kstat_read(%p, '%s') failed", (void *)kc,
6364 		    ksp->ks_name);
6365 	return (kstat_chain_id);
6366 }
6367 
6368 /*
6369  * Parse a list of IRE flag characters into a bit field.
6370  */
6371 static uint_t
6372 flag_bits(const char *arg)
6373 {
6374 	const char *cp;
6375 	uint_t val;
6376 
6377 	if (*arg == '\0')
6378 		fatal(1, "missing flag list\n");
6379 
6380 	val = 0;
6381 	while (*arg != '\0') {
6382 		if ((cp = strchr(flag_list, *arg)) == NULL)
6383 			fatal(1, "%c: illegal flag\n", *arg);
6384 		val |= 1 << (cp - flag_list);
6385 		arg++;
6386 	}
6387 	return (val);
6388 }
6389 
6390 /*
6391  * Handle -f argument.  Validate input format, sort by keyword, and
6392  * save off digested results.
6393  */
6394 static void
6395 process_filter(char *arg)
6396 {
6397 	int idx;
6398 	int klen = 0;
6399 	char *cp, *cp2;
6400 	int val;
6401 	filter_t *newf;
6402 	struct hostent *hp;
6403 	int error_num;
6404 	uint8_t *ucp;
6405 	int maxv;
6406 
6407 	/* Look up the keyword first */
6408 	if (strchr(arg, ':') == NULL) {
6409 		idx = FK_AF;
6410 	} else {
6411 		for (idx = 0; idx < NFILTERKEYS; idx++) {
6412 			klen = strlen(filter_keys[idx]);
6413 			if (strncmp(filter_keys[idx], arg, klen) == 0 &&
6414 			    arg[klen] == ':')
6415 				break;
6416 		}
6417 		if (idx >= NFILTERKEYS)
6418 			fatal(1, "%s: unknown filter keyword\n", arg);
6419 
6420 		/* Advance past keyword and separator. */
6421 		arg += klen + 1;
6422 	}
6423 
6424 	if ((newf = malloc(sizeof (*newf))) == NULL) {
6425 		perror("filter");
6426 		exit(1);
6427 	}
6428 	switch (idx) {
6429 	case FK_AF:
6430 		if (strcmp(arg, "inet") == 0) {
6431 			newf->u.f_family = AF_INET;
6432 		} else if (strcmp(arg, "inet6") == 0) {
6433 			newf->u.f_family = AF_INET6;
6434 		} else if (strcmp(arg, "unix") == 0) {
6435 			newf->u.f_family = AF_UNIX;
6436 		} else {
6437 			newf->u.f_family = strtol(arg, &cp, 0);
6438 			if (arg == cp || *cp != '\0')
6439 				fatal(1, "%s: unknown address family.\n", arg);
6440 		}
6441 		break;
6442 
6443 	case FK_OUTIF:
6444 		if (strcmp(arg, "none") == 0) {
6445 			newf->u.f_ifname = NULL;
6446 			break;
6447 		}
6448 		if (strcmp(arg, "any") == 0) {
6449 			newf->u.f_ifname = "";
6450 			break;
6451 		}
6452 		val = strtol(arg, &cp, 0);
6453 		if (val <= 0 || arg == cp || cp[0] != '\0') {
6454 			if ((val = if_nametoindex(arg)) == 0) {
6455 				perror(arg);
6456 				exit(1);
6457 			}
6458 		}
6459 		newf->u.f_ifname = arg;
6460 		break;
6461 
6462 	case FK_DST:
6463 		V4MASK_TO_V6(IP_HOST_MASK, newf->u.a.f_mask);
6464 		if (strcmp(arg, "any") == 0) {
6465 			/* Special semantics; any address *but* zero */
6466 			newf->u.a.f_address = NULL;
6467 			(void) memset(&newf->u.a.f_mask, 0,
6468 			    sizeof (newf->u.a.f_mask));
6469 			break;
6470 		}
6471 		if (strcmp(arg, "none") == 0) {
6472 			newf->u.a.f_address = NULL;
6473 			break;
6474 		}
6475 		if ((cp = strrchr(arg, '/')) != NULL)
6476 			*cp++ = '\0';
6477 		hp = getipnodebyname(arg, AF_INET6, AI_V4MAPPED|AI_ALL,
6478 		    &error_num);
6479 		if (hp == NULL)
6480 			fatal(1, "%s: invalid or unknown host address\n", arg);
6481 		newf->u.a.f_address = hp;
6482 		if (cp == NULL) {
6483 			V4MASK_TO_V6(IP_HOST_MASK, newf->u.a.f_mask);
6484 		} else {
6485 			val = strtol(cp, &cp2, 0);
6486 			if (cp != cp2 && cp2[0] == '\0') {
6487 				/*
6488 				 * If decode as "/n" works, then translate
6489 				 * into a mask.
6490 				 */
6491 				if (hp->h_addr_list[0] != NULL &&
6492 				    /* LINTED: (note 1) */
6493 				    IN6_IS_ADDR_V4MAPPED((in6_addr_t *)
6494 				    hp->h_addr_list[0])) {
6495 					maxv = IP_ABITS;
6496 				} else {
6497 					maxv = IPV6_ABITS;
6498 				}
6499 				if (val < 0 || val >= maxv)
6500 					fatal(1, "%d: not in range 0 to %d\n",
6501 					    val, maxv - 1);
6502 				if (maxv == IP_ABITS)
6503 					val += IPV6_ABITS - IP_ABITS;
6504 				ucp = newf->u.a.f_mask.s6_addr;
6505 				while (val >= 8)
6506 					*ucp++ = 0xff, val -= 8;
6507 				*ucp++ = (0xff << (8 - val)) & 0xff;
6508 				while (ucp < newf->u.a.f_mask.s6_addr +
6509 				    sizeof (newf->u.a.f_mask.s6_addr))
6510 					*ucp++ = 0;
6511 				/* Otherwise, try as numeric address */
6512 			} else if (inet_pton(AF_INET6,
6513 			    cp, &newf->u.a.f_mask) <= 0) {
6514 				fatal(1, "%s: illegal mask format\n", cp);
6515 			}
6516 		}
6517 		break;
6518 
6519 	case FK_FLAGS:
6520 		if (*arg == '+') {
6521 			newf->u.f.f_flagset = flag_bits(arg + 1);
6522 			newf->u.f.f_flagclear = 0;
6523 		} else if (*arg == '-') {
6524 			newf->u.f.f_flagset = 0;
6525 			newf->u.f.f_flagclear = flag_bits(arg + 1);
6526 		} else {
6527 			newf->u.f.f_flagset = flag_bits(arg);
6528 			newf->u.f.f_flagclear = ~newf->u.f.f_flagset;
6529 		}
6530 		break;
6531 
6532 	default:
6533 		assert(0);
6534 	}
6535 	newf->f_next = filters[idx];
6536 	filters[idx] = newf;
6537 }
6538 
6539 /* Determine if user wants this address family printed. */
6540 static boolean_t
6541 family_selected(int family)
6542 {
6543 	const filter_t *fp;
6544 
6545 	if (v4compat && family == AF_INET6)
6546 		return (B_FALSE);
6547 	if ((fp = filters[FK_AF]) == NULL)
6548 		return (B_TRUE);
6549 	while (fp != NULL) {
6550 		if (fp->u.f_family == family)
6551 			return (B_TRUE);
6552 		fp = fp->f_next;
6553 	}
6554 	return (B_FALSE);
6555 }
6556 
6557 /*
6558  * Convert the interface index to a string using the buffer `ifname', which
6559  * must be at least LIFNAMSIZ bytes.  We first try to map it to name.  If that
6560  * fails (e.g., because we're inside a zone and it does not have access to
6561  * interface for the index in question), just return "if#<num>".
6562  */
6563 static char *
6564 ifindex2str(uint_t ifindex, char *ifname)
6565 {
6566 	if (if_indextoname(ifindex, ifname) == NULL)
6567 		(void) snprintf(ifname, LIFNAMSIZ, "if#%d", ifindex);
6568 
6569 	return (ifname);
6570 }
6571 
6572 /*
6573  * print the usage line
6574  */
6575 static void
6576 usage(char *cmdname)
6577 {
6578 	(void) fprintf(stderr, "usage: %s [-anv] [-f address_family] "
6579 	    "[-T d|u]\n", cmdname);
6580 	(void) fprintf(stderr, "       %s [-n] [-f address_family] "
6581 	    "[-P protocol] [-T d|u] [-g | -p | -s [interval [count]]]\n",
6582 	    cmdname);
6583 	(void) fprintf(stderr, "       %s -m [-v] [-T d|u] "
6584 	    "[interval [count]]\n", cmdname);
6585 	(void) fprintf(stderr, "       %s -i [-I interface] [-an] "
6586 	    "[-f address_family] [-T d|u] [interval [count]]\n", cmdname);
6587 	(void) fprintf(stderr, "       %s -r [-anv] "
6588 	    "[-f address_family|filter] [-T d|u]\n", cmdname);
6589 	(void) fprintf(stderr, "       %s -M [-ns] [-f address_family] "
6590 	    "[-T d|u]\n", cmdname);
6591 	(void) fprintf(stderr, "       %s -D [-I interface] "
6592 	    "[-f address_family] [-T d|u]\n", cmdname);
6593 	exit(EXIT_FAILURE);
6594 }
6595 
6596 /*
6597  * fatal: print error message to stderr and
6598  * call exit(errcode)
6599  */
6600 /*PRINTFLIKE2*/
6601 static void
6602 fatal(int errcode, char *format, ...)
6603 {
6604 	va_list argp;
6605 
6606 	if (format == NULL)
6607 		return;
6608 
6609 	va_start(argp, format);
6610 	(void) vfprintf(stderr, format, argp);
6611 	va_end(argp);
6612 
6613 	exit(errcode);
6614 }
6615