1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright (c) 1990  Mentat Inc.
24  * netstat.c 2.2, last change 9/9/91
25  * MROUTING Revision 3.5
26  * Copyright 2018, Joyent, Inc.
27  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
28  * Copyright 2021 Racktop Systems, Inc.
29  */
30 
31 /*
32  * simple netstat based on snmp/mib-2 interface to the TCP/IP stack
33  *
34  * TODO:
35  *	Add ability to request subsets from kernel (with level = MIB2_IP;
36  *	name = 0 meaning everything for compatibility)
37  */
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <stdarg.h>
42 #include <unistd.h>
43 #include <strings.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <ctype.h>
47 #include <kstat.h>
48 #include <assert.h>
49 #include <locale.h>
50 #include <synch.h>
51 #include <thread.h>
52 #include <pwd.h>
53 #include <limits.h>
54 #include <sys/ccompile.h>
55 
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <sys/stream.h>
59 #include <stropts.h>
60 #include <sys/strstat.h>
61 #include <sys/tihdr.h>
62 #include <procfs.h>
63 #include <dirent.h>
64 
65 #include <sys/socket.h>
66 #include <sys/socketvar.h>
67 #include <sys/sockio.h>
68 #include <netinet/in.h>
69 #include <net/if.h>
70 #include <net/route.h>
71 
72 #include <inet/mib2.h>
73 #include <inet/ip.h>
74 #include <inet/arp.h>
75 #include <inet/tcp.h>
76 #include <netinet/igmp_var.h>
77 #include <netinet/ip_mroute.h>
78 
79 #include <arpa/inet.h>
80 #include <netdb.h>
81 #include <fcntl.h>
82 #include <sys/systeminfo.h>
83 #include <arpa/inet.h>
84 
85 #include <netinet/dhcp.h>
86 #include <dhcpagent_ipc.h>
87 #include <dhcpagent_util.h>
88 #include <compat.h>
89 #include <sys/mkdev.h>
90 
91 #include <libtsnet.h>
92 #include <tsol/label.h>
93 
94 #include <libproc.h>
95 
96 #include "statcommon.h"
97 
98 #define	STR_EXPAND	4
99 
100 #define	V4MASK_TO_V6(v4, v6)	((v6)._S6_un._S6_u32[0] = 0xfffffffful, \
101 				(v6)._S6_un._S6_u32[1] = 0xfffffffful, \
102 				(v6)._S6_un._S6_u32[2] = 0xfffffffful, \
103 				(v6)._S6_un._S6_u32[3] = (v4))
104 
105 #define	IN6_IS_V4MASK(v6)	((v6)._S6_un._S6_u32[0] == 0xfffffffful && \
106 				(v6)._S6_un._S6_u32[1] == 0xfffffffful && \
107 				(v6)._S6_un._S6_u32[2] == 0xfffffffful)
108 
109 /*
110  * This is used as a cushion in the buffer allocation directed by SIOCGLIFNUM.
111  * Because there's no locking between SIOCGLIFNUM and SIOCGLIFCONF, it's
112  * possible for an administrator to plumb new interfaces between those two
113  * calls, resulting in the failure of the latter.  This addition makes that
114  * less likely.
115  */
116 #define	LIFN_GUARD_VALUE	10
117 
118 typedef struct mib_item_s {
119 	struct mib_item_s	*next_item;
120 	int			group;
121 	int			mib_id;
122 	int			length;
123 	void			*valp;
124 } mib_item_t;
125 
126 struct	ifstat {
127 	uint64_t	ipackets;
128 	uint64_t	ierrors;
129 	uint64_t	opackets;
130 	uint64_t	oerrors;
131 	uint64_t	collisions;
132 };
133 
134 struct iflist {
135 	struct iflist	*next_if;
136 	char		ifname[LIFNAMSIZ];
137 	struct ifstat	tot;
138 };
139 
140 static void fatal(int, char *, ...) __NORETURN;
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, mib_item_t *item2);
148 static void		mib_item_destroy(mib_item_t **item);
149 
150 static boolean_t	octetstrmatch(const Octet_t *a, const Octet_t *b);
151 static char		*octetstr(const Octet_t *op, int code,
152 			    char *dst, uint_t dstlen);
153 static char		*pr_addr(uint_t addr, char *dst, uint_t dstlen);
154 static char		*pr_addrnz(ipaddr_t addr, char *dst, uint_t dstlen);
155 static char		*pr_addr6(const in6_addr_t *addr,
156 			    char *dst, uint_t dstlen);
157 static char		*pr_mask(uint_t addr, char *dst, uint_t dstlen);
158 static char		*pr_prefix6(const struct in6_addr *addr,
159 			    uint_t prefixlen, char *dst, uint_t dstlen);
160 static char		*pr_ap(uint_t addr, uint_t port,
161 			    char *proto, char *dst, uint_t dstlen);
162 static char		*pr_ap6(const in6_addr_t *addr, uint_t port,
163 			    char *proto, char *dst, uint_t dstlen);
164 static char		*pr_net(uint_t addr, uint_t mask,
165 			    char *dst, uint_t dstlen);
166 static char		*pr_netaddr(uint_t addr, uint_t mask,
167 			    char *dst, uint_t dstlen);
168 static char		*fmodestr(uint_t fmode);
169 static char		*portname(uint_t port, char *proto,
170 			    char *dst, uint_t dstlen);
171 
172 static const char	*mitcp_state(int code,
173 			    const mib2_transportMLPEntry_t *attr);
174 static const char	*miudp_state(int code,
175 			    const mib2_transportMLPEntry_t *attr);
176 
177 static void		stat_report(mib_item_t *item);
178 static void		mrt_stat_report(mib_item_t *item);
179 static void		arp_report(mib_item_t *item);
180 static void		ndp_report(mib_item_t *item);
181 static void		mrt_report(mib_item_t *item);
182 static void		if_stat_total(struct ifstat *oldstats,
183 			    struct ifstat *newstats, struct ifstat *sumstats);
184 static void		if_report(mib_item_t *item, char *ifname,
185 			    int Iflag_only, boolean_t once_only);
186 static void		if_report_ip4(mib2_ipAddrEntry_t *ap,
187 			    char ifname[], char logintname[],
188 			    struct ifstat *statptr, boolean_t ksp_not_null);
189 static void		if_report_ip6(mib2_ipv6AddrEntry_t *ap6,
190 			    char ifname[], char logintname[],
191 			    struct ifstat *statptr, boolean_t ksp_not_null);
192 static void		ire_report(const mib_item_t *item);
193 static void		tcp_report(const mib_item_t *item);
194 static void		udp_report(const mib_item_t *item);
195 static void		uds_report(kstat_ctl_t *);
196 static void		group_report(mib_item_t *item);
197 static void		dce_report(mib_item_t *item);
198 static void		print_ip_stats(mib2_ip_t *ip);
199 static void		print_icmp_stats(mib2_icmp_t *icmp);
200 static void		print_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6);
201 static void		print_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6);
202 static void		print_sctp_stats(mib2_sctp_t *tcp);
203 static void		print_tcp_stats(mib2_tcp_t *tcp);
204 static void		print_udp_stats(mib2_udp_t *udp);
205 static void		print_rawip_stats(mib2_rawip_t *rawip);
206 static void		print_igmp_stats(struct igmpstat *igps);
207 static void		print_mrt_stats(struct mrtstat *mrts);
208 static void		sctp_report(const mib_item_t *item);
209 static void		sum_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6,
210 			    mib2_ipv6IfStatsEntry_t *sum6);
211 static void		sum_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6,
212 			    mib2_ipv6IfIcmpEntry_t *sum6);
213 static void		m_report(void);
214 static void		dhcp_report(char *);
215 
216 static	uint64_t	kstat_named_value(kstat_t *, char *);
217 static	kid_t		safe_kstat_read(kstat_ctl_t *, kstat_t *, void *);
218 static int		isnum(char *);
219 static char		*plural(int n);
220 static char		*pluraly(int n);
221 static char		*plurales(int n);
222 static void		process_filter(char *arg);
223 static char		*ifindex2str(uint_t, char *);
224 static boolean_t	family_selected(int family);
225 
226 static void		usage(char *);
227 static char		*get_username(uid_t);
228 
229 static void		process_hash_build(void);
230 static void		process_hash_free(void);
231 
232 #define	PLURAL(n) plural((int)n)
233 #define	PLURALY(n) pluraly((int)n)
234 #define	PLURALES(n) plurales((int)n)
235 #define	IFLAGMOD(flg, val1, val2)	if (flg == val1) flg = val2
236 #define	MDIFF(diff, elem2, elem1, member)	(diff)->member = \
237 	(elem2)->member - (elem1)->member
238 
239 static	boolean_t	Aflag = B_FALSE;	/* All sockets/ifs/rtng-tbls */
240 static	boolean_t	CIDRflag = B_FALSE;	/* CIDR for IPv4 -i/-r addrs */
241 static	boolean_t	Dflag = B_FALSE;	/* DCE info */
242 static	boolean_t	Iflag = B_FALSE;	/* IP Traffic Interfaces */
243 static	boolean_t	Mflag = B_FALSE;	/* STREAMS Memory Statistics */
244 static	boolean_t	Nflag = B_FALSE;	/* Numeric Network Addresses */
245 static	boolean_t	Rflag = B_FALSE;	/* Routing Tables */
246 static	boolean_t	RSECflag = B_FALSE;	/* Security attributes */
247 static	boolean_t	Sflag = B_FALSE;	/* Per-protocol Statistics */
248 static	boolean_t	Vflag = B_FALSE;	/* Verbose */
249 static	boolean_t	Uflag = B_FALSE;	/* Show PID and UID info. */
250 static	boolean_t	Pflag = B_FALSE;	/* Net to Media Tables */
251 static	boolean_t	Gflag = B_FALSE;	/* Multicast group membership */
252 static	boolean_t	MMflag = B_FALSE;	/* Multicast routing table */
253 static	boolean_t	DHCPflag = B_FALSE;	/* DHCP statistics */
254 static	boolean_t	Xflag = B_FALSE;	/* Debug Info */
255 
256 static	int	v4compat = 0;	/* Compatible printing format for status */
257 
258 static int	proto = IPPROTO_MAX;	/* all protocols */
259 kstat_ctl_t	*kc = NULL;
260 
261 /*
262  * Name service timeout detection constants.
263  */
264 static mutex_t ns_lock = ERRORCHECKMUTEX;
265 static boolean_t ns_active = B_FALSE;	/* Is a lookup ongoing? */
266 static hrtime_t ns_starttime;		/* Time the lookup started */
267 static int ns_sleeptime = 2;		/* Time in seconds between checks */
268 static int ns_warntime = 2;		/* Time in seconds before warning */
269 
270 /*
271  * Sizes of data structures extracted from the base mib.
272  * This allows the size of the tables entries to grow while preserving
273  * binary compatibility.
274  */
275 static int ipAddrEntrySize;
276 static int ipRouteEntrySize;
277 static int ipNetToMediaEntrySize;
278 static int ipMemberEntrySize;
279 static int ipGroupSourceEntrySize;
280 static int ipRouteAttributeSize;
281 static int vifctlSize;
282 static int mfcctlSize;
283 
284 static int ipv6IfStatsEntrySize;
285 static int ipv6IfIcmpEntrySize;
286 static int ipv6AddrEntrySize;
287 static int ipv6RouteEntrySize;
288 static int ipv6NetToMediaEntrySize;
289 static int ipv6MemberEntrySize;
290 static int ipv6GroupSourceEntrySize;
291 
292 static int ipDestEntrySize;
293 
294 static int transportMLPSize;
295 static int tcpConnEntrySize;
296 static int tcp6ConnEntrySize;
297 static int udpEntrySize;
298 static int udp6EntrySize;
299 static int sctpEntrySize;
300 static int sctpLocalEntrySize;
301 static int sctpRemoteEntrySize;
302 
303 #define	protocol_selected(p)	(proto == IPPROTO_MAX || proto == (p))
304 
305 /* Machinery used for -f (filter) option */
306 enum { FK_AF = 0, FK_OUTIF, FK_DST, FK_FLAGS, NFILTERKEYS };
307 
308 static const char *filter_keys[NFILTERKEYS] = {
309 	"af", "outif", "dst", "flags"
310 };
311 
312 static m_label_t *zone_security_label = NULL;
313 
314 /* Flags on routes */
315 #define	FLF_A		0x00000001
316 #define	FLF_b		0x00000002
317 #define	FLF_D		0x00000004
318 #define	FLF_G		0x00000008
319 #define	FLF_H		0x00000010
320 #define	FLF_L		0x00000020
321 #define	FLF_U		0x00000040
322 #define	FLF_M		0x00000080
323 #define	FLF_S		0x00000100
324 #define	FLF_C		0x00000200	/* IRE_IF_CLONE */
325 #define	FLF_I		0x00000400	/* RTF_INDIRECT */
326 #define	FLF_R		0x00000800	/* RTF_REJECT */
327 #define	FLF_B		0x00001000	/* RTF_BLACKHOLE */
328 #define	FLF_Z		0x00100000	/* RTF_ZONE */
329 
330 static const char flag_list[] = "AbDGHLUMSCIRBZ";
331 
332 typedef struct filter_rule filter_t;
333 
334 struct filter_rule {
335 	filter_t *f_next;
336 	union {
337 		int f_family;
338 		const char *f_ifname;
339 		struct {
340 			struct hostent *f_address;
341 			in6_addr_t f_mask;
342 		} a;
343 		struct {
344 			uint_t f_flagset;
345 			uint_t f_flagclear;
346 		} f;
347 	} u;
348 };
349 
350 /*
351  * The user-specified filters are linked into lists separated by
352  * keyword (type of filter).  Thus, the matching algorithm is:
353  *	For each non-empty filter list
354  *		If no filters in the list match
355  *			then stop here; route doesn't match
356  *	If loop above completes, then route does match and will be
357  *	displayed.
358  */
359 static filter_t *filters[NFILTERKEYS];
360 
361 static uint_t timestamp_fmt = NODATE;
362 
363 #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
364 #define	TEXT_DOMAIN "SYS_TEST"		/* Use this only if it isn't */
365 #endif
366 
367 static void
ns_lookup_start(void)368 ns_lookup_start(void)
369 {
370 	mutex_enter(&ns_lock);
371 	ns_active = B_TRUE;
372 	ns_starttime = gethrtime();
373 	mutex_exit(&ns_lock);
374 }
375 
376 static void
ns_lookup_end(void)377 ns_lookup_end(void)
378 {
379 	mutex_enter(&ns_lock);
380 	ns_active = B_FALSE;
381 	mutex_exit(&ns_lock);
382 }
383 
384 /*
385  * When name services are not functioning, this program appears to hang to the
386  * user. To try and give the user a chance of figuring out that this might be
387  * the case, we end up warning them and suggest that they may want to use the -n
388  * flag.
389  */
390 /* ARGSUSED */
391 static void *
ns_warning_thr(void * unsued)392 ns_warning_thr(void *unsued)
393 {
394 	for (;;) {
395 		hrtime_t now;
396 
397 		(void) sleep(ns_sleeptime);
398 		now = gethrtime();
399 		mutex_enter(&ns_lock);
400 		if (ns_active && now - ns_starttime >= ns_warntime * NANOSEC) {
401 			(void) fprintf(stderr, "warning: data "
402 			    "available, but name service lookups are "
403 			    "taking a while. Use the -n option to "
404 			    "disable name service lookups.\n");
405 			mutex_exit(&ns_lock);
406 			return (NULL);
407 		}
408 		mutex_exit(&ns_lock);
409 	}
410 
411 	return (NULL);
412 }
413 
414 int
main(int argc,char ** argv)415 main(int argc, char **argv)
416 {
417 	char		*name;
418 	mib_item_t	*item = NULL;
419 	mib_item_t	*previtem = NULL;
420 	int		sd = -1;
421 	char	*ifname = NULL;
422 	int	interval = 0;	/* Single time by default */
423 	int	count = -1;	/* Forever */
424 	int	c;
425 	int	d;
426 	/*
427 	 * Possible values of 'Iflag_only':
428 	 * -1, no feature-flags;
429 	 *  0, IFlag and other feature-flags enabled
430 	 *  1, IFlag is the only feature-flag enabled
431 	 * : trinary variable, modified using IFLAGMOD()
432 	 */
433 	int Iflag_only = -1;
434 	boolean_t once_only = B_FALSE; /* '-i' with count > 1 */
435 	extern char	*optarg;
436 	extern int	optind;
437 	char *default_ip_str = NULL;
438 
439 	name = argv[0];
440 
441 	v4compat = get_compat_flag(&default_ip_str);
442 	if (v4compat == DEFAULT_PROT_BAD_VALUE)
443 		fatal(2, "%s: %s: Bad value for %s in %s\n", name,
444 		    default_ip_str, DEFAULT_IP, INET_DEFAULT_FILE);
445 	free(default_ip_str);
446 
447 	(void) setlocale(LC_ALL, "");
448 	(void) textdomain(TEXT_DOMAIN);
449 
450 	while ((c = getopt(argc, argv, "acdimnrspMguvxf:P:I:DRT:")) != -1) {
451 		switch ((char)c) {
452 		case 'a':		/* all connections */
453 			Aflag = B_TRUE;
454 			break;
455 
456 		case 'c':
457 			CIDRflag = B_TRUE;
458 			break;
459 
460 		case 'd':		/* DCE info */
461 			Dflag = B_TRUE;
462 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
463 			break;
464 
465 		case 'i':		/* interface (ill/ipif report) */
466 			Iflag = B_TRUE;
467 			IFLAGMOD(Iflag_only, -1, 1); /* '-i' exists */
468 			break;
469 
470 		case 'm':		/* streams msg report */
471 			Mflag = B_TRUE;
472 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
473 			break;
474 
475 		case 'n':		/* numeric format */
476 			Nflag = B_TRUE;
477 			break;
478 
479 		case 'r':		/* route tables */
480 			Rflag = B_TRUE;
481 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
482 			break;
483 
484 		case 'R':		/* security attributes */
485 			RSECflag = B_TRUE;
486 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
487 			break;
488 
489 		case 's':		/* per-protocol statistics */
490 			Sflag = B_TRUE;
491 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
492 			break;
493 
494 		case 'p':		/* arp/ndp table */
495 			Pflag = B_TRUE;
496 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
497 			break;
498 
499 		case 'M':		/* multicast routing tables */
500 			MMflag = B_TRUE;
501 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
502 			break;
503 
504 		case 'g':		/* multicast group membership */
505 			Gflag = B_TRUE;
506 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
507 			break;
508 
509 		case 'v':		/* verbose output format */
510 			Vflag = B_TRUE;
511 			IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
512 			break;
513 
514 		case 'u':		/* show pid and uid information */
515 			Uflag = B_TRUE;
516 			break;
517 
518 		case 'x':		/* turn on debugging */
519 			Xflag = B_TRUE;
520 			break;
521 
522 		case 'f':
523 			process_filter(optarg);
524 			break;
525 
526 		case 'P':
527 			if (strcmp(optarg, "ip") == 0) {
528 				proto = IPPROTO_IP;
529 			} else if (strcmp(optarg, "ipv6") == 0 ||
530 			    strcmp(optarg, "ip6") == 0) {
531 				v4compat = 0;	/* Overridden */
532 				proto = IPPROTO_IPV6;
533 			} else if (strcmp(optarg, "icmp") == 0) {
534 				proto = IPPROTO_ICMP;
535 			} else if (strcmp(optarg, "icmpv6") == 0 ||
536 			    strcmp(optarg, "icmp6") == 0) {
537 				v4compat = 0;	/* Overridden */
538 				proto = IPPROTO_ICMPV6;
539 			} else if (strcmp(optarg, "igmp") == 0) {
540 				proto = IPPROTO_IGMP;
541 			} else if (strcmp(optarg, "udp") == 0) {
542 				proto = IPPROTO_UDP;
543 			} else if (strcmp(optarg, "tcp") == 0) {
544 				proto = IPPROTO_TCP;
545 			} else if (strcmp(optarg, "sctp") == 0) {
546 				proto = IPPROTO_SCTP;
547 			} else if (strcmp(optarg, "raw") == 0 ||
548 			    strcmp(optarg, "rawip") == 0) {
549 				proto = IPPROTO_RAW;
550 			} else {
551 				fatal(1, "%s: unknown protocol.\n", optarg);
552 			}
553 			break;
554 
555 		case 'I':
556 			ifname = optarg;
557 			Iflag = B_TRUE;
558 			IFLAGMOD(Iflag_only, -1, 1); /* see macro def'n */
559 			break;
560 
561 		case 'D':
562 			DHCPflag = B_TRUE;
563 			Iflag_only = 0;
564 			break;
565 
566 		case 'T':
567 			if (optarg) {
568 				if (*optarg == 'u')
569 					timestamp_fmt = UDATE;
570 				else if (*optarg == 'd')
571 					timestamp_fmt = DDATE;
572 				else
573 					usage(name);
574 			} else {
575 				usage(name);
576 			}
577 			break;
578 
579 		case '?':
580 		default:
581 			usage(name);
582 		}
583 	}
584 
585 	/*
586 	 * Make sure -R option is set only on a labeled system.
587 	 */
588 	if (RSECflag && !is_system_labeled()) {
589 		(void) fprintf(stderr, "-R set but labeling is not enabled\n");
590 		usage(name);
591 	}
592 
593 	/*
594 	 * Handle other arguments: find interval, count; the
595 	 * flags that accept 'interval' and 'count' are OR'd
596 	 * in the outermost 'if'; more flags may be added as
597 	 * required
598 	 */
599 	if (Iflag || Sflag || Mflag) {
600 		for (d = optind; d < argc; d++) {
601 			if (isnum(argv[d])) {
602 				interval = atoi(argv[d]);
603 				if (d + 1 < argc &&
604 				    isnum(argv[d + 1])) {
605 					count = atoi(argv[d + 1]);
606 					optind++;
607 				}
608 				optind++;
609 				if (interval == 0 || count == 0)
610 					usage(name);
611 				break;
612 			}
613 		}
614 	}
615 	if (optind < argc) {
616 		if (Iflag && isnum(argv[optind])) {
617 			count = atoi(argv[optind]);
618 			if (count == 0)
619 				usage(name);
620 			optind++;
621 		}
622 	}
623 	if (optind < argc) {
624 		(void) fprintf(stderr, "%s: extra arguments\n", name);
625 		usage(name);
626 	}
627 	if (interval)
628 		setbuf(stdout, NULL);
629 
630 	/*
631 	 * Start up the thread to check for name services warnings.
632 	 */
633 	if (thr_create(NULL, 0, ns_warning_thr, NULL,
634 	    THR_DETACHED | THR_DAEMON, NULL) != 0) {
635 		fatal(1, "%s: failed to create name services "
636 		    "thread: %s\n", name, strerror(errno));
637 	}
638 
639 	if (DHCPflag) {
640 		dhcp_report(Iflag ? ifname : NULL);
641 		exit(0);
642 	}
643 
644 	if (Uflag)
645 		process_hash_build();
646 
647 	/*
648 	 * Get this process's security label if the -R switch is set.
649 	 * We use this label as the current zone's security label.
650 	 */
651 	if (RSECflag) {
652 		zone_security_label = m_label_alloc(MAC_LABEL);
653 		if (zone_security_label == NULL)
654 			fatal(errno, "m_label_alloc() failed");
655 		if (getplabel(zone_security_label) < 0)
656 			fatal(errno, "getplabel() failed");
657 	}
658 
659 	/* Get data structures: priming before iteration */
660 	if (family_selected(AF_INET) || family_selected(AF_INET6)) {
661 		sd = mibopen();
662 		if (sd == -1)
663 			fatal(1, "can't open mib stream\n");
664 		if ((item = mibget(sd)) == NULL) {
665 			(void) close(sd);
666 			fatal(1, "mibget() failed\n");
667 		}
668 		/* Extract constant sizes - need do once only */
669 		mib_get_constants(item);
670 	}
671 	if ((kc = kstat_open()) == NULL) {
672 		mibfree(item);
673 		(void) close(sd);
674 		fail(1, "kstat_open(): can't open /dev/kstat");
675 	}
676 
677 	if (interval <= 0) {
678 		count = 1;
679 		once_only = B_TRUE;
680 	}
681 	for (;;) {
682 		mib_item_t *curritem = NULL; /* only for -[M]s */
683 
684 		if (timestamp_fmt != NODATE)
685 			print_timestamp(timestamp_fmt);
686 
687 		/* netstat: AF_INET[6] behaviour */
688 		if (family_selected(AF_INET) || family_selected(AF_INET6)) {
689 			if (Sflag) {
690 				curritem = mib_item_diff(previtem, item);
691 				if (curritem == NULL)
692 					fatal(1, "can't process mib data, "
693 					    "out of memory\n");
694 				mib_item_destroy(&previtem);
695 			}
696 
697 			if (!(Dflag || Iflag || Rflag || Sflag || Mflag ||
698 			    MMflag || Pflag || Gflag || DHCPflag)) {
699 				if (protocol_selected(IPPROTO_UDP))
700 					udp_report(item);
701 				if (protocol_selected(IPPROTO_TCP))
702 					tcp_report(item);
703 				if (protocol_selected(IPPROTO_SCTP))
704 					sctp_report(item);
705 			}
706 			if (Iflag)
707 				if_report(item, ifname, Iflag_only, once_only);
708 			if (Mflag)
709 				m_report();
710 			if (Rflag)
711 				ire_report(item);
712 			if (Sflag && MMflag) {
713 				mrt_stat_report(curritem);
714 			} else {
715 				if (Sflag)
716 					stat_report(curritem);
717 				if (MMflag)
718 					mrt_report(item);
719 			}
720 			if (Gflag)
721 				group_report(item);
722 			if (Pflag) {
723 				if (family_selected(AF_INET))
724 					arp_report(item);
725 				if (family_selected(AF_INET6))
726 					ndp_report(item);
727 			}
728 			if (Dflag)
729 				dce_report(item);
730 			mib_item_destroy(&curritem);
731 		}
732 
733 		/* netstat: AF_UNIX behaviour */
734 		if (family_selected(AF_UNIX) &&
735 		    (!(Dflag || Iflag || Rflag || Sflag || Mflag ||
736 		    MMflag || Pflag || Gflag)))
737 			uds_report(kc);
738 		(void) kstat_close(kc);
739 
740 		/* iteration handling code */
741 		if (count > 0 && --count == 0)
742 			break;
743 		(void) sleep(interval);
744 
745 		/* re-populating of data structures */
746 		if (family_selected(AF_INET) || family_selected(AF_INET6)) {
747 			if (Sflag) {
748 				/* previtem is a cut-down list */
749 				previtem = mib_item_dup(item);
750 				if (previtem == NULL)
751 					fatal(1, "can't process mib data, "
752 					    "out of memory\n");
753 			}
754 			mibfree(item);
755 			(void) close(sd);
756 			if ((sd = mibopen()) == -1)
757 				fatal(1, "can't open mib stream anymore\n");
758 			if ((item = mibget(sd)) == NULL) {
759 				(void) close(sd);
760 				fatal(1, "mibget() failed\n");
761 			}
762 		}
763 		if ((kc = kstat_open()) == NULL)
764 			fail(1, "kstat_open(): can't open /dev/kstat");
765 
766 	}
767 	mibfree(item);
768 	(void) close(sd);
769 	if (zone_security_label != NULL)
770 		m_label_free(zone_security_label);
771 
772 	if (Uflag)
773 		process_hash_free();
774 
775 	return (0);
776 }
777 
778 static int
isnum(char * p)779 isnum(char *p)
780 {
781 	int	len;
782 	int	i;
783 
784 	len = strlen(p);
785 	for (i = 0; i < len; i++)
786 		if (!isdigit(p[i]))
787 			return (0);
788 	return (1);
789 }
790 
791 /*
792  * ------------------------------ Process Hash -----------------------------
793  *
794  * When passed the -u option, netstat presents additional information against
795  * each socket showing the associated process ID(s), user(s) and command(s).
796  *
797  * The kernel provides some additional information for each socket, namely:
798  *   - inode;
799  *   - address family;
800  *   - socket type;
801  *   - major number;
802  *   - flags.
803  *
804  * Netstat must correlate this information against processes running on the
805  * system and the files which they have open.
806  *
807  * It does this by traversing /proc and checking each process' open files,
808  * looking for BSD sockets or file descriptors relating to TLI/XTI sockets.
809  * When it finds one, it retrieves information and records it in the
810  * 'process_table' hash table with the entry hashed by its inode.
811  *
812  * For a BSD socket, libproc is used to grab the process and retrieve
813  * further information. This is not necessary for TLI/XTI sockets since the
814  * information can be derived directly via stat().
815  *
816  * Note that each socket can be associated with more than one process.
817  */
818 
819 /*
820  * The size of the hash table for recording sockets found under /proc.
821  * This should be a prime number. The value below was chosen after testing
822  * on a busy web server to reduce the number of hash table collisions to
823  * fewer than five per slot.
824  */
825 #define	PROC_HASH_SIZE		2003
826 /* Maximum length of a username - anything larger will be truncated */
827 #define	PROC_USERNAME_SIZE	128
828 /* Maximum length of the string representation of a process ID */
829 #define	PROC_PID_SIZE		15
830 
831 #define	PROC_HASH(k) ((k) % PROC_HASH_SIZE)
832 
833 typedef struct proc_fdinfo {
834 	uint64_t ph_inode;
835 	uint64_t ph_fd;
836 	mode_t ph_mode;
837 	major_t ph_major;
838 	int ph_family;
839 	int ph_type;
840 
841 	char ph_fname[PRFNSZ];
842 	char ph_psargs[PRARGSZ];
843 	char ph_username[PROC_USERNAME_SIZE];
844 	pid_t ph_pid;
845 	char ph_pidstr[PROC_PID_SIZE];
846 
847 	struct proc_fdinfo *ph_next; /* Next (for collisions) */
848 	struct proc_fdinfo *ph_next_proc; /* Next process with this inode */
849 } proc_fdinfo_t;
850 
851 static proc_fdinfo_t *process_table[PROC_HASH_SIZE];
852 
853 static proc_fdinfo_t unknown_proc = {
854 	.ph_pid = 0,
855 	.ph_pidstr = "",
856 	.ph_username = "",
857 	.ph_fname = "",
858 	.ph_psargs = "",
859 	.ph_next_proc = NULL
860 };
861 
862 /*
863  * Gets username given uid. It doesn't return NULL.
864  */
865 static char *
get_username(uid_t u)866 get_username(uid_t u)
867 {
868 	static uid_t saved_uid = UID_MAX;
869 	static char saved_username[PROC_USERNAME_SIZE];
870 	struct passwd *pw = NULL;
871 
872 	if (u == UID_MAX)
873 		return ("<unknown>");
874 
875 	if (u == saved_uid && saved_username[0] != '\0')
876 		return (saved_username);
877 
878 	setpwent();
879 
880 	if ((pw = getpwuid(u)) != NULL) {
881 		(void) strlcpy(saved_username, pw->pw_name,
882 		    sizeof (saved_username));
883 	} else {
884 		(void) snprintf(saved_username, sizeof (saved_username),
885 		    "(%u)", u);
886 	}
887 
888 	saved_uid = u;
889 	return (saved_username);
890 }
891 
892 static proc_fdinfo_t *
process_hash_find(const mib2_socketInfoEntry_t * sie,int type,int family)893 process_hash_find(const mib2_socketInfoEntry_t *sie, int type, int family)
894 {
895 	proc_fdinfo_t *ph;
896 	uint_t idx = PROC_HASH(sie->sie_inode);
897 
898 	for (ph = process_table[idx]; ph != NULL; ph = ph->ph_next) {
899 		if (ph->ph_inode != sie->sie_inode)
900 			continue;
901 		if ((sie->sie_flags & MIB2_SOCKINFO_STREAM)) {
902 			/* TLI/XTI socket */
903 			if (S_ISCHR(ph->ph_mode) &&
904 			    major(sie->sie_dev) == ph->ph_major) {
905 				return (ph);
906 			}
907 		} else {
908 			if (S_ISSOCK(ph->ph_mode) && ph->ph_type == type &&
909 			    ph->ph_family == family) {
910 				return (ph);
911 			}
912 		}
913 	}
914 
915 	return (NULL);
916 }
917 
918 static proc_fdinfo_t *
process_hash_get(const mib2_socketInfoEntry_t * sie,int type,int family)919 process_hash_get(const mib2_socketInfoEntry_t *sie, int type, int family)
920 {
921 	proc_fdinfo_t *ph;
922 
923 	if (sie != NULL && sie->sie_inode > 0 &&
924 	    (ph = process_hash_find(sie, type, family)) != NULL) {
925 		return (ph);
926 	}
927 
928 	return (&unknown_proc);
929 }
930 
931 static void
process_hash_insert(proc_fdinfo_t * ph)932 process_hash_insert(proc_fdinfo_t *ph)
933 {
934 	uint_t idx = PROC_HASH(ph->ph_inode);
935 	proc_fdinfo_t *slotp;
936 
937 	mib2_socketInfoEntry_t sie = {
938 		.sie_inode = ph->ph_inode,
939 		.sie_dev = makedev(ph->ph_major, 0),
940 		.sie_flags = S_ISCHR(ph->ph_mode) ? MIB2_SOCKINFO_STREAM : 0
941 	};
942 
943 	slotp = process_hash_find(&sie, ph->ph_type, ph->ph_family);
944 
945 	if (slotp == NULL) {
946 		ph->ph_next = process_table[idx];
947 		process_table[idx] = ph;
948 	} else {
949 		ph->ph_next_proc = slotp->ph_next_proc;
950 		slotp->ph_next_proc = ph;
951 	}
952 }
953 
954 static void
process_hash_dump(void)955 process_hash_dump(void)
956 {
957 	unsigned int i;
958 
959 	(void) printf("--- Process hash table\n");
960 	for (i = 0; i < PROC_HASH_SIZE; i++) {
961 		proc_fdinfo_t *ph;
962 
963 		if (process_table[i] == NULL)
964 			continue;
965 
966 		(void) printf("Slot %d\n", i);
967 
968 		for (ph = process_table[i]; ph != NULL; ph = ph->ph_next) {
969 			proc_fdinfo_t *ph2;
970 
971 			(void) printf("    -> Inode %" PRIu64 "\n",
972 			    ph->ph_inode);
973 
974 			for (ph2 = ph; ph2 != NULL; ph2 = ph2->ph_next_proc) {
975 				(void) printf("        -> "
976 				    "/proc/%ld/fd/%" PRIu64 " %s - "
977 				    "fname %s - "
978 				    "psargs %s - "
979 				    "major %" PRIx32 " - "
980 				    "type/fam %d/%d\n",
981 				    ph2->ph_pid, ph2->ph_fd,
982 				    S_ISCHR(ph2->ph_mode) ? "CHR" : "SOCK",
983 				    ph2->ph_fname, ph2->ph_psargs,
984 				    ph2->ph_major,
985 				    ph2->ph_type, ph2->ph_family);
986 			}
987 		}
988 	}
989 }
990 
991 static int
process_hash_iterfd(const prfdinfo_t * pr,void * psinfop)992 process_hash_iterfd(const prfdinfo_t *pr, void *psinfop)
993 {
994 	psinfo_t *psinfo = psinfop;
995 	proc_fdinfo_t *ph;
996 
997 	/*
998 	 * We are interested both in sockets and in descriptors linked to
999 	 * network STREAMS character devices.
1000 	 */
1001 	if (S_ISCHR(pr->pr_mode)) {
1002 		/*
1003 		 * There's no elegant way to determine if a character device
1004 		 * supports TLI, so just check a hardcoded list of known TLI
1005 		 * devices.
1006 		 */
1007 		const char *tlidevs[] = {
1008 		    "tcp", "tcp6", "udp", "udp6", NULL
1009 		};
1010 		boolean_t istli = B_FALSE;
1011 		const char *path;
1012 		char *dev;
1013 		int i;
1014 
1015 		path = proc_fdinfo_misc(pr, PR_PATHNAME, NULL);
1016 		if (path == NULL)
1017 			return (0);
1018 
1019 		/* global zone: /devices paths */
1020 		dev = strrchr(path, ':');
1021 		/* also check the /dev path for zones */
1022 		if (dev == NULL)
1023 			dev = strrchr(path, '/');
1024 		if (dev == NULL)
1025 			return (0);
1026 		dev++; /* skip past the `:' or '/' */
1027 
1028 		for (i = 0; tlidevs[i] != NULL; i++) {
1029 			if (strcmp(dev, tlidevs[i]) == 0) {
1030 				istli = B_TRUE;
1031 				break;
1032 			}
1033 		}
1034 		if (!istli)
1035 			return (0);
1036 	} else if (!S_ISSOCK(pr->pr_mode)) {
1037 		return (0);
1038 	}
1039 
1040 	if ((ph = calloc(1, sizeof (proc_fdinfo_t))) == NULL)
1041 		fatal(1, "out of memory\n");
1042 
1043 	ph->ph_pid = psinfo->pr_pid;
1044 	if (ph->ph_pid > 0)
1045 		(void) snprintf(ph->ph_pidstr, PROC_PID_SIZE, "%" PRIu64,
1046 		    ph->ph_pid);
1047 	ph->ph_inode = pr->pr_ino;
1048 	ph->ph_fd = pr->pr_fd;
1049 	ph->ph_major = pr->pr_rmajor;
1050 	ph->ph_mode = pr->pr_mode;
1051 	(void) strlcpy(ph->ph_fname, psinfo->pr_fname, sizeof (ph->ph_fname));
1052 	(void) strlcpy(ph->ph_psargs, psinfo->pr_psargs,
1053 	    sizeof (ph->ph_psargs));
1054 	(void) strlcpy(ph->ph_username, get_username(psinfo->pr_uid),
1055 	    sizeof (ph->ph_username));
1056 
1057 	if (S_ISSOCK(pr->pr_mode)) {
1058 		const struct sockaddr *sa;
1059 		const int *type;
1060 
1061 		/* Determine the socket type */
1062 		type = proc_fdinfo_misc(pr, PR_SOCKOPT_TYPE, NULL);
1063 		if (type != NULL)
1064 			ph->ph_type = *type;
1065 
1066 		/* Determine the protocol family */
1067 		sa = proc_fdinfo_misc(pr, PR_SOCKETNAME, NULL);
1068 		if (sa != NULL)
1069 			ph->ph_family = sa->sa_family;
1070 	}
1071 
1072 	process_hash_insert(ph);
1073 
1074 	return (0);
1075 }
1076 
1077 static int
process_hash_iterproc(psinfo_t * psinfo,lwpsinfo_t * lwp __unused,void * arg __unused)1078 process_hash_iterproc(psinfo_t *psinfo, lwpsinfo_t *lwp __unused,
1079     void *arg __unused)
1080 {
1081 	static pid_t me = -1;
1082 
1083 	if (me == -1)
1084 		me = getpid();
1085 
1086 	if (psinfo->pr_pid == me)
1087 		return (0);
1088 
1089 	/*
1090 	 * We do not use libproc's Pfdinfo_iter() here as it requires
1091 	 * grabbing the process.
1092 	 */
1093 	return (proc_fdwalk(psinfo->pr_pid, process_hash_iterfd, psinfo));
1094 }
1095 
1096 static void
process_hash_build(void)1097 process_hash_build(void)
1098 {
1099 	(void) proc_walk(process_hash_iterproc, NULL, PR_WALK_PROC);
1100 
1101 	if (Xflag)
1102 		process_hash_dump();
1103 }
1104 
1105 static void
process_hash_free(void)1106 process_hash_free(void)
1107 {
1108 	unsigned int i;
1109 
1110 	for (i = 0; i < PROC_HASH_SIZE; i++) {
1111 		proc_fdinfo_t *ph, *ph_next;
1112 
1113 		for (ph = process_table[i]; ph != NULL; ph = ph_next) {
1114 			ph_next = ph->ph_next;
1115 			free(ph);
1116 		}
1117 		process_table[i] = NULL;
1118 	}
1119 }
1120 
1121 /* --------------------------------- MIBGET -------------------------------- */
1122 
1123 static mib_item_t *
mibget(int sd)1124 mibget(int sd)
1125 {
1126 	/*
1127 	 * buf is an automatic for this function, so the
1128 	 * compiler has complete control over its alignment;
1129 	 * it is assumed this alignment is satisfactory for
1130 	 * it to be casted to certain other struct pointers
1131 	 * here, such as struct T_optmgmt_ack * .
1132 	 */
1133 	uintptr_t		buf[512 / sizeof (uintptr_t)];
1134 	int			flags;
1135 	int			i, j, getcode;
1136 	struct strbuf		ctlbuf, databuf;
1137 	struct T_optmgmt_req	*tor = (struct T_optmgmt_req *)buf;
1138 	struct T_optmgmt_ack	*toa = (struct T_optmgmt_ack *)buf;
1139 	struct T_error_ack	*tea = (struct T_error_ack *)buf;
1140 	struct opthdr		*req;
1141 	mib_item_t		*first_item = NULL;
1142 	mib_item_t		*last_item  = NULL;
1143 	mib_item_t		*temp;
1144 
1145 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
1146 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
1147 	tor->OPT_length = sizeof (struct opthdr);
1148 	tor->MGMT_flags = T_CURRENT;
1149 
1150 	/*
1151 	 * Note: we use the special level value below so that IP will return
1152 	 * us information concerning IRE_MARK_TESTHIDDEN routes.
1153 	 */
1154 	req = (struct opthdr *)&tor[1];
1155 	req->level = EXPER_IP_AND_ALL_IRES;
1156 	req->name  = 0;
1157 	req->len   = 1;
1158 
1159 	ctlbuf.buf = (char *)buf;
1160 	ctlbuf.len = tor->OPT_length + tor->OPT_offset;
1161 	flags = 0;
1162 	if (putmsg(sd, &ctlbuf, (struct strbuf *)0, flags) == -1) {
1163 		perror("mibget: putmsg(ctl) failed");
1164 		goto error_exit;
1165 	}
1166 
1167 	/*
1168 	 * Each reply consists of a ctl part for one fixed structure
1169 	 * or table, as defined in mib2.h.  The format is a T_OPTMGMT_ACK,
1170 	 * containing an opthdr structure.  level/name identify the entry,
1171 	 * len is the size of the data part of the message.
1172 	 */
1173 	req = (struct opthdr *)&toa[1];
1174 	ctlbuf.maxlen = sizeof (buf);
1175 	j = 1;
1176 	for (;;) {
1177 		flags = 0;
1178 		getcode = getmsg(sd, &ctlbuf, (struct strbuf *)0, &flags);
1179 		if (getcode == -1) {
1180 			perror("mibget getmsg(ctl) failed");
1181 			if (Xflag) {
1182 				(void) fputs("#   level   name    len\n",
1183 				    stderr);
1184 				i = 0;
1185 				for (last_item = first_item; last_item;
1186 				    last_item = last_item->next_item)
1187 					(void) printf("%d  %4d   %5d   %d\n",
1188 					    ++i,
1189 					    last_item->group,
1190 					    last_item->mib_id,
1191 					    last_item->length);
1192 			}
1193 			goto error_exit;
1194 		}
1195 		if (getcode == 0 &&
1196 		    ctlbuf.len >= sizeof (struct T_optmgmt_ack) &&
1197 		    toa->PRIM_type == T_OPTMGMT_ACK &&
1198 		    toa->MGMT_flags == T_SUCCESS &&
1199 		    req->len == 0) {
1200 			if (Xflag)
1201 				(void) printf("mibget getmsg() %d returned "
1202 				    "EOD (level %ld, name %ld)\n",
1203 				    j, req->level, req->name);
1204 			return (first_item);		/* this is EOD msg */
1205 		}
1206 
1207 		if (ctlbuf.len >= sizeof (struct T_error_ack) &&
1208 		    tea->PRIM_type == T_ERROR_ACK) {
1209 			(void) fprintf(stderr,
1210 			    "mibget %d gives T_ERROR_ACK: TLI_error = 0x%lx, "
1211 			    "UNIX_error = 0x%lx\n",
1212 			    j, tea->TLI_error, tea->UNIX_error);
1213 
1214 			errno = (tea->TLI_error == TSYSERR) ?
1215 			    tea->UNIX_error : EPROTO;
1216 			goto error_exit;
1217 		}
1218 
1219 		if (getcode != MOREDATA ||
1220 		    ctlbuf.len < sizeof (struct T_optmgmt_ack) ||
1221 		    toa->PRIM_type != T_OPTMGMT_ACK ||
1222 		    toa->MGMT_flags != T_SUCCESS) {
1223 			(void) printf("mibget getmsg(ctl) %d returned %d, "
1224 			    "ctlbuf.len = %d, PRIM_type = %ld\n",
1225 			    j, getcode, ctlbuf.len, toa->PRIM_type);
1226 
1227 			if (toa->PRIM_type == T_OPTMGMT_ACK)
1228 				(void) printf("T_OPTMGMT_ACK: "
1229 				    "MGMT_flags = 0x%lx, req->len = %ld\n",
1230 				    toa->MGMT_flags, req->len);
1231 			errno = ENOMSG;
1232 			goto error_exit;
1233 		}
1234 
1235 		temp = (mib_item_t *)malloc(sizeof (mib_item_t));
1236 		if (temp == NULL) {
1237 			perror("mibget malloc failed");
1238 			goto error_exit;
1239 		}
1240 		if (last_item != NULL)
1241 			last_item->next_item = temp;
1242 		else
1243 			first_item = temp;
1244 		last_item = temp;
1245 		last_item->next_item = NULL;
1246 		last_item->group = req->level;
1247 		last_item->mib_id = req->name;
1248 		last_item->length = req->len;
1249 		last_item->valp = malloc((int)req->len);
1250 		if (last_item->valp == NULL)
1251 			goto error_exit;
1252 		if (Xflag)
1253 			(void) printf("msg %4d: group = %-4d mib_id = %-5d "
1254 			    "length = %d\n",
1255 			    j, last_item->group, last_item->mib_id,
1256 			    last_item->length);
1257 
1258 		databuf.maxlen = last_item->length;
1259 		databuf.buf    = (char *)last_item->valp;
1260 		databuf.len    = 0;
1261 		flags = 0;
1262 		getcode = getmsg(sd, (struct strbuf *)0, &databuf, &flags);
1263 		if (getcode == -1) {
1264 			perror("mibget getmsg(data) failed");
1265 			goto error_exit;
1266 		} else if (getcode != 0) {
1267 			(void) printf("mibget getmsg(data) returned %d, "
1268 			    "databuf.maxlen = %d, databuf.len = %d\n",
1269 			    getcode, databuf.maxlen, databuf.len);
1270 			goto error_exit;
1271 		}
1272 		j++;
1273 	}
1274 	/* NOTREACHED */
1275 
1276 error_exit:;
1277 	mibfree(first_item);
1278 	return (NULL);
1279 }
1280 
1281 /*
1282  * mibfree: frees a linked list of type (mib_item_t *)
1283  * returned by mibget(); this is NOT THE SAME AS
1284  * mib_item_destroy(), so should be used for objects
1285  * returned by mibget() only
1286  */
1287 static void
mibfree(mib_item_t * firstitem)1288 mibfree(mib_item_t *firstitem)
1289 {
1290 	mib_item_t *lastitem;
1291 
1292 	while (firstitem != NULL) {
1293 		lastitem = firstitem;
1294 		firstitem = firstitem->next_item;
1295 		if (lastitem->valp != NULL)
1296 			free(lastitem->valp);
1297 		free(lastitem);
1298 	}
1299 }
1300 
1301 static int
mibopen(void)1302 mibopen(void)
1303 {
1304 	int	sd;
1305 
1306 	sd = open("/dev/arp", O_RDWR);
1307 	if (sd == -1) {
1308 		perror("arp open");
1309 		return (-1);
1310 	}
1311 	if (ioctl(sd, I_PUSH, "tcp") == -1) {
1312 		perror("tcp I_PUSH");
1313 		(void) close(sd);
1314 		return (-1);
1315 	}
1316 	if (ioctl(sd, I_PUSH, "udp") == -1) {
1317 		perror("udp I_PUSH");
1318 		(void) close(sd);
1319 		return (-1);
1320 	}
1321 	if (ioctl(sd, I_PUSH, "icmp") == -1) {
1322 		perror("icmp I_PUSH");
1323 		(void) close(sd);
1324 		return (-1);
1325 	}
1326 	return (sd);
1327 }
1328 
1329 /*
1330  * mib_item_dup: returns a clean mib_item_t * linked
1331  * list, so that for every element item->mib_id is 0;
1332  * to deallocate this linked list, use mib_item_destroy
1333  */
1334 static mib_item_t *
mib_item_dup(mib_item_t * item)1335 mib_item_dup(mib_item_t *item)
1336 {
1337 	int	c = 0;
1338 	mib_item_t *localp;
1339 	mib_item_t *tempp;
1340 
1341 	for (tempp = item; tempp; tempp = tempp->next_item)
1342 		if (tempp->mib_id == 0)
1343 			c++;
1344 	tempp = NULL;
1345 
1346 	localp = (mib_item_t *)malloc(c * sizeof (mib_item_t));
1347 	if (localp == NULL)
1348 		return (NULL);
1349 	c = 0;
1350 	for (; item; item = item->next_item) {
1351 		if (item->mib_id == 0) {
1352 			/* Replicate item in localp */
1353 			(localp[c]).next_item = NULL;
1354 			(localp[c]).group = item->group;
1355 			(localp[c]).mib_id = item->mib_id;
1356 			(localp[c]).length = item->length;
1357 			(localp[c]).valp = (uintptr_t *)malloc(
1358 			    item->length);
1359 			if ((localp[c]).valp == NULL) {
1360 				mib_item_destroy(&localp);
1361 				return (NULL);
1362 			}
1363 			(void *) memcpy((localp[c]).valp,
1364 			    item->valp,
1365 			    item->length);
1366 			tempp = &(localp[c]);
1367 			if (c > 0)
1368 				(localp[c - 1]).next_item = tempp;
1369 			c++;
1370 		}
1371 	}
1372 	return (localp);
1373 }
1374 
1375 /*
1376  * mib_item_diff: takes two (mib_item_t *) linked lists
1377  * item1 and item2 and computes the difference between
1378  * differentiable values in item2 against item1 for every
1379  * given member of item2; returns an mib_item_t * linked
1380  * list of diff's, or a copy of item2 if item1 is NULL;
1381  * will return NULL if system out of memory; works only
1382  * for item->mib_id == 0
1383  */
1384 static mib_item_t *
mib_item_diff(mib_item_t * item1,mib_item_t * item2)1385 mib_item_diff(mib_item_t *item1, mib_item_t *item2)
1386 {
1387 	int	nitems	= 0; /* no. of items in item2 */
1388 	mib_item_t *tempp2;  /* walking copy of item2 */
1389 	mib_item_t *tempp1;  /* walking copy of item1 */
1390 	mib_item_t *diffp;
1391 	mib_item_t *diffptr; /* walking copy of diffp */
1392 	mib_item_t *prevp = NULL;
1393 
1394 	if (item1 == NULL) {
1395 		diffp = mib_item_dup(item2);
1396 		return (diffp);
1397 	}
1398 
1399 	for (tempp2 = item2;
1400 	    tempp2;
1401 	    tempp2 = tempp2->next_item) {
1402 		if (tempp2->mib_id == 0)
1403 			switch (tempp2->group) {
1404 			/*
1405 			 * upon adding a case here, the same
1406 			 * must also be added in the next
1407 			 * switch statement, alongwith
1408 			 * appropriate code
1409 			 */
1410 			case MIB2_IP:
1411 			case MIB2_IP6:
1412 			case EXPER_DVMRP:
1413 			case EXPER_IGMP:
1414 			case MIB2_ICMP:
1415 			case MIB2_ICMP6:
1416 			case MIB2_TCP:
1417 			case MIB2_UDP:
1418 			case MIB2_SCTP:
1419 			case EXPER_RAWIP:
1420 				nitems++;
1421 			}
1422 	}
1423 	tempp2 = NULL;
1424 	if (nitems == 0) {
1425 		diffp = mib_item_dup(item2);
1426 		return (diffp);
1427 	}
1428 
1429 	diffp = calloc(nitems, sizeof (mib_item_t));
1430 	if (diffp == NULL)
1431 		return (NULL);
1432 	diffptr = diffp;
1433 	for (tempp2 = item2; tempp2 != NULL; tempp2 = tempp2->next_item) {
1434 		if (tempp2->mib_id != 0)
1435 			continue;
1436 		for (tempp1 = item1; tempp1 != NULL;
1437 		    tempp1 = tempp1->next_item) {
1438 			if (!(tempp1->mib_id == 0 &&
1439 			    tempp1->group == tempp2->group &&
1440 			    tempp1->mib_id == tempp2->mib_id))
1441 				continue;
1442 			/* found comparable data sets */
1443 			if (prevp != NULL)
1444 				prevp->next_item = diffptr;
1445 			switch (tempp2->group) {
1446 			/*
1447 			 * Indenting note: Because of long variable names
1448 			 * in cases MIB2_IP6 and MIB2_ICMP6, their contents
1449 			 * have been indented by one tab space only
1450 			 */
1451 			case MIB2_IP: {
1452 				mib2_ip_t *i2 = (mib2_ip_t *)tempp2->valp;
1453 				mib2_ip_t *i1 = (mib2_ip_t *)tempp1->valp;
1454 				mib2_ip_t *d;
1455 
1456 				diffptr->group = tempp2->group;
1457 				diffptr->mib_id = tempp2->mib_id;
1458 				diffptr->length = tempp2->length;
1459 				d = calloc(1, tempp2->length);
1460 				if (d == NULL)
1461 					goto mibdiff_out_of_memory;
1462 				diffptr->valp = d;
1463 				d->ipForwarding = i2->ipForwarding;
1464 				d->ipDefaultTTL = i2->ipDefaultTTL;
1465 				MDIFF(d, i2, i1, ipInReceives);
1466 				MDIFF(d, i2, i1, ipInHdrErrors);
1467 				MDIFF(d, i2, i1, ipInAddrErrors);
1468 				MDIFF(d, i2, i1, ipInCksumErrs);
1469 				MDIFF(d, i2, i1, ipForwDatagrams);
1470 				MDIFF(d, i2, i1, ipForwProhibits);
1471 				MDIFF(d, i2, i1, ipInUnknownProtos);
1472 				MDIFF(d, i2, i1, ipInDiscards);
1473 				MDIFF(d, i2, i1, ipInDelivers);
1474 				MDIFF(d, i2, i1, ipOutRequests);
1475 				MDIFF(d, i2, i1, ipOutDiscards);
1476 				MDIFF(d, i2, i1, ipOutNoRoutes);
1477 				MDIFF(d, i2, i1, ipReasmTimeout);
1478 				MDIFF(d, i2, i1, ipReasmReqds);
1479 				MDIFF(d, i2, i1, ipReasmOKs);
1480 				MDIFF(d, i2, i1, ipReasmFails);
1481 				MDIFF(d, i2, i1, ipReasmDuplicates);
1482 				MDIFF(d, i2, i1, ipReasmPartDups);
1483 				MDIFF(d, i2, i1, ipFragOKs);
1484 				MDIFF(d, i2, i1, ipFragFails);
1485 				MDIFF(d, i2, i1, ipFragCreates);
1486 				MDIFF(d, i2, i1, ipRoutingDiscards);
1487 				MDIFF(d, i2, i1, tcpInErrs);
1488 				MDIFF(d, i2, i1, udpNoPorts);
1489 				MDIFF(d, i2, i1, udpInCksumErrs);
1490 				MDIFF(d, i2, i1, udpInOverflows);
1491 				MDIFF(d, i2, i1, rawipInOverflows);
1492 				MDIFF(d, i2, i1, ipsecInSucceeded);
1493 				MDIFF(d, i2, i1, ipsecInFailed);
1494 				MDIFF(d, i2, i1, ipInIPv6);
1495 				MDIFF(d, i2, i1, ipOutIPv6);
1496 				MDIFF(d, i2, i1, ipOutSwitchIPv6);
1497 				prevp = diffptr++;
1498 				break;
1499 			}
1500 			case MIB2_IP6: {
1501 			mib2_ipv6IfStatsEntry_t *i2;
1502 			mib2_ipv6IfStatsEntry_t *i1;
1503 			mib2_ipv6IfStatsEntry_t *d;
1504 
1505 			i2 = (mib2_ipv6IfStatsEntry_t *)tempp2->valp;
1506 			i1 = (mib2_ipv6IfStatsEntry_t *)tempp1->valp;
1507 			diffptr->group = tempp2->group;
1508 			diffptr->mib_id = tempp2->mib_id;
1509 			diffptr->length = tempp2->length;
1510 			d = calloc(1, tempp2->length);
1511 			if (d == NULL)
1512 				goto mibdiff_out_of_memory;
1513 			diffptr->valp = d;
1514 			d->ipv6Forwarding = i2->ipv6Forwarding;
1515 			d->ipv6DefaultHopLimit =
1516 			    i2->ipv6DefaultHopLimit;
1517 
1518 			MDIFF(d, i2, i1, ipv6InReceives);
1519 			MDIFF(d, i2, i1, ipv6InHdrErrors);
1520 			MDIFF(d, i2, i1, ipv6InTooBigErrors);
1521 			MDIFF(d, i2, i1, ipv6InNoRoutes);
1522 			MDIFF(d, i2, i1, ipv6InAddrErrors);
1523 			MDIFF(d, i2, i1, ipv6InUnknownProtos);
1524 			MDIFF(d, i2, i1, ipv6InTruncatedPkts);
1525 			MDIFF(d, i2, i1, ipv6InDiscards);
1526 			MDIFF(d, i2, i1, ipv6InDelivers);
1527 			MDIFF(d, i2, i1, ipv6OutForwDatagrams);
1528 			MDIFF(d, i2, i1, ipv6OutRequests);
1529 			MDIFF(d, i2, i1, ipv6OutDiscards);
1530 			MDIFF(d, i2, i1, ipv6OutNoRoutes);
1531 			MDIFF(d, i2, i1, ipv6OutFragOKs);
1532 			MDIFF(d, i2, i1, ipv6OutFragFails);
1533 			MDIFF(d, i2, i1, ipv6OutFragCreates);
1534 			MDIFF(d, i2, i1, ipv6ReasmReqds);
1535 			MDIFF(d, i2, i1, ipv6ReasmOKs);
1536 			MDIFF(d, i2, i1, ipv6ReasmFails);
1537 			MDIFF(d, i2, i1, ipv6InMcastPkts);
1538 			MDIFF(d, i2, i1, ipv6OutMcastPkts);
1539 			MDIFF(d, i2, i1, ipv6ReasmDuplicates);
1540 			MDIFF(d, i2, i1, ipv6ReasmPartDups);
1541 			MDIFF(d, i2, i1, ipv6ForwProhibits);
1542 			MDIFF(d, i2, i1, udpInCksumErrs);
1543 			MDIFF(d, i2, i1, udpInOverflows);
1544 			MDIFF(d, i2, i1, rawipInOverflows);
1545 			MDIFF(d, i2, i1, ipv6InIPv4);
1546 			MDIFF(d, i2, i1, ipv6OutIPv4);
1547 			MDIFF(d, i2, i1, ipv6OutSwitchIPv4);
1548 			prevp = diffptr++;
1549 			break;
1550 			}
1551 			case EXPER_DVMRP: {
1552 				struct mrtstat *m2;
1553 				struct mrtstat *m1;
1554 				struct mrtstat *d;
1555 
1556 				m2 = (struct mrtstat *)tempp2->valp;
1557 				m1 = (struct mrtstat *)tempp1->valp;
1558 				diffptr->group = tempp2->group;
1559 				diffptr->mib_id = tempp2->mib_id;
1560 				diffptr->length = tempp2->length;
1561 				d = calloc(1, tempp2->length);
1562 				if (d == NULL)
1563 					goto mibdiff_out_of_memory;
1564 				diffptr->valp = d;
1565 				MDIFF(d, m2, m1, mrts_mfc_hits);
1566 				MDIFF(d, m2, m1, mrts_mfc_misses);
1567 				MDIFF(d, m2, m1, mrts_fwd_in);
1568 				MDIFF(d, m2, m1, mrts_fwd_out);
1569 				d->mrts_upcalls = m2->mrts_upcalls;
1570 				MDIFF(d, m2, m1, mrts_fwd_drop);
1571 				MDIFF(d, m2, m1, mrts_bad_tunnel);
1572 				MDIFF(d, m2, m1, mrts_cant_tunnel);
1573 				MDIFF(d, m2, m1, mrts_wrong_if);
1574 				MDIFF(d, m2, m1, mrts_upq_ovflw);
1575 				MDIFF(d, m2, m1, mrts_cache_cleanups);
1576 				MDIFF(d, m2, m1, mrts_drop_sel);
1577 				MDIFF(d, m2, m1, mrts_q_overflow);
1578 				MDIFF(d, m2, m1, mrts_pkt2large);
1579 				MDIFF(d, m2, m1, mrts_pim_badversion);
1580 				MDIFF(d, m2, m1, mrts_pim_rcv_badcsum);
1581 				MDIFF(d, m2, m1, mrts_pim_badregisters);
1582 				MDIFF(d, m2, m1, mrts_pim_regforwards);
1583 				MDIFF(d, m2, m1, mrts_pim_regsend_drops);
1584 				MDIFF(d, m2, m1, mrts_pim_malformed);
1585 				MDIFF(d, m2, m1, mrts_pim_nomemory);
1586 				prevp = diffptr++;
1587 				break;
1588 			}
1589 			case EXPER_IGMP: {
1590 				struct igmpstat *i2;
1591 				struct igmpstat *i1;
1592 				struct igmpstat *d;
1593 
1594 				i2 = (struct igmpstat *)tempp2->valp;
1595 				i1 = (struct igmpstat *)tempp1->valp;
1596 				diffptr->group = tempp2->group;
1597 				diffptr->mib_id = tempp2->mib_id;
1598 				diffptr->length = tempp2->length;
1599 				d = calloc(1, tempp2->length);
1600 				if (d == NULL)
1601 					goto mibdiff_out_of_memory;
1602 				diffptr->valp = d;
1603 				MDIFF(d, i2, i1, igps_rcv_total);
1604 				MDIFF(d, i2, i1, igps_rcv_tooshort);
1605 				MDIFF(d, i2, i1, igps_rcv_badsum);
1606 				MDIFF(d, i2, i1, igps_rcv_queries);
1607 				MDIFF(d, i2, i1, igps_rcv_badqueries);
1608 				MDIFF(d, i2, i1, igps_rcv_reports);
1609 				MDIFF(d, i2, i1, igps_rcv_badreports);
1610 				MDIFF(d, i2, i1, igps_rcv_ourreports);
1611 				MDIFF(d, i2, i1, igps_snd_reports);
1612 				prevp = diffptr++;
1613 				break;
1614 			}
1615 			case MIB2_ICMP: {
1616 				mib2_icmp_t *i2;
1617 				mib2_icmp_t *i1;
1618 				mib2_icmp_t *d;
1619 
1620 				i2 = (mib2_icmp_t *)tempp2->valp;
1621 				i1 = (mib2_icmp_t *)tempp1->valp;
1622 				diffptr->group = tempp2->group;
1623 				diffptr->mib_id = tempp2->mib_id;
1624 				diffptr->length = tempp2->length;
1625 				d = calloc(1, tempp2->length);
1626 				if (d == NULL)
1627 					goto mibdiff_out_of_memory;
1628 				diffptr->valp = d;
1629 				MDIFF(d, i2, i1, icmpInMsgs);
1630 				MDIFF(d, i2, i1, icmpInErrors);
1631 				MDIFF(d, i2, i1, icmpInCksumErrs);
1632 				MDIFF(d, i2, i1, icmpInUnknowns);
1633 				MDIFF(d, i2, i1, icmpInDestUnreachs);
1634 				MDIFF(d, i2, i1, icmpInTimeExcds);
1635 				MDIFF(d, i2, i1, icmpInParmProbs);
1636 				MDIFF(d, i2, i1, icmpInSrcQuenchs);
1637 				MDIFF(d, i2, i1, icmpInRedirects);
1638 				MDIFF(d, i2, i1, icmpInBadRedirects);
1639 				MDIFF(d, i2, i1, icmpInEchos);
1640 				MDIFF(d, i2, i1, icmpInEchoReps);
1641 				MDIFF(d, i2, i1, icmpInTimestamps);
1642 				MDIFF(d, i2, i1, icmpInAddrMasks);
1643 				MDIFF(d, i2, i1, icmpInAddrMaskReps);
1644 				MDIFF(d, i2, i1, icmpInFragNeeded);
1645 				MDIFF(d, i2, i1, icmpOutMsgs);
1646 				MDIFF(d, i2, i1, icmpOutDrops);
1647 				MDIFF(d, i2, i1, icmpOutErrors);
1648 				MDIFF(d, i2, i1, icmpOutDestUnreachs);
1649 				MDIFF(d, i2, i1, icmpOutTimeExcds);
1650 				MDIFF(d, i2, i1, icmpOutParmProbs);
1651 				MDIFF(d, i2, i1, icmpOutSrcQuenchs);
1652 				MDIFF(d, i2, i1, icmpOutRedirects);
1653 				MDIFF(d, i2, i1, icmpOutEchos);
1654 				MDIFF(d, i2, i1, icmpOutEchoReps);
1655 				MDIFF(d, i2, i1, icmpOutTimestamps);
1656 				MDIFF(d, i2, i1, icmpOutTimestampReps);
1657 				MDIFF(d, i2, i1, icmpOutAddrMasks);
1658 				MDIFF(d, i2, i1, icmpOutAddrMaskReps);
1659 				MDIFF(d, i2, i1, icmpOutFragNeeded);
1660 				MDIFF(d, i2, i1, icmpInOverflows);
1661 				prevp = diffptr++;
1662 				break;
1663 			}
1664 			case MIB2_ICMP6: {
1665 	mib2_ipv6IfIcmpEntry_t *i2;
1666 	mib2_ipv6IfIcmpEntry_t *i1;
1667 	mib2_ipv6IfIcmpEntry_t *d;
1668 
1669 	i2 = (mib2_ipv6IfIcmpEntry_t *)tempp2->valp;
1670 	i1 = (mib2_ipv6IfIcmpEntry_t *)tempp1->valp;
1671 	diffptr->group = tempp2->group;
1672 	diffptr->mib_id = tempp2->mib_id;
1673 	diffptr->length = tempp2->length;
1674 	d = calloc(1, tempp2->length);
1675 	if (d == NULL)
1676 		goto mibdiff_out_of_memory;
1677 	diffptr->valp = d;
1678 	MDIFF(d, i2, i1, ipv6IfIcmpInMsgs);
1679 	MDIFF(d, i2, i1, ipv6IfIcmpInErrors);
1680 	MDIFF(d, i2, i1, ipv6IfIcmpInDestUnreachs);
1681 	MDIFF(d, i2, i1, ipv6IfIcmpInAdminProhibs);
1682 	MDIFF(d, i2, i1, ipv6IfIcmpInTimeExcds);
1683 	MDIFF(d, i2, i1, ipv6IfIcmpInParmProblems);
1684 	MDIFF(d, i2, i1, ipv6IfIcmpInPktTooBigs);
1685 	MDIFF(d, i2, i1, ipv6IfIcmpInEchos);
1686 	MDIFF(d, i2, i1, ipv6IfIcmpInEchoReplies);
1687 	MDIFF(d, i2, i1, ipv6IfIcmpInRouterSolicits);
1688 	MDIFF(d, i2, i1, ipv6IfIcmpInRouterAdvertisements);
1689 	MDIFF(d, i2, i1, ipv6IfIcmpInNeighborSolicits);
1690 	MDIFF(d, i2, i1, ipv6IfIcmpInNeighborAdvertisements);
1691 	MDIFF(d, i2, i1, ipv6IfIcmpInRedirects);
1692 	MDIFF(d, i2, i1, ipv6IfIcmpInBadRedirects);
1693 	MDIFF(d, i2, i1, ipv6IfIcmpInGroupMembQueries);
1694 	MDIFF(d, i2, i1, ipv6IfIcmpInGroupMembResponses);
1695 	MDIFF(d, i2, i1, ipv6IfIcmpInGroupMembReductions);
1696 	MDIFF(d, i2, i1, ipv6IfIcmpInOverflows);
1697 	MDIFF(d, i2, i1, ipv6IfIcmpOutMsgs);
1698 	MDIFF(d, i2, i1, ipv6IfIcmpOutErrors);
1699 	MDIFF(d, i2, i1, ipv6IfIcmpOutDestUnreachs);
1700 	MDIFF(d, i2, i1, ipv6IfIcmpOutAdminProhibs);
1701 	MDIFF(d, i2, i1, ipv6IfIcmpOutTimeExcds);
1702 	MDIFF(d, i2, i1, ipv6IfIcmpOutParmProblems);
1703 	MDIFF(d, i2, i1, ipv6IfIcmpOutPktTooBigs);
1704 	MDIFF(d, i2, i1, ipv6IfIcmpOutEchos);
1705 	MDIFF(d, i2, i1, ipv6IfIcmpOutEchoReplies);
1706 	MDIFF(d, i2, i1, ipv6IfIcmpOutRouterSolicits);
1707 	MDIFF(d, i2, i1, ipv6IfIcmpOutRouterAdvertisements);
1708 	MDIFF(d, i2, i1, ipv6IfIcmpOutNeighborSolicits);
1709 	MDIFF(d, i2, i1, ipv6IfIcmpOutNeighborAdvertisements);
1710 	MDIFF(d, i2, i1, ipv6IfIcmpOutRedirects);
1711 	MDIFF(d, i2, i1, ipv6IfIcmpOutGroupMembQueries);
1712 	MDIFF(d, i2, i1, ipv6IfIcmpOutGroupMembResponses);
1713 	MDIFF(d, i2, i1, ipv6IfIcmpOutGroupMembReductions);
1714 	prevp = diffptr++;
1715 	break;
1716 			}
1717 			case MIB2_TCP: {
1718 				mib2_tcp_t *t2;
1719 				mib2_tcp_t *t1;
1720 				mib2_tcp_t *d;
1721 
1722 				t2 = (mib2_tcp_t *)tempp2->valp;
1723 				t1 = (mib2_tcp_t *)tempp1->valp;
1724 				diffptr->group = tempp2->group;
1725 				diffptr->mib_id = tempp2->mib_id;
1726 				diffptr->length = tempp2->length;
1727 				d = calloc(1, tempp2->length);
1728 				if (d == NULL)
1729 					goto mibdiff_out_of_memory;
1730 				diffptr->valp = d;
1731 				d->tcpRtoMin = t2->tcpRtoMin;
1732 				d->tcpRtoMax = t2->tcpRtoMax;
1733 				d->tcpMaxConn = t2->tcpMaxConn;
1734 				MDIFF(d, t2, t1, tcpActiveOpens);
1735 				MDIFF(d, t2, t1, tcpPassiveOpens);
1736 				MDIFF(d, t2, t1, tcpAttemptFails);
1737 				MDIFF(d, t2, t1, tcpEstabResets);
1738 				d->tcpCurrEstab = t2->tcpCurrEstab;
1739 				MDIFF(d, t2, t1, tcpHCOutSegs);
1740 				MDIFF(d, t2, t1, tcpOutDataSegs);
1741 				MDIFF(d, t2, t1, tcpOutDataBytes);
1742 				MDIFF(d, t2, t1, tcpRetransSegs);
1743 				MDIFF(d, t2, t1, tcpRetransBytes);
1744 				MDIFF(d, t2, t1, tcpOutAck);
1745 				MDIFF(d, t2, t1, tcpOutAckDelayed);
1746 				MDIFF(d, t2, t1, tcpOutUrg);
1747 				MDIFF(d, t2, t1, tcpOutWinUpdate);
1748 				MDIFF(d, t2, t1, tcpOutWinProbe);
1749 				MDIFF(d, t2, t1, tcpOutControl);
1750 				MDIFF(d, t2, t1, tcpOutRsts);
1751 				MDIFF(d, t2, t1, tcpOutFastRetrans);
1752 				MDIFF(d, t2, t1, tcpHCInSegs);
1753 				MDIFF(d, t2, t1, tcpInAckSegs);
1754 				MDIFF(d, t2, t1, tcpInAckBytes);
1755 				MDIFF(d, t2, t1, tcpInDupAck);
1756 				MDIFF(d, t2, t1, tcpInAckUnsent);
1757 				MDIFF(d, t2, t1, tcpInDataInorderSegs);
1758 				MDIFF(d, t2, t1, tcpInDataInorderBytes);
1759 				MDIFF(d, t2, t1, tcpInDataUnorderSegs);
1760 				MDIFF(d, t2, t1, tcpInDataUnorderBytes);
1761 				MDIFF(d, t2, t1, tcpInDataDupSegs);
1762 				MDIFF(d, t2, t1, tcpInDataDupBytes);
1763 				MDIFF(d, t2, t1, tcpInDataPartDupSegs);
1764 				MDIFF(d, t2, t1, tcpInDataPartDupBytes);
1765 				MDIFF(d, t2, t1, tcpInDataPastWinSegs);
1766 				MDIFF(d, t2, t1, tcpInDataPastWinBytes);
1767 				MDIFF(d, t2, t1, tcpInWinProbe);
1768 				MDIFF(d, t2, t1, tcpInWinUpdate);
1769 				MDIFF(d, t2, t1, tcpInClosed);
1770 				MDIFF(d, t2, t1, tcpRttNoUpdate);
1771 				MDIFF(d, t2, t1, tcpRttUpdate);
1772 				MDIFF(d, t2, t1, tcpTimRetrans);
1773 				MDIFF(d, t2, t1, tcpTimRetransDrop);
1774 				MDIFF(d, t2, t1, tcpTimKeepalive);
1775 				MDIFF(d, t2, t1, tcpTimKeepaliveProbe);
1776 				MDIFF(d, t2, t1, tcpTimKeepaliveDrop);
1777 				MDIFF(d, t2, t1, tcpListenDrop);
1778 				MDIFF(d, t2, t1, tcpListenDropQ0);
1779 				MDIFF(d, t2, t1, tcpHalfOpenDrop);
1780 				MDIFF(d, t2, t1, tcpOutSackRetransSegs);
1781 				prevp = diffptr++;
1782 				break;
1783 			}
1784 			case MIB2_UDP: {
1785 				mib2_udp_t *u2;
1786 				mib2_udp_t *u1;
1787 				mib2_udp_t *d;
1788 
1789 				u2 = (mib2_udp_t *)tempp2->valp;
1790 				u1 = (mib2_udp_t *)tempp1->valp;
1791 				diffptr->group = tempp2->group;
1792 				diffptr->mib_id = tempp2->mib_id;
1793 				diffptr->length = tempp2->length;
1794 				d = calloc(1, tempp2->length);
1795 				if (d == NULL)
1796 					goto mibdiff_out_of_memory;
1797 				diffptr->valp = d;
1798 				MDIFF(d, u2, u1, udpHCInDatagrams);
1799 				MDIFF(d, u2, u1, udpInErrors);
1800 				MDIFF(d, u2, u1, udpHCOutDatagrams);
1801 				MDIFF(d, u2, u1, udpOutErrors);
1802 				prevp = diffptr++;
1803 				break;
1804 			}
1805 			case MIB2_SCTP: {
1806 				mib2_sctp_t *s2;
1807 				mib2_sctp_t *s1;
1808 				mib2_sctp_t *d;
1809 
1810 				s2 = (mib2_sctp_t *)tempp2->valp;
1811 				s1 = (mib2_sctp_t *)tempp1->valp;
1812 				diffptr->group = tempp2->group;
1813 				diffptr->mib_id = tempp2->mib_id;
1814 				diffptr->length = tempp2->length;
1815 				d = calloc(1, tempp2->length);
1816 				if (d == NULL)
1817 					goto mibdiff_out_of_memory;
1818 				diffptr->valp = d;
1819 				d->sctpRtoAlgorithm = s2->sctpRtoAlgorithm;
1820 				d->sctpRtoMin = s2->sctpRtoMin;
1821 				d->sctpRtoMax = s2->sctpRtoMax;
1822 				d->sctpRtoInitial = s2->sctpRtoInitial;
1823 				d->sctpMaxAssocs = s2->sctpMaxAssocs;
1824 				d->sctpValCookieLife = s2->sctpValCookieLife;
1825 				d->sctpMaxInitRetr = s2->sctpMaxInitRetr;
1826 				d->sctpCurrEstab = s2->sctpCurrEstab;
1827 				MDIFF(d, s2, s1, sctpActiveEstab);
1828 				MDIFF(d, s2, s1, sctpPassiveEstab);
1829 				MDIFF(d, s2, s1, sctpAborted);
1830 				MDIFF(d, s2, s1, sctpShutdowns);
1831 				MDIFF(d, s2, s1, sctpOutOfBlue);
1832 				MDIFF(d, s2, s1, sctpChecksumError);
1833 				MDIFF(d, s2, s1, sctpOutCtrlChunks);
1834 				MDIFF(d, s2, s1, sctpOutOrderChunks);
1835 				MDIFF(d, s2, s1, sctpOutUnorderChunks);
1836 				MDIFF(d, s2, s1, sctpRetransChunks);
1837 				MDIFF(d, s2, s1, sctpOutAck);
1838 				MDIFF(d, s2, s1, sctpOutAckDelayed);
1839 				MDIFF(d, s2, s1, sctpOutWinUpdate);
1840 				MDIFF(d, s2, s1, sctpOutFastRetrans);
1841 				MDIFF(d, s2, s1, sctpOutWinProbe);
1842 				MDIFF(d, s2, s1, sctpInCtrlChunks);
1843 				MDIFF(d, s2, s1, sctpInOrderChunks);
1844 				MDIFF(d, s2, s1, sctpInUnorderChunks);
1845 				MDIFF(d, s2, s1, sctpInAck);
1846 				MDIFF(d, s2, s1, sctpInDupAck);
1847 				MDIFF(d, s2, s1, sctpInAckUnsent);
1848 				MDIFF(d, s2, s1, sctpFragUsrMsgs);
1849 				MDIFF(d, s2, s1, sctpReasmUsrMsgs);
1850 				MDIFF(d, s2, s1, sctpOutSCTPPkts);
1851 				MDIFF(d, s2, s1, sctpInSCTPPkts);
1852 				MDIFF(d, s2, s1, sctpInInvalidCookie);
1853 				MDIFF(d, s2, s1, sctpTimRetrans);
1854 				MDIFF(d, s2, s1, sctpTimRetransDrop);
1855 				MDIFF(d, s2, s1, sctpTimHeartBeatProbe);
1856 				MDIFF(d, s2, s1, sctpTimHeartBeatDrop);
1857 				MDIFF(d, s2, s1, sctpListenDrop);
1858 				MDIFF(d, s2, s1, sctpInClosed);
1859 				prevp = diffptr++;
1860 				break;
1861 			}
1862 			case EXPER_RAWIP: {
1863 				mib2_rawip_t *r2;
1864 				mib2_rawip_t *r1;
1865 				mib2_rawip_t *d;
1866 
1867 				r2 = (mib2_rawip_t *)tempp2->valp;
1868 				r1 = (mib2_rawip_t *)tempp1->valp;
1869 				diffptr->group = tempp2->group;
1870 				diffptr->mib_id = tempp2->mib_id;
1871 				diffptr->length = tempp2->length;
1872 				d = calloc(1, tempp2->length);
1873 				if (d == NULL)
1874 					goto mibdiff_out_of_memory;
1875 				diffptr->valp = d;
1876 				MDIFF(d, r2, r1, rawipInDatagrams);
1877 				MDIFF(d, r2, r1, rawipInErrors);
1878 				MDIFF(d, r2, r1, rawipInCksumErrs);
1879 				MDIFF(d, r2, r1, rawipOutDatagrams);
1880 				MDIFF(d, r2, r1, rawipOutErrors);
1881 				prevp = diffptr++;
1882 				break;
1883 			}
1884 			/*
1885 			 * there are more "group" types but they aren't
1886 			 * required for the -s and -Ms options
1887 			 */
1888 			}
1889 		}
1890 		tempp1 = NULL;
1891 	}
1892 	tempp2 = NULL;
1893 	diffptr--;
1894 	diffptr->next_item = NULL;
1895 	return (diffp);
1896 
1897 mibdiff_out_of_memory:;
1898 	mib_item_destroy(&diffp);
1899 	return (NULL);
1900 }
1901 
1902 /*
1903  * mib_item_destroy: cleans up a mib_item_t *
1904  * that was created by calling mib_item_dup or
1905  * mib_item_diff
1906  */
1907 static void
mib_item_destroy(mib_item_t ** itemp)1908 mib_item_destroy(mib_item_t **itemp)
1909 {
1910 	int	nitems = 0;
1911 	int	c = 0;
1912 	mib_item_t *tempp;
1913 
1914 	if (itemp == NULL || *itemp == NULL)
1915 		return;
1916 
1917 	for (tempp = *itemp; tempp != NULL; tempp = tempp->next_item)
1918 		if (tempp->mib_id == 0)
1919 			nitems++;
1920 		else
1921 			return;	/* cannot destroy! */
1922 
1923 	if (nitems == 0)
1924 		return;		/* cannot destroy! */
1925 
1926 	for (c = nitems - 1; c >= 0; c--) {
1927 		if ((itemp[0][c]).valp != NULL)
1928 			free((itemp[0][c]).valp);
1929 	}
1930 	free(*itemp);
1931 
1932 	*itemp = NULL;
1933 }
1934 
1935 /* Compare two Octet_ts.  Return B_TRUE if they match, B_FALSE if not. */
1936 static boolean_t
octetstrmatch(const Octet_t * a,const Octet_t * b)1937 octetstrmatch(const Octet_t *a, const Octet_t *b)
1938 {
1939 	if (a == NULL || b == NULL)
1940 		return (B_FALSE);
1941 
1942 	if (a->o_length != b->o_length)
1943 		return (B_FALSE);
1944 
1945 	return (memcmp(a->o_bytes, b->o_bytes, a->o_length) == 0);
1946 }
1947 
1948 /* If octetstr() changes make an appropriate change to STR_EXPAND */
1949 static char *
octetstr(const Octet_t * op,int code,char * dst,uint_t dstlen)1950 octetstr(const Octet_t *op, int code, char *dst, uint_t dstlen)
1951 {
1952 	int	i;
1953 	char	*cp;
1954 
1955 	cp = dst;
1956 	if (op) {
1957 		for (i = 0; i < op->o_length; i++) {
1958 			switch (code) {
1959 			case 'd':
1960 				if (cp - dst + 4 > dstlen) {
1961 					*cp = '\0';
1962 					return (dst);
1963 				}
1964 				(void) snprintf(cp, 5, "%d.",
1965 				    0xff & op->o_bytes[i]);
1966 				cp = strchr(cp, '\0');
1967 				break;
1968 			case 'a':
1969 				if (cp - dst + 1 > dstlen) {
1970 					*cp = '\0';
1971 					return (dst);
1972 				}
1973 				*cp++ = op->o_bytes[i];
1974 				break;
1975 			case 'h':
1976 			default:
1977 				if (cp - dst + 3 > dstlen) {
1978 					*cp = '\0';
1979 					return (dst);
1980 				}
1981 				(void) snprintf(cp, 4, "%02x:",
1982 				    0xff & op->o_bytes[i]);
1983 				cp += 3;
1984 				break;
1985 			}
1986 		}
1987 	}
1988 	if (code != 'a' && cp != dst)
1989 		cp--;
1990 	*cp = '\0';
1991 	return (dst);
1992 }
1993 
1994 static const char *
mitcp_state(int state,const mib2_transportMLPEntry_t * attr)1995 mitcp_state(int state, const mib2_transportMLPEntry_t *attr)
1996 {
1997 	static char tcpsbuf[50];
1998 	const char *cp;
1999 
2000 	switch (state) {
2001 	case TCPS_CLOSED:
2002 		cp = "CLOSED";
2003 		break;
2004 	case TCPS_IDLE:
2005 		cp = "IDLE";
2006 		break;
2007 	case TCPS_BOUND:
2008 		cp = "BOUND";
2009 		break;
2010 	case TCPS_LISTEN:
2011 		cp = "LISTEN";
2012 		break;
2013 	case TCPS_SYN_SENT:
2014 		cp = "SYN_SENT";
2015 		break;
2016 	case TCPS_SYN_RCVD:
2017 		cp = "SYN_RCVD";
2018 		break;
2019 	case TCPS_ESTABLISHED:
2020 		cp = "ESTABLISHED";
2021 		break;
2022 	case TCPS_CLOSE_WAIT:
2023 		cp = "CLOSE_WAIT";
2024 		break;
2025 	case TCPS_FIN_WAIT_1:
2026 		cp = "FIN_WAIT_1";
2027 		break;
2028 	case TCPS_CLOSING:
2029 		cp = "CLOSING";
2030 		break;
2031 	case TCPS_LAST_ACK:
2032 		cp = "LAST_ACK";
2033 		break;
2034 	case TCPS_FIN_WAIT_2:
2035 		cp = "FIN_WAIT_2";
2036 		break;
2037 	case TCPS_TIME_WAIT:
2038 		cp = "TIME_WAIT";
2039 		break;
2040 	default:
2041 		(void) snprintf(tcpsbuf, sizeof (tcpsbuf),
2042 		    "UnknownState(%d)", state);
2043 		cp = tcpsbuf;
2044 		break;
2045 	}
2046 
2047 	if (RSECflag && attr != NULL && attr->tme_flags != 0) {
2048 		if (cp != tcpsbuf) {
2049 			(void) strlcpy(tcpsbuf, cp, sizeof (tcpsbuf));
2050 			cp = tcpsbuf;
2051 		}
2052 		if (attr->tme_flags & MIB2_TMEF_PRIVATE)
2053 			(void) strlcat(tcpsbuf, " P", sizeof (tcpsbuf));
2054 		if (attr->tme_flags & MIB2_TMEF_SHARED)
2055 			(void) strlcat(tcpsbuf, " S", sizeof (tcpsbuf));
2056 	}
2057 
2058 	return (cp);
2059 }
2060 
2061 static const char *
miudp_state(int state,const mib2_transportMLPEntry_t * attr)2062 miudp_state(int state, const mib2_transportMLPEntry_t *attr)
2063 {
2064 	static char udpsbuf[50];
2065 	const char *cp;
2066 
2067 	switch (state) {
2068 	case MIB2_UDP_unbound:
2069 		cp = "Unbound";
2070 		break;
2071 	case MIB2_UDP_idle:
2072 		cp = "Idle";
2073 		break;
2074 	case MIB2_UDP_connected:
2075 		cp = "Connected";
2076 		break;
2077 	default:
2078 		(void) snprintf(udpsbuf, sizeof (udpsbuf),
2079 		    "Unknown State(%d)", state);
2080 		cp = udpsbuf;
2081 		break;
2082 	}
2083 
2084 	if (RSECflag && attr != NULL && attr->tme_flags != 0) {
2085 		if (cp != udpsbuf) {
2086 			(void) strlcpy(udpsbuf, cp, sizeof (udpsbuf));
2087 			cp = udpsbuf;
2088 		}
2089 		if (attr->tme_flags & MIB2_TMEF_PRIVATE)
2090 			(void) strlcat(udpsbuf, " P", sizeof (udpsbuf));
2091 		if (attr->tme_flags & MIB2_TMEF_SHARED)
2092 			(void) strlcat(udpsbuf, " S", sizeof (udpsbuf));
2093 	}
2094 
2095 	return (cp);
2096 }
2097 
2098 static int odd;
2099 
2100 static void
prval_init(void)2101 prval_init(void)
2102 {
2103 	odd = 0;
2104 }
2105 
2106 static void
prval(char * str,Counter val)2107 prval(char *str, Counter val)
2108 {
2109 	(void) printf("\t%-20s=%6u", str, val);
2110 	if (odd++ & 1)
2111 		(void) putchar('\n');
2112 }
2113 
2114 static void
prval64(char * str,Counter64 val)2115 prval64(char *str, Counter64 val)
2116 {
2117 	(void) printf("\t%-20s=%6llu", str, val);
2118 	if (odd++ & 1)
2119 		(void) putchar('\n');
2120 }
2121 
2122 static void
pr_int_val(char * str,int val)2123 pr_int_val(char *str, int val)
2124 {
2125 	(void) printf("\t%-20s=%6d", str, val);
2126 	if (odd++ & 1)
2127 		(void) putchar('\n');
2128 }
2129 
2130 static void
pr_sctp_rtoalgo(char * str,int val)2131 pr_sctp_rtoalgo(char *str, int val)
2132 {
2133 	(void) printf("\t%-20s=", str);
2134 	switch (val) {
2135 		case MIB2_SCTP_RTOALGO_OTHER:
2136 			(void) printf("%6.6s", "other");
2137 			break;
2138 
2139 		case MIB2_SCTP_RTOALGO_VANJ:
2140 			(void) printf("%6.6s", "vanj");
2141 			break;
2142 
2143 		default:
2144 			(void) printf("%6d", val);
2145 			break;
2146 	}
2147 	if (odd++ & 1)
2148 		(void) putchar('\n');
2149 }
2150 
2151 static void
prval_end(void)2152 prval_end(void)
2153 {
2154 	if (odd++ & 1)
2155 		(void) putchar('\n');
2156 }
2157 
2158 /* Extract constant sizes */
2159 static void
mib_get_constants(mib_item_t * item)2160 mib_get_constants(mib_item_t *item)
2161 {
2162 	for (; item; item = item->next_item) {
2163 		if (item->mib_id != 0)
2164 			continue;
2165 
2166 		switch (item->group) {
2167 		case MIB2_IP: {
2168 			mib2_ip_t	*ip = (mib2_ip_t *)item->valp;
2169 
2170 			ipAddrEntrySize = ip->ipAddrEntrySize;
2171 			ipRouteEntrySize = ip->ipRouteEntrySize;
2172 			ipNetToMediaEntrySize = ip->ipNetToMediaEntrySize;
2173 			ipMemberEntrySize = ip->ipMemberEntrySize;
2174 			ipGroupSourceEntrySize = ip->ipGroupSourceEntrySize;
2175 			ipRouteAttributeSize = ip->ipRouteAttributeSize;
2176 			transportMLPSize = ip->transportMLPSize;
2177 			ipDestEntrySize = ip->ipDestEntrySize;
2178 			assert(IS_P2ALIGNED(ipAddrEntrySize,
2179 			    sizeof (mib2_ipAddrEntry_t *)));
2180 			assert(IS_P2ALIGNED(ipRouteEntrySize,
2181 			    sizeof (mib2_ipRouteEntry_t *)));
2182 			assert(IS_P2ALIGNED(ipNetToMediaEntrySize,
2183 			    sizeof (mib2_ipNetToMediaEntry_t *)));
2184 			assert(IS_P2ALIGNED(ipMemberEntrySize,
2185 			    sizeof (ip_member_t *)));
2186 			assert(IS_P2ALIGNED(ipGroupSourceEntrySize,
2187 			    sizeof (ip_grpsrc_t *)));
2188 			assert(IS_P2ALIGNED(ipRouteAttributeSize,
2189 			    sizeof (mib2_ipAttributeEntry_t *)));
2190 			assert(IS_P2ALIGNED(transportMLPSize,
2191 			    sizeof (mib2_transportMLPEntry_t *)));
2192 			break;
2193 		}
2194 		case EXPER_DVMRP: {
2195 			struct mrtstat	*mrts = (struct mrtstat *)item->valp;
2196 
2197 			vifctlSize = mrts->mrts_vifctlSize;
2198 			mfcctlSize = mrts->mrts_mfcctlSize;
2199 			assert(IS_P2ALIGNED(vifctlSize,
2200 			    sizeof (struct vifclt *)));
2201 			assert(IS_P2ALIGNED(mfcctlSize,
2202 			    sizeof (struct mfcctl *)));
2203 			break;
2204 		}
2205 		case MIB2_IP6: {
2206 			mib2_ipv6IfStatsEntry_t *ip6;
2207 			/* Just use the first entry */
2208 
2209 			ip6 = (mib2_ipv6IfStatsEntry_t *)item->valp;
2210 			ipv6IfStatsEntrySize = ip6->ipv6IfStatsEntrySize;
2211 			ipv6AddrEntrySize = ip6->ipv6AddrEntrySize;
2212 			ipv6RouteEntrySize = ip6->ipv6RouteEntrySize;
2213 			ipv6NetToMediaEntrySize = ip6->ipv6NetToMediaEntrySize;
2214 			ipv6MemberEntrySize = ip6->ipv6MemberEntrySize;
2215 			ipv6GroupSourceEntrySize =
2216 			    ip6->ipv6GroupSourceEntrySize;
2217 			assert(IS_P2ALIGNED(ipv6IfStatsEntrySize,
2218 			    sizeof (mib2_ipv6IfStatsEntry_t *)));
2219 			assert(IS_P2ALIGNED(ipv6AddrEntrySize,
2220 			    sizeof (mib2_ipv6AddrEntry_t *)));
2221 			assert(IS_P2ALIGNED(ipv6RouteEntrySize,
2222 			    sizeof (mib2_ipv6RouteEntry_t *)));
2223 			assert(IS_P2ALIGNED(ipv6NetToMediaEntrySize,
2224 			    sizeof (mib2_ipv6NetToMediaEntry_t *)));
2225 			assert(IS_P2ALIGNED(ipv6MemberEntrySize,
2226 			    sizeof (ipv6_member_t *)));
2227 			assert(IS_P2ALIGNED(ipv6GroupSourceEntrySize,
2228 			    sizeof (ipv6_grpsrc_t *)));
2229 			break;
2230 		}
2231 		case MIB2_ICMP6: {
2232 			mib2_ipv6IfIcmpEntry_t *icmp6;
2233 			/* Just use the first entry */
2234 
2235 			icmp6 = (mib2_ipv6IfIcmpEntry_t *)item->valp;
2236 			ipv6IfIcmpEntrySize = icmp6->ipv6IfIcmpEntrySize;
2237 			assert(IS_P2ALIGNED(ipv6IfIcmpEntrySize,
2238 			    sizeof (mib2_ipv6IfIcmpEntry_t *)));
2239 			break;
2240 		}
2241 		case MIB2_TCP: {
2242 			mib2_tcp_t	*tcp = (mib2_tcp_t *)item->valp;
2243 
2244 			tcpConnEntrySize = tcp->tcpConnTableSize;
2245 			tcp6ConnEntrySize = tcp->tcp6ConnTableSize;
2246 			assert(IS_P2ALIGNED(tcpConnEntrySize,
2247 			    sizeof (mib2_tcpConnEntry_t *)));
2248 			assert(IS_P2ALIGNED(tcp6ConnEntrySize,
2249 			    sizeof (mib2_tcp6ConnEntry_t *)));
2250 			break;
2251 		}
2252 		case MIB2_UDP: {
2253 			mib2_udp_t	*udp = (mib2_udp_t *)item->valp;
2254 
2255 			udpEntrySize = udp->udpEntrySize;
2256 			udp6EntrySize = udp->udp6EntrySize;
2257 			assert(IS_P2ALIGNED(udpEntrySize,
2258 			    sizeof (mib2_udpEntry_t *)));
2259 			assert(IS_P2ALIGNED(udp6EntrySize,
2260 			    sizeof (mib2_udp6Entry_t *)));
2261 			break;
2262 		}
2263 		case MIB2_SCTP: {
2264 			mib2_sctp_t	*sctp = (mib2_sctp_t *)item->valp;
2265 
2266 			sctpEntrySize = sctp->sctpEntrySize;
2267 			sctpLocalEntrySize = sctp->sctpLocalEntrySize;
2268 			sctpRemoteEntrySize = sctp->sctpRemoteEntrySize;
2269 			break;
2270 		}
2271 		}
2272 	}
2273 
2274 	if (Xflag) {
2275 		(void) puts("mib_get_constants:");
2276 		(void) printf("\tipv6IfStatsEntrySize %d\n",
2277 		    ipv6IfStatsEntrySize);
2278 		(void) printf("\tipAddrEntrySize %d\n", ipAddrEntrySize);
2279 		(void) printf("\tipRouteEntrySize %d\n", ipRouteEntrySize);
2280 		(void) printf("\tipNetToMediaEntrySize %d\n",
2281 		    ipNetToMediaEntrySize);
2282 		(void) printf("\tipMemberEntrySize %d\n", ipMemberEntrySize);
2283 		(void) printf("\tipRouteAttributeSize %d\n",
2284 		    ipRouteAttributeSize);
2285 		(void) printf("\tvifctlSize %d\n", vifctlSize);
2286 		(void) printf("\tmfcctlSize %d\n", mfcctlSize);
2287 
2288 		(void) printf("\tipv6AddrEntrySize %d\n", ipv6AddrEntrySize);
2289 		(void) printf("\tipv6RouteEntrySize %d\n", ipv6RouteEntrySize);
2290 		(void) printf("\tipv6NetToMediaEntrySize %d\n",
2291 		    ipv6NetToMediaEntrySize);
2292 		(void) printf("\tipv6MemberEntrySize %d\n",
2293 		    ipv6MemberEntrySize);
2294 		(void) printf("\tipv6IfIcmpEntrySize %d\n",
2295 		    ipv6IfIcmpEntrySize);
2296 		(void) printf("\tipDestEntrySize %d\n", ipDestEntrySize);
2297 		(void) printf("\ttransportMLPSize %d\n", transportMLPSize);
2298 		(void) printf("\ttcpConnEntrySize %d\n", tcpConnEntrySize);
2299 		(void) printf("\ttcp6ConnEntrySize %d\n", tcp6ConnEntrySize);
2300 		(void) printf("\tudpEntrySize %d\n", udpEntrySize);
2301 		(void) printf("\tudp6EntrySize %d\n", udp6EntrySize);
2302 		(void) printf("\tsctpEntrySize %d\n", sctpEntrySize);
2303 		(void) printf("\tsctpLocalEntrySize %d\n", sctpLocalEntrySize);
2304 		(void) printf("\tsctpRemoteEntrySize %d\n",
2305 		    sctpRemoteEntrySize);
2306 	}
2307 }
2308 
2309 /* ----------------------------- STAT_REPORT ------------------------------- */
2310 
2311 static void
stat_report(mib_item_t * item)2312 stat_report(mib_item_t *item)
2313 {
2314 	int	jtemp = 0;
2315 	char	ifname[LIFNAMSIZ + 1];
2316 
2317 	for (; item; item = item->next_item) {
2318 		if (Xflag) {
2319 			(void) printf("[%4d] Group = %d, mib_id = %d, "
2320 			    "length = %d, valp = 0x%p\n",
2321 			    jtemp++, item->group, item->mib_id,
2322 			    item->length, item->valp);
2323 		}
2324 		if (item->mib_id != 0)
2325 			continue;
2326 
2327 		switch (item->group) {
2328 		case MIB2_IP: {
2329 			mib2_ip_t	*ip = (mib2_ip_t *)item->valp;
2330 
2331 			if (protocol_selected(IPPROTO_IP) &&
2332 			    family_selected(AF_INET)) {
2333 				(void) fputs(v4compat ? "\nIP" : "\nIPv4",
2334 				    stdout);
2335 				print_ip_stats(ip);
2336 			}
2337 			break;
2338 		}
2339 		case MIB2_ICMP: {
2340 			mib2_icmp_t	*icmp =
2341 			    (mib2_icmp_t *)item->valp;
2342 
2343 			if (protocol_selected(IPPROTO_ICMP) &&
2344 			    family_selected(AF_INET)) {
2345 				(void) fputs(v4compat ? "\nICMP" : "\nICMPv4",
2346 				    stdout);
2347 				print_icmp_stats(icmp);
2348 			}
2349 			break;
2350 		}
2351 		case MIB2_IP6: {
2352 			mib2_ipv6IfStatsEntry_t *ip6;
2353 			mib2_ipv6IfStatsEntry_t sum6;
2354 
2355 			if (!(protocol_selected(IPPROTO_IPV6)) ||
2356 			    !(family_selected(AF_INET6)))
2357 				break;
2358 			bzero(&sum6, sizeof (sum6));
2359 			for (ip6 = (mib2_ipv6IfStatsEntry_t *)item->valp;
2360 			    (char *)ip6 < (char *)item->valp + item->length;
2361 			    ip6 = (mib2_ipv6IfStatsEntry_t *)((char *)ip6 +
2362 			    ipv6IfStatsEntrySize)) {
2363 				if (ip6->ipv6IfIndex == 0) {
2364 					/*
2365 					 * The "unknown interface" ip6
2366 					 * mib. Just add to the sum.
2367 					 */
2368 					sum_ip6_stats(ip6, &sum6);
2369 					continue;
2370 				}
2371 				if (Aflag) {
2372 					(void) printf("\nIPv6 for %s\n",
2373 					    ifindex2str(ip6->ipv6IfIndex,
2374 					    ifname));
2375 					print_ip6_stats(ip6);
2376 				}
2377 				sum_ip6_stats(ip6, &sum6);
2378 			}
2379 			(void) fputs("\nIPv6", stdout);
2380 			print_ip6_stats(&sum6);
2381 			break;
2382 		}
2383 		case MIB2_ICMP6: {
2384 			mib2_ipv6IfIcmpEntry_t *icmp6;
2385 			mib2_ipv6IfIcmpEntry_t sum6;
2386 
2387 			if (!(protocol_selected(IPPROTO_ICMPV6)) ||
2388 			    !(family_selected(AF_INET6)))
2389 				break;
2390 			bzero(&sum6, sizeof (sum6));
2391 			for (icmp6 = (mib2_ipv6IfIcmpEntry_t *)item->valp;
2392 			    (char *)icmp6 < (char *)item->valp + item->length;
2393 			    icmp6 = (void *)((char *)icmp6 +
2394 			    ipv6IfIcmpEntrySize)) {
2395 				if (icmp6->ipv6IfIcmpIfIndex == 0) {
2396 					/*
2397 					 * The "unknown interface" icmp6
2398 					 * mib. Just add to the sum.
2399 					 */
2400 					sum_icmp6_stats(icmp6, &sum6);
2401 					continue;
2402 				}
2403 				if (Aflag) {
2404 					(void) printf("\nICMPv6 for %s\n",
2405 					    ifindex2str(
2406 					    icmp6->ipv6IfIcmpIfIndex, ifname));
2407 					print_icmp6_stats(icmp6);
2408 				}
2409 				sum_icmp6_stats(icmp6, &sum6);
2410 			}
2411 			(void) fputs("\nICMPv6", stdout);
2412 			print_icmp6_stats(&sum6);
2413 			break;
2414 		}
2415 		case MIB2_TCP: {
2416 			mib2_tcp_t	*tcp = (mib2_tcp_t *)item->valp;
2417 
2418 			if (protocol_selected(IPPROTO_TCP) &&
2419 			    (family_selected(AF_INET) ||
2420 			    family_selected(AF_INET6))) {
2421 				(void) fputs("\nTCP", stdout);
2422 				print_tcp_stats(tcp);
2423 			}
2424 			break;
2425 		}
2426 		case MIB2_UDP: {
2427 			mib2_udp_t	*udp = (mib2_udp_t *)item->valp;
2428 
2429 			if (protocol_selected(IPPROTO_UDP) &&
2430 			    (family_selected(AF_INET) ||
2431 			    family_selected(AF_INET6))) {
2432 				(void) fputs("\nUDP", stdout);
2433 				print_udp_stats(udp);
2434 			}
2435 			break;
2436 		}
2437 		case MIB2_SCTP: {
2438 			mib2_sctp_t	*sctp = (mib2_sctp_t *)item->valp;
2439 
2440 			if (protocol_selected(IPPROTO_SCTP) &&
2441 			    (family_selected(AF_INET) ||
2442 			    family_selected(AF_INET6))) {
2443 				(void) fputs("\nSCTP", stdout);
2444 				print_sctp_stats(sctp);
2445 			}
2446 			break;
2447 		}
2448 		case EXPER_RAWIP: {
2449 			mib2_rawip_t	*rawip =
2450 			    (mib2_rawip_t *)item->valp;
2451 
2452 			if (protocol_selected(IPPROTO_RAW) &&
2453 			    (family_selected(AF_INET) ||
2454 			    family_selected(AF_INET6))) {
2455 				(void) fputs("\nRAWIP", stdout);
2456 				print_rawip_stats(rawip);
2457 			}
2458 			break;
2459 		}
2460 		case EXPER_IGMP: {
2461 			struct igmpstat	*igps =
2462 			    (struct igmpstat *)item->valp;
2463 
2464 			if (protocol_selected(IPPROTO_IGMP) &&
2465 			    (family_selected(AF_INET))) {
2466 				(void) fputs("\nIGMP:\n", stdout);
2467 				print_igmp_stats(igps);
2468 			}
2469 			break;
2470 		}
2471 		}
2472 	}
2473 	(void) putchar('\n');
2474 	(void) fflush(stdout);
2475 }
2476 
2477 static void
print_ip_stats(mib2_ip_t * ip)2478 print_ip_stats(mib2_ip_t *ip)
2479 {
2480 	prval_init();
2481 	pr_int_val("ipForwarding",	ip->ipForwarding);
2482 	pr_int_val("ipDefaultTTL",	ip->ipDefaultTTL);
2483 	prval("ipInReceives",		ip->ipInReceives);
2484 	prval("ipInHdrErrors",		ip->ipInHdrErrors);
2485 	prval("ipInAddrErrors",		ip->ipInAddrErrors);
2486 	prval("ipInCksumErrs",		ip->ipInCksumErrs);
2487 	prval("ipForwDatagrams",	ip->ipForwDatagrams);
2488 	prval("ipForwProhibits",	ip->ipForwProhibits);
2489 	prval("ipInUnknownProtos",	ip->ipInUnknownProtos);
2490 	prval("ipInDiscards",		ip->ipInDiscards);
2491 	prval("ipInDelivers",		ip->ipInDelivers);
2492 	prval("ipOutRequests",		ip->ipOutRequests);
2493 	prval("ipOutDiscards",		ip->ipOutDiscards);
2494 	prval("ipOutNoRoutes",		ip->ipOutNoRoutes);
2495 	pr_int_val("ipReasmTimeout",	ip->ipReasmTimeout);
2496 	prval("ipReasmReqds",		ip->ipReasmReqds);
2497 	prval("ipReasmOKs",		ip->ipReasmOKs);
2498 	prval("ipReasmFails",		ip->ipReasmFails);
2499 	prval("ipReasmDuplicates",	ip->ipReasmDuplicates);
2500 	prval("ipReasmPartDups",	ip->ipReasmPartDups);
2501 	prval("ipFragOKs",		ip->ipFragOKs);
2502 	prval("ipFragFails",		ip->ipFragFails);
2503 	prval("ipFragCreates",		ip->ipFragCreates);
2504 	prval("ipRoutingDiscards",	ip->ipRoutingDiscards);
2505 
2506 	prval("tcpInErrs",		ip->tcpInErrs);
2507 	prval("udpNoPorts",		ip->udpNoPorts);
2508 	prval("udpInCksumErrs",		ip->udpInCksumErrs);
2509 	prval("udpInOverflows",		ip->udpInOverflows);
2510 	prval("rawipInOverflows",	ip->rawipInOverflows);
2511 	prval("ipsecInSucceeded",	ip->ipsecInSucceeded);
2512 	prval("ipsecInFailed",		ip->ipsecInFailed);
2513 	prval("ipInIPv6",		ip->ipInIPv6);
2514 	prval("ipOutIPv6",		ip->ipOutIPv6);
2515 	prval("ipOutSwitchIPv6",	ip->ipOutSwitchIPv6);
2516 	prval_end();
2517 }
2518 
2519 static void
print_icmp_stats(mib2_icmp_t * icmp)2520 print_icmp_stats(mib2_icmp_t *icmp)
2521 {
2522 	prval_init();
2523 	prval("icmpInMsgs",		icmp->icmpInMsgs);
2524 	prval("icmpInErrors",		icmp->icmpInErrors);
2525 	prval("icmpInCksumErrs",	icmp->icmpInCksumErrs);
2526 	prval("icmpInUnknowns",		icmp->icmpInUnknowns);
2527 	prval("icmpInDestUnreachs",	icmp->icmpInDestUnreachs);
2528 	prval("icmpInTimeExcds",	icmp->icmpInTimeExcds);
2529 	prval("icmpInParmProbs",	icmp->icmpInParmProbs);
2530 	prval("icmpInSrcQuenchs",	icmp->icmpInSrcQuenchs);
2531 	prval("icmpInRedirects",	icmp->icmpInRedirects);
2532 	prval("icmpInBadRedirects",	icmp->icmpInBadRedirects);
2533 	prval("icmpInEchos",		icmp->icmpInEchos);
2534 	prval("icmpInEchoReps",		icmp->icmpInEchoReps);
2535 	prval("icmpInTimestamps",	icmp->icmpInTimestamps);
2536 	prval("icmpInTimestampReps",	icmp->icmpInTimestampReps);
2537 	prval("icmpInAddrMasks",	icmp->icmpInAddrMasks);
2538 	prval("icmpInAddrMaskReps",	icmp->icmpInAddrMaskReps);
2539 	prval("icmpInFragNeeded",	icmp->icmpInFragNeeded);
2540 	prval("icmpOutMsgs",		icmp->icmpOutMsgs);
2541 	prval("icmpOutDrops",		icmp->icmpOutDrops);
2542 	prval("icmpOutErrors",		icmp->icmpOutErrors);
2543 	prval("icmpOutDestUnreachs",	icmp->icmpOutDestUnreachs);
2544 	prval("icmpOutTimeExcds",	icmp->icmpOutTimeExcds);
2545 	prval("icmpOutParmProbs",	icmp->icmpOutParmProbs);
2546 	prval("icmpOutSrcQuenchs",	icmp->icmpOutSrcQuenchs);
2547 	prval("icmpOutRedirects",	icmp->icmpOutRedirects);
2548 	prval("icmpOutEchos",		icmp->icmpOutEchos);
2549 	prval("icmpOutEchoReps",	icmp->icmpOutEchoReps);
2550 	prval("icmpOutTimestamps",	icmp->icmpOutTimestamps);
2551 	prval("icmpOutTimestampReps",	icmp->icmpOutTimestampReps);
2552 	prval("icmpOutAddrMasks",	icmp->icmpOutAddrMasks);
2553 	prval("icmpOutAddrMaskReps",	icmp->icmpOutAddrMaskReps);
2554 	prval("icmpOutFragNeeded",	icmp->icmpOutFragNeeded);
2555 	prval("icmpInOverflows",	icmp->icmpInOverflows);
2556 	prval_end();
2557 }
2558 
2559 static void
print_ip6_stats(mib2_ipv6IfStatsEntry_t * ip6)2560 print_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6)
2561 {
2562 	prval_init();
2563 	prval("ipv6Forwarding",		ip6->ipv6Forwarding);
2564 	prval("ipv6DefaultHopLimit",	ip6->ipv6DefaultHopLimit);
2565 
2566 	prval("ipv6InReceives",		ip6->ipv6InReceives);
2567 	prval("ipv6InHdrErrors",	ip6->ipv6InHdrErrors);
2568 	prval("ipv6InTooBigErrors",	ip6->ipv6InTooBigErrors);
2569 	prval("ipv6InNoRoutes",		ip6->ipv6InNoRoutes);
2570 	prval("ipv6InAddrErrors",	ip6->ipv6InAddrErrors);
2571 	prval("ipv6InUnknownProtos",	ip6->ipv6InUnknownProtos);
2572 	prval("ipv6InTruncatedPkts",	ip6->ipv6InTruncatedPkts);
2573 	prval("ipv6InDiscards",		ip6->ipv6InDiscards);
2574 	prval("ipv6InDelivers",		ip6->ipv6InDelivers);
2575 	prval("ipv6OutForwDatagrams",	ip6->ipv6OutForwDatagrams);
2576 	prval("ipv6OutRequests",	ip6->ipv6OutRequests);
2577 	prval("ipv6OutDiscards",	ip6->ipv6OutDiscards);
2578 	prval("ipv6OutNoRoutes",	ip6->ipv6OutNoRoutes);
2579 	prval("ipv6OutFragOKs",		ip6->ipv6OutFragOKs);
2580 	prval("ipv6OutFragFails",	ip6->ipv6OutFragFails);
2581 	prval("ipv6OutFragCreates",	ip6->ipv6OutFragCreates);
2582 	prval("ipv6ReasmReqds",		ip6->ipv6ReasmReqds);
2583 	prval("ipv6ReasmOKs",		ip6->ipv6ReasmOKs);
2584 	prval("ipv6ReasmFails",		ip6->ipv6ReasmFails);
2585 	prval("ipv6InMcastPkts",	ip6->ipv6InMcastPkts);
2586 	prval("ipv6OutMcastPkts",	ip6->ipv6OutMcastPkts);
2587 	prval("ipv6ReasmDuplicates",	ip6->ipv6ReasmDuplicates);
2588 	prval("ipv6ReasmPartDups",	ip6->ipv6ReasmPartDups);
2589 	prval("ipv6ForwProhibits",	ip6->ipv6ForwProhibits);
2590 	prval("udpInCksumErrs",		ip6->udpInCksumErrs);
2591 	prval("udpInOverflows",		ip6->udpInOverflows);
2592 	prval("rawipInOverflows",	ip6->rawipInOverflows);
2593 	prval("ipv6InIPv4",		ip6->ipv6InIPv4);
2594 	prval("ipv6OutIPv4",		ip6->ipv6OutIPv4);
2595 	prval("ipv6OutSwitchIPv4",	ip6->ipv6OutSwitchIPv4);
2596 	prval_end();
2597 }
2598 
2599 static void
print_icmp6_stats(mib2_ipv6IfIcmpEntry_t * icmp6)2600 print_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6)
2601 {
2602 	prval_init();
2603 	prval("icmp6InMsgs",		icmp6->ipv6IfIcmpInMsgs);
2604 	prval("icmp6InErrors",		icmp6->ipv6IfIcmpInErrors);
2605 	prval("icmp6InDestUnreachs",	icmp6->ipv6IfIcmpInDestUnreachs);
2606 	prval("icmp6InAdminProhibs",	icmp6->ipv6IfIcmpInAdminProhibs);
2607 	prval("icmp6InTimeExcds",	icmp6->ipv6IfIcmpInTimeExcds);
2608 	prval("icmp6InParmProblems",	icmp6->ipv6IfIcmpInParmProblems);
2609 	prval("icmp6InPktTooBigs",	icmp6->ipv6IfIcmpInPktTooBigs);
2610 	prval("icmp6InEchos",		icmp6->ipv6IfIcmpInEchos);
2611 	prval("icmp6InEchoReplies",	icmp6->ipv6IfIcmpInEchoReplies);
2612 	prval("icmp6InRouterSols",	icmp6->ipv6IfIcmpInRouterSolicits);
2613 	prval("icmp6InRouterAds",
2614 	    icmp6->ipv6IfIcmpInRouterAdvertisements);
2615 	prval("icmp6InNeighborSols",	icmp6->ipv6IfIcmpInNeighborSolicits);
2616 	prval("icmp6InNeighborAds",
2617 	    icmp6->ipv6IfIcmpInNeighborAdvertisements);
2618 	prval("icmp6InRedirects",	icmp6->ipv6IfIcmpInRedirects);
2619 	prval("icmp6InBadRedirects",	icmp6->ipv6IfIcmpInBadRedirects);
2620 	prval("icmp6InGroupQueries",	icmp6->ipv6IfIcmpInGroupMembQueries);
2621 	prval("icmp6InGroupResps",	icmp6->ipv6IfIcmpInGroupMembResponses);
2622 	prval("icmp6InGroupReds",	icmp6->ipv6IfIcmpInGroupMembReductions);
2623 	prval("icmp6InOverflows",	icmp6->ipv6IfIcmpInOverflows);
2624 	prval_end();
2625 	prval_init();
2626 	prval("icmp6OutMsgs",		icmp6->ipv6IfIcmpOutMsgs);
2627 	prval("icmp6OutErrors",		icmp6->ipv6IfIcmpOutErrors);
2628 	prval("icmp6OutDestUnreachs",	icmp6->ipv6IfIcmpOutDestUnreachs);
2629 	prval("icmp6OutAdminProhibs",	icmp6->ipv6IfIcmpOutAdminProhibs);
2630 	prval("icmp6OutTimeExcds",	icmp6->ipv6IfIcmpOutTimeExcds);
2631 	prval("icmp6OutParmProblems",	icmp6->ipv6IfIcmpOutParmProblems);
2632 	prval("icmp6OutPktTooBigs",	icmp6->ipv6IfIcmpOutPktTooBigs);
2633 	prval("icmp6OutEchos",		icmp6->ipv6IfIcmpOutEchos);
2634 	prval("icmp6OutEchoReplies",	icmp6->ipv6IfIcmpOutEchoReplies);
2635 	prval("icmp6OutRouterSols",	icmp6->ipv6IfIcmpOutRouterSolicits);
2636 	prval("icmp6OutRouterAds",
2637 	    icmp6->ipv6IfIcmpOutRouterAdvertisements);
2638 	prval("icmp6OutNeighborSols",	icmp6->ipv6IfIcmpOutNeighborSolicits);
2639 	prval("icmp6OutNeighborAds",
2640 	    icmp6->ipv6IfIcmpOutNeighborAdvertisements);
2641 	prval("icmp6OutRedirects",	icmp6->ipv6IfIcmpOutRedirects);
2642 	prval("icmp6OutGroupQueries",	icmp6->ipv6IfIcmpOutGroupMembQueries);
2643 	prval("icmp6OutGroupResps",
2644 	    icmp6->ipv6IfIcmpOutGroupMembResponses);
2645 	prval("icmp6OutGroupReds",
2646 	    icmp6->ipv6IfIcmpOutGroupMembReductions);
2647 	prval_end();
2648 }
2649 
2650 static void
print_sctp_stats(mib2_sctp_t * sctp)2651 print_sctp_stats(mib2_sctp_t *sctp)
2652 {
2653 	prval_init();
2654 	pr_sctp_rtoalgo("sctpRtoAlgorithm", sctp->sctpRtoAlgorithm);
2655 	prval("sctpRtoMin",		sctp->sctpRtoMin);
2656 	prval("sctpRtoMax",		sctp->sctpRtoMax);
2657 	prval("sctpRtoInitial",		sctp->sctpRtoInitial);
2658 	pr_int_val("sctpMaxAssocs",	sctp->sctpMaxAssocs);
2659 	prval("sctpValCookieLife",	sctp->sctpValCookieLife);
2660 	prval("sctpMaxInitRetr",	sctp->sctpMaxInitRetr);
2661 	prval("sctpCurrEstab",		sctp->sctpCurrEstab);
2662 	prval("sctpActiveEstab",	sctp->sctpActiveEstab);
2663 	prval("sctpPassiveEstab",	sctp->sctpPassiveEstab);
2664 	prval("sctpAborted",		sctp->sctpAborted);
2665 	prval("sctpShutdowns",		sctp->sctpShutdowns);
2666 	prval("sctpOutOfBlue",		sctp->sctpOutOfBlue);
2667 	prval("sctpChecksumError",	sctp->sctpChecksumError);
2668 	prval64("sctpOutCtrlChunks",	sctp->sctpOutCtrlChunks);
2669 	prval64("sctpOutOrderChunks",	sctp->sctpOutOrderChunks);
2670 	prval64("sctpOutUnorderChunks",	sctp->sctpOutUnorderChunks);
2671 	prval64("sctpRetransChunks",	sctp->sctpRetransChunks);
2672 	prval("sctpOutAck",		sctp->sctpOutAck);
2673 	prval("sctpOutAckDelayed",	sctp->sctpOutAckDelayed);
2674 	prval("sctpOutWinUpdate",	sctp->sctpOutWinUpdate);
2675 	prval("sctpOutFastRetrans",	sctp->sctpOutFastRetrans);
2676 	prval("sctpOutWinProbe",	sctp->sctpOutWinProbe);
2677 	prval64("sctpInCtrlChunks",	sctp->sctpInCtrlChunks);
2678 	prval64("sctpInOrderChunks",	sctp->sctpInOrderChunks);
2679 	prval64("sctpInUnorderChunks",	sctp->sctpInUnorderChunks);
2680 	prval("sctpInAck",		sctp->sctpInAck);
2681 	prval("sctpInDupAck",		sctp->sctpInDupAck);
2682 	prval("sctpInAckUnsent",	sctp->sctpInAckUnsent);
2683 	prval64("sctpFragUsrMsgs",	sctp->sctpFragUsrMsgs);
2684 	prval64("sctpReasmUsrMsgs",	sctp->sctpReasmUsrMsgs);
2685 	prval64("sctpOutSCTPPkts",	sctp->sctpOutSCTPPkts);
2686 	prval64("sctpInSCTPPkts",	sctp->sctpInSCTPPkts);
2687 	prval("sctpInInvalidCookie",	sctp->sctpInInvalidCookie);
2688 	prval("sctpTimRetrans",		sctp->sctpTimRetrans);
2689 	prval("sctpTimRetransDrop",	sctp->sctpTimRetransDrop);
2690 	prval("sctpTimHearBeatProbe",	sctp->sctpTimHeartBeatProbe);
2691 	prval("sctpTimHearBeatDrop",	sctp->sctpTimHeartBeatDrop);
2692 	prval("sctpListenDrop",		sctp->sctpListenDrop);
2693 	prval("sctpInClosed",		sctp->sctpInClosed);
2694 	prval_end();
2695 }
2696 
2697 static void
print_tcp_stats(mib2_tcp_t * tcp)2698 print_tcp_stats(mib2_tcp_t *tcp)
2699 {
2700 	prval_init();
2701 	pr_int_val("tcpRtoAlgorithm",	tcp->tcpRtoAlgorithm);
2702 	pr_int_val("tcpRtoMin",		tcp->tcpRtoMin);
2703 	pr_int_val("tcpRtoMax",		tcp->tcpRtoMax);
2704 	pr_int_val("tcpMaxConn",	tcp->tcpMaxConn);
2705 	prval("tcpActiveOpens",		tcp->tcpActiveOpens);
2706 	prval("tcpPassiveOpens",	tcp->tcpPassiveOpens);
2707 	prval("tcpAttemptFails",	tcp->tcpAttemptFails);
2708 	prval("tcpEstabResets",		tcp->tcpEstabResets);
2709 	prval("tcpCurrEstab",		tcp->tcpCurrEstab);
2710 	prval64("tcpOutSegs",		tcp->tcpHCOutSegs);
2711 	prval("tcpOutDataSegs",		tcp->tcpOutDataSegs);
2712 	prval("tcpOutDataBytes",	tcp->tcpOutDataBytes);
2713 	prval("tcpRetransSegs",		tcp->tcpRetransSegs);
2714 	prval("tcpRetransBytes",	tcp->tcpRetransBytes);
2715 	prval("tcpOutAck",		tcp->tcpOutAck);
2716 	prval("tcpOutAckDelayed",	tcp->tcpOutAckDelayed);
2717 	prval("tcpOutUrg",		tcp->tcpOutUrg);
2718 	prval("tcpOutWinUpdate",	tcp->tcpOutWinUpdate);
2719 	prval("tcpOutWinProbe",		tcp->tcpOutWinProbe);
2720 	prval("tcpOutControl",		tcp->tcpOutControl);
2721 	prval("tcpOutRsts",		tcp->tcpOutRsts);
2722 	prval("tcpOutFastRetrans",	tcp->tcpOutFastRetrans);
2723 	prval64("tcpInSegs",		tcp->tcpHCInSegs);
2724 	prval_end();
2725 	prval("tcpInAckSegs",		tcp->tcpInAckSegs);
2726 	prval("tcpInAckBytes",		tcp->tcpInAckBytes);
2727 	prval("tcpInDupAck",		tcp->tcpInDupAck);
2728 	prval("tcpInAckUnsent",		tcp->tcpInAckUnsent);
2729 	prval("tcpInInorderSegs",	tcp->tcpInDataInorderSegs);
2730 	prval("tcpInInorderBytes",	tcp->tcpInDataInorderBytes);
2731 	prval("tcpInUnorderSegs",	tcp->tcpInDataUnorderSegs);
2732 	prval("tcpInUnorderBytes",	tcp->tcpInDataUnorderBytes);
2733 	prval("tcpInDupSegs",		tcp->tcpInDataDupSegs);
2734 	prval("tcpInDupBytes",		tcp->tcpInDataDupBytes);
2735 	prval("tcpInPartDupSegs",	tcp->tcpInDataPartDupSegs);
2736 	prval("tcpInPartDupBytes",	tcp->tcpInDataPartDupBytes);
2737 	prval("tcpInPastWinSegs",	tcp->tcpInDataPastWinSegs);
2738 	prval("tcpInPastWinBytes",	tcp->tcpInDataPastWinBytes);
2739 	prval("tcpInWinProbe",		tcp->tcpInWinProbe);
2740 	prval("tcpInWinUpdate",		tcp->tcpInWinUpdate);
2741 	prval("tcpInClosed",		tcp->tcpInClosed);
2742 	prval("tcpRttNoUpdate",		tcp->tcpRttNoUpdate);
2743 	prval("tcpRttUpdate",		tcp->tcpRttUpdate);
2744 	prval("tcpTimRetrans",		tcp->tcpTimRetrans);
2745 	prval("tcpTimRetransDrop",	tcp->tcpTimRetransDrop);
2746 	prval("tcpTimKeepalive",	tcp->tcpTimKeepalive);
2747 	prval("tcpTimKeepaliveProbe",	tcp->tcpTimKeepaliveProbe);
2748 	prval("tcpTimKeepaliveDrop",	tcp->tcpTimKeepaliveDrop);
2749 	prval("tcpListenDrop",		tcp->tcpListenDrop);
2750 	prval("tcpListenDropQ0",	tcp->tcpListenDropQ0);
2751 	prval("tcpHalfOpenDrop",	tcp->tcpHalfOpenDrop);
2752 	prval("tcpOutSackRetrans",	tcp->tcpOutSackRetransSegs);
2753 	prval_end();
2754 
2755 }
2756 
2757 static void
print_udp_stats(mib2_udp_t * udp)2758 print_udp_stats(mib2_udp_t *udp)
2759 {
2760 	prval_init();
2761 	prval64("udpInDatagrams",	udp->udpHCInDatagrams);
2762 	prval("udpInErrors",		udp->udpInErrors);
2763 	prval64("udpOutDatagrams",	udp->udpHCOutDatagrams);
2764 	prval("udpOutErrors",		udp->udpOutErrors);
2765 	prval_end();
2766 }
2767 
2768 static void
print_rawip_stats(mib2_rawip_t * rawip)2769 print_rawip_stats(mib2_rawip_t *rawip)
2770 {
2771 	prval_init();
2772 	prval("rawipInDatagrams",	rawip->rawipInDatagrams);
2773 	prval("rawipInErrors",		rawip->rawipInErrors);
2774 	prval("rawipInCksumErrs",	rawip->rawipInCksumErrs);
2775 	prval("rawipOutDatagrams",	rawip->rawipOutDatagrams);
2776 	prval("rawipOutErrors",		rawip->rawipOutErrors);
2777 	prval_end();
2778 }
2779 
2780 void
print_igmp_stats(struct igmpstat * igps)2781 print_igmp_stats(struct igmpstat *igps)
2782 {
2783 	(void) printf(" %10u message%s received\n",
2784 	    igps->igps_rcv_total, PLURAL(igps->igps_rcv_total));
2785 	(void) printf(" %10u message%s received with too few bytes\n",
2786 	    igps->igps_rcv_tooshort, PLURAL(igps->igps_rcv_tooshort));
2787 	(void) printf(" %10u message%s received with bad checksum\n",
2788 	    igps->igps_rcv_badsum, PLURAL(igps->igps_rcv_badsum));
2789 	(void) printf(" %10u membership quer%s received\n",
2790 	    igps->igps_rcv_queries, PLURALY(igps->igps_rcv_queries));
2791 	(void) printf(" %10u membership quer%s received with invalid "
2792 	    "field(s)\n",
2793 	    igps->igps_rcv_badqueries, PLURALY(igps->igps_rcv_badqueries));
2794 	(void) printf(" %10u membership report%s received\n",
2795 	    igps->igps_rcv_reports, PLURAL(igps->igps_rcv_reports));
2796 	(void) printf(" %10u membership report%s received with invalid "
2797 	    "field(s)\n",
2798 	    igps->igps_rcv_badreports, PLURAL(igps->igps_rcv_badreports));
2799 	(void) printf(" %10u membership report%s received for groups to "
2800 	    "which we belong\n",
2801 	    igps->igps_rcv_ourreports, PLURAL(igps->igps_rcv_ourreports));
2802 	(void) printf(" %10u membership report%s sent\n",
2803 	    igps->igps_snd_reports, PLURAL(igps->igps_snd_reports));
2804 }
2805 
2806 static void
print_mrt_stats(struct mrtstat * mrts)2807 print_mrt_stats(struct mrtstat *mrts)
2808 {
2809 	(void) puts("DVMRP multicast routing:");
2810 	(void) printf(" %10u hit%s - kernel forwarding cache hits\n",
2811 	    mrts->mrts_mfc_hits, PLURAL(mrts->mrts_mfc_hits));
2812 	(void) printf(" %10u miss%s - kernel forwarding cache misses\n",
2813 	    mrts->mrts_mfc_misses, PLURALES(mrts->mrts_mfc_misses));
2814 	(void) printf(" %10u packet%s potentially forwarded\n",
2815 	    mrts->mrts_fwd_in, PLURAL(mrts->mrts_fwd_in));
2816 	(void) printf(" %10u packet%s actually sent out\n",
2817 	    mrts->mrts_fwd_out, PLURAL(mrts->mrts_fwd_out));
2818 	(void) printf(" %10u upcall%s - upcalls made to mrouted\n",
2819 	    mrts->mrts_upcalls, PLURAL(mrts->mrts_upcalls));
2820 	(void) printf(" %10u packet%s not sent out due to lack of resources\n",
2821 	    mrts->mrts_fwd_drop, PLURAL(mrts->mrts_fwd_drop));
2822 	(void) printf(" %10u datagram%s with malformed tunnel options\n",
2823 	    mrts->mrts_bad_tunnel, PLURAL(mrts->mrts_bad_tunnel));
2824 	(void) printf(" %10u datagram%s with no room for tunnel options\n",
2825 	    mrts->mrts_cant_tunnel, PLURAL(mrts->mrts_cant_tunnel));
2826 	(void) printf(" %10u datagram%s arrived on wrong interface\n",
2827 	    mrts->mrts_wrong_if, PLURAL(mrts->mrts_wrong_if));
2828 	(void) printf(" %10u datagram%s dropped due to upcall Q overflow\n",
2829 	    mrts->mrts_upq_ovflw, PLURAL(mrts->mrts_upq_ovflw));
2830 	(void) printf(" %10u datagram%s cleaned up by the cache\n",
2831 	    mrts->mrts_cache_cleanups, PLURAL(mrts->mrts_cache_cleanups));
2832 	(void) printf(" %10u datagram%s dropped selectively by ratelimiter\n",
2833 	    mrts->mrts_drop_sel, PLURAL(mrts->mrts_drop_sel));
2834 	(void) printf(" %10u datagram%s dropped - bucket Q overflow\n",
2835 	    mrts->mrts_q_overflow, PLURAL(mrts->mrts_q_overflow));
2836 	(void) printf(" %10u datagram%s dropped - larger than bkt size\n",
2837 	    mrts->mrts_pkt2large, PLURAL(mrts->mrts_pkt2large));
2838 	(void) printf("\nPIM multicast routing:\n");
2839 	(void) printf(" %10u datagram%s dropped - bad version number\n",
2840 	    mrts->mrts_pim_badversion, PLURAL(mrts->mrts_pim_badversion));
2841 	(void) printf(" %10u datagram%s dropped - bad checksum\n",
2842 	    mrts->mrts_pim_rcv_badcsum, PLURAL(mrts->mrts_pim_rcv_badcsum));
2843 	(void) printf(" %10u datagram%s dropped - bad register packets\n",
2844 	    mrts->mrts_pim_badregisters, PLURAL(mrts->mrts_pim_badregisters));
2845 	(void) printf(
2846 	    " %10u datagram%s potentially forwarded - register packets\n",
2847 	    mrts->mrts_pim_regforwards, PLURAL(mrts->mrts_pim_regforwards));
2848 	(void) printf(" %10u datagram%s dropped - register send drops\n",
2849 	    mrts->mrts_pim_regsend_drops, PLURAL(mrts->mrts_pim_regsend_drops));
2850 	(void) printf(" %10u datagram%s dropped - packet malformed\n",
2851 	    mrts->mrts_pim_malformed, PLURAL(mrts->mrts_pim_malformed));
2852 	(void) printf(" %10u datagram%s dropped - no memory to forward\n",
2853 	    mrts->mrts_pim_nomemory, PLURAL(mrts->mrts_pim_nomemory));
2854 }
2855 
2856 static void
sum_ip6_stats(mib2_ipv6IfStatsEntry_t * ip6,mib2_ipv6IfStatsEntry_t * sum6)2857 sum_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6, mib2_ipv6IfStatsEntry_t *sum6)
2858 {
2859 	/* First few are not additive */
2860 	sum6->ipv6Forwarding = ip6->ipv6Forwarding;
2861 	sum6->ipv6DefaultHopLimit = ip6->ipv6DefaultHopLimit;
2862 
2863 	sum6->ipv6InReceives += ip6->ipv6InReceives;
2864 	sum6->ipv6InHdrErrors += ip6->ipv6InHdrErrors;
2865 	sum6->ipv6InTooBigErrors += ip6->ipv6InTooBigErrors;
2866 	sum6->ipv6InNoRoutes += ip6->ipv6InNoRoutes;
2867 	sum6->ipv6InAddrErrors += ip6->ipv6InAddrErrors;
2868 	sum6->ipv6InUnknownProtos += ip6->ipv6InUnknownProtos;
2869 	sum6->ipv6InTruncatedPkts += ip6->ipv6InTruncatedPkts;
2870 	sum6->ipv6InDiscards += ip6->ipv6InDiscards;
2871 	sum6->ipv6InDelivers += ip6->ipv6InDelivers;
2872 	sum6->ipv6OutForwDatagrams += ip6->ipv6OutForwDatagrams;
2873 	sum6->ipv6OutRequests += ip6->ipv6OutRequests;
2874 	sum6->ipv6OutDiscards += ip6->ipv6OutDiscards;
2875 	sum6->ipv6OutFragOKs += ip6->ipv6OutFragOKs;
2876 	sum6->ipv6OutFragFails += ip6->ipv6OutFragFails;
2877 	sum6->ipv6OutFragCreates +=