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