summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c')
-rw-r--r--usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c5950
1 files changed, 5950 insertions, 0 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c b/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
new file mode 100644
index 0000000000..f978ae489e
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.bin/netstat/netstat.c
@@ -0,0 +1,5950 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright (c) 1990 Mentat Inc.
+ * netstat.c 2.2, last change 9/9/91
+ * MROUTING Revision 3.5
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * simple netstat based on snmp/mib-2 interface to the TCP/IP stack
+ *
+ * NOTES:
+ * 1. A comment "LINTED: (note 1)" appears before certain lines where
+ * lint would have complained, "pointer cast may result in improper
+ * alignment". These are lines where lint had suspected potential
+ * improper alignment of a data structure; in each such situation
+ * we have relied on the kernel guaranteeing proper alignment.
+ * 2. Some 'for' loops have been commented as "'for' loop 1", etc
+ * because they have 'continue' or 'break' statements in their
+ * bodies. 'continue' statements have been used inside some loops
+ * where avoiding them would have led to deep levels of indentation.
+ *
+ * TODO:
+ * Add ability to request subsets from kernel (with level = MIB2_IP;
+ * name = 0 meaning everything for compatibility)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <strings.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <kstat.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <stropts.h>
+#include <sys/strstat.h>
+#include <sys/sysmacros.h>
+#include <sys/tihdr.h>
+
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <net/route.h>
+
+#include <inet/common.h>
+#include <inet/mib2.h>
+#include <inet/ip.h>
+#include <inet/arp.h>
+#include <inet/tcp.h>
+#include <netinet/igmp_var.h>
+#include <netinet/ip_mroute.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <sys/systeminfo.h>
+#include <arpa/inet.h>
+
+#include <netinet/dhcp.h>
+#include <dhcpagent_ipc.h>
+#include <dhcpagent_util.h>
+#include <compat.h>
+
+extern void unixpr(kstat_ctl_t *kc);
+extern void setifdhcp(const char *caller, const char *ifname,
+ int argc, char *argv[]);
+
+#define STR_EXPAND 4
+
+#define V4MASK_TO_V6(v4, v6) ((v6)._S6_un._S6_u32[0] = 0xfffffffful, \
+ (v6)._S6_un._S6_u32[1] = 0xfffffffful, \
+ (v6)._S6_un._S6_u32[2] = 0xfffffffful, \
+ (v6)._S6_un._S6_u32[3] = (v4))
+
+#define IN6_IS_V4MASK(v6) ((v6)._S6_un._S6_u32[0] == 0xfffffffful && \
+ (v6)._S6_un._S6_u32[1] == 0xfffffffful && \
+ (v6)._S6_un._S6_u32[2] == 0xfffffffful)
+
+typedef struct mib_item_s {
+ struct mib_item_s *next_item;
+ int group;
+ int mib_id;
+ int length;
+ void *valp;
+} mib_item_t;
+
+struct ifstat {
+ uint64_t ipackets;
+ uint64_t ierrors;
+ uint64_t opackets;
+ uint64_t oerrors;
+ uint64_t collisions;
+};
+
+struct iflist {
+ struct iflist *next_if;
+ char ifname[LIFNAMSIZ];
+ struct ifstat tot;
+};
+
+static mib_item_t *mibget(int sd);
+static void mibfree(mib_item_t *firstitem);
+static int mibopen(void);
+static void mib_get_constants(mib_item_t *item);
+static mib_item_t *mib_item_dup(mib_item_t *item);
+static mib_item_t *mib_item_diff(mib_item_t *item1,
+ mib_item_t *item2);
+static void mib_item_destroy(mib_item_t **item);
+
+static boolean_t octetstrmatch(const Octet_t *a, const Octet_t *b);
+static char *octetstr(Octet_t *op, int code,
+ char *dst, uint_t dstlen);
+static char *pr_addr(uint_t addr,
+ char *dst, uint_t dstlen);
+static char *pr_addrnz(ipaddr_t addr, char *dst, uint_t dstlen);
+static char *pr_addr6(const in6_addr_t *addr,
+ char *dst, uint_t dstlen);
+static char *pr_mask(uint_t addr,
+ char *dst, uint_t dstlen);
+static char *pr_prefix6(struct in6_addr *addr, uint_t prefixlen,
+ char *dst, uint_t dstlen);
+static char *pr_ap(uint_t addr, uint_t port,
+ char *proto, char *dst, uint_t dstlen);
+static char *pr_ap6(const in6_addr_t *addr, uint_t port,
+ char *proto, char *dst, uint_t dstlen);
+static char *pr_net(uint_t addr, uint_t mask,
+ char *dst, uint_t dstlen);
+static char *pr_netaddr(uint_t addr, uint_t mask,
+ char *dst, uint_t dstlen);
+static char *pr_netclassless(ipaddr_t addr, ipaddr_t mask,
+ char *dst, size_t dstlen);
+static char *fmodestr(uint_t fmode);
+static char *portname(uint_t port, char *proto,
+ char *dst, uint_t dstlen);
+
+static char *mitcp_state(int code);
+
+static void stat_report(mib_item_t *item);
+static void mrt_stat_report(mib_item_t *item);
+static void arp_report(mib_item_t *item);
+static void ndp_report(mib_item_t *item);
+static void mrt_report(mib_item_t *item);
+static void if_stat_total(struct ifstat *oldstats,
+ struct ifstat *newstats, struct ifstat *sumstats);
+static void if_report(mib_item_t *item, char *ifname,
+ int Iflag_only, boolean_t once_only);
+static void if_report_ip4(mib2_ipAddrEntry_t *ap,
+ char ifname[], char logintname[],
+ struct ifstat *statptr, boolean_t ksp_not_null);
+static void if_report_ip6(mib2_ipv6AddrEntry_t *ap6,
+ char ifname[], char logintname[],
+ struct ifstat *statptr, boolean_t ksp_not_null);
+static void ire_report(mib_item_t *item);
+static void tcp_report(mib_item_t *item);
+static void udp_report(mib_item_t *item);
+static void group_report(mib_item_t *item);
+static void print_ip_stats(mib2_ip_t *ip);
+static void print_icmp_stats(mib2_icmp_t *icmp);
+static void print_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6);
+static void print_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6);
+static void print_sctp_stats(mib2_sctp_t *tcp);
+static void print_tcp_stats(mib2_tcp_t *tcp);
+static void print_udp_stats(mib2_udp_t *udp);
+static void print_rawip_stats(mib2_rawip_t *rawip);
+static void print_igmp_stats(struct igmpstat *igps);
+static void print_mrt_stats(struct mrtstat *mrts);
+static void sctp_report(mib_item_t *item);
+static void sum_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6,
+ mib2_ipv6IfStatsEntry_t *sum6);
+static void sum_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6,
+ mib2_ipv6IfIcmpEntry_t *sum6);
+static void m_report(void);
+static void dhcp_report(char *);
+
+ void fail(int, char *, ...);
+static uint64_t kstat_named_value(kstat_t *, char *);
+static kid_t safe_kstat_read(kstat_ctl_t *, kstat_t *, void *);
+static int isnum(char *);
+static char *plural(int n);
+static char *pluraly(int n);
+static char *plurales(int n);
+static void process_filter(char *arg);
+static boolean_t family_selected(int family);
+
+static void usage(char *);
+static void fatal(int errcode, char *str1, ...);
+
+#define PLURAL(n) plural((int)n)
+#define PLURALY(n) pluraly((int)n)
+#define PLURALES(n) plurales((int)n)
+#define IFLAGMOD(flg, val1, val2) if (flg == val1) flg = val2
+#define MDIFF(diff, elem2, elem1, member) (diff)->member = \
+ (elem2)->member - (elem1)->member
+
+
+static boolean_t Aflag = B_FALSE; /* All sockets/ifs/rtng-tbls */
+static boolean_t Dflag = B_FALSE; /* Debug Info */
+static boolean_t Iflag = B_FALSE; /* IP Traffic Interfaces */
+static boolean_t Mflag = B_FALSE; /* STREAMS Memory Statistics */
+static boolean_t Nflag = B_FALSE; /* Numeric Network Addresses */
+static boolean_t Rflag = B_FALSE; /* Routing Tables */
+static boolean_t Sflag = B_FALSE; /* Per-protocol Statistics */
+static boolean_t Vflag = B_FALSE; /* Verbose */
+static boolean_t Pflag = B_FALSE; /* Net to Media Tables */
+static boolean_t Gflag = B_FALSE; /* Multicast group membership */
+static boolean_t MMflag = B_FALSE; /* Multicast routing table */
+static boolean_t DHCPflag = B_FALSE; /* DHCP statistics */
+
+static int v4compat = 0; /* Compatible printing format for status */
+
+static int proto = IPPROTO_MAX; /* all protocols */
+kstat_ctl_t *kc = NULL;
+
+/*
+ * Sizes of data structures extracted from the base mib.
+ * This allows the size of the tables entries to grow while preserving
+ * binary compatibility.
+ */
+static int ipAddrEntrySize;
+static int ipRouteEntrySize;
+static int ipNetToMediaEntrySize;
+static int ipMemberEntrySize;
+static int ipGroupSourceEntrySize;
+static int vifctlSize;
+static int mfcctlSize;
+
+static int ipv6IfStatsEntrySize;
+static int ipv6IfIcmpEntrySize;
+static int ipv6AddrEntrySize;
+static int ipv6RouteEntrySize;
+static int ipv6NetToMediaEntrySize;
+static int ipv6MemberEntrySize;
+static int ipv6GroupSourceEntrySize;
+
+static int tcpConnEntrySize;
+static int tcp6ConnEntrySize;
+static int udpEntrySize;
+static int udp6EntrySize;
+static int sctpEntrySize;
+static int sctpLocalEntrySize;
+static int sctpRemoteEntrySize;
+
+#define protocol_selected(p) (proto == IPPROTO_MAX || proto == (p))
+
+/* Machinery used for -f (filter) option */
+#define FK_AF 0
+#define FK_INIF 1
+#define FK_OUTIF 2
+#define FK_SRC 3
+#define FK_DST 4
+#define FK_FLAGS 5
+#define NFILTERKEYS 6
+
+static const char *filter_keys[NFILTERKEYS] = {
+ "af", "inif", "outif", "src", "dst", "flags"
+};
+
+/* Flags on routes */
+#define FLF_A 0x00000001
+#define FLF_B 0x00000002
+#define FLF_D 0x00000004
+#define FLF_G 0x00000008
+#define FLF_H 0x00000010
+#define FLF_L 0x00000020
+#define FLF_U 0x00000040
+#define FLF_M 0x00000080
+#define FLF_S 0x00000100
+static const char flag_list[] = "ABDGHLUMS";
+
+typedef struct filter_rule filter_t;
+
+struct filter_rule {
+ filter_t *f_next;
+ union {
+ int f_family;
+ const char *f_ifname;
+ struct {
+ struct hostent *f_address;
+ in6_addr_t f_mask;
+ } a;
+ struct {
+ uint_t f_flagset;
+ uint_t f_flagclear;
+ } f;
+ } u;
+};
+
+/*
+ * The user-specified filters are linked into lists separated by
+ * keyword (type of filter). Thus, the matching algorithm is:
+ * For each non-empty filter list
+ * If no filters in the list match
+ * then stop here; route doesn't match
+ * If loop above completes, then route does match and will be
+ * displayed.
+ */
+static filter_t *filters[NFILTERKEYS];
+
+int
+main(int argc, char **argv)
+{
+ char *name;
+ mib_item_t *item = NULL;
+ mib_item_t *previtem = NULL;
+ int sd = -1;
+ char *ifname = NULL;
+ int interval = 0; /* Single time by default */
+ int count = -1; /* Forever */
+ int c;
+ int d;
+ /*
+ * Possible values of 'Iflag_only':
+ * -1, no feature-flags;
+ * 0, IFlag and other feature-flags enabled
+ * 1, IFlag is the only feature-flag enabled
+ * : trinary variable, modified using IFLAGMOD()
+ */
+ int Iflag_only = -1;
+ boolean_t once_only = B_FALSE; /* '-i' with count > 1 */
+ extern char *optarg;
+ extern int optind;
+ char *default_ip_str = NULL;
+
+ name = argv[0];
+
+ v4compat = get_compat_flag(&default_ip_str);
+ if (v4compat == DEFAULT_PROT_BAD_VALUE)
+ fatal(2, "%s: %s: Bad value for %s in %s\n", name,
+ default_ip_str, DEFAULT_IP, INET_DEFAULT_FILE);
+ free(default_ip_str);
+
+ while ((c = getopt(argc, argv, "adimnrspMgvf:P:I:D")) != -1) {
+ switch ((char)c) {
+ case 'a': /* all connections */
+ Aflag = B_TRUE;
+ break;
+
+ case 'd': /* turn on debugging */
+ Dflag = B_TRUE;
+ break;
+
+ case 'i': /* interface (ill/ipif report) */
+ Iflag = B_TRUE;
+ IFLAGMOD(Iflag_only, -1, 1); /* '-i' exists */
+ break;
+
+ case 'm': /* streams msg report */
+ Mflag = B_TRUE;
+ IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
+ break;
+
+ case 'n': /* numeric format */
+ Nflag = B_TRUE;
+ break;
+
+ case 'r': /* route tables */
+ Rflag = B_TRUE;
+ IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
+ break;
+
+ case 's': /* per-protocol statistics */
+ Sflag = B_TRUE;
+ IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
+ break;
+
+ case 'p': /* arp/ndp table */
+ Pflag = B_TRUE;
+ IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
+ break;
+
+ case 'M': /* multicast routing tables */
+ MMflag = B_TRUE;
+ IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
+ break;
+
+ case 'g': /* multicast group membership */
+ Gflag = B_TRUE;
+ IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
+ break;
+
+ case 'v': /* verbose output format */
+ Vflag = B_TRUE;
+ IFLAGMOD(Iflag_only, 1, 0); /* see macro def'n */
+ break;
+
+ case 'f':
+ process_filter(optarg);
+ break;
+
+ case 'P':
+ if (strcmp(optarg, "ip") == 0) {
+ proto = IPPROTO_IP;
+ } else if (strcmp(optarg, "ipv6") == 0 ||
+ strcmp(optarg, "ip6") == 0) {
+ v4compat = 0; /* Overridden */
+ proto = IPPROTO_IPV6;
+ } else if (strcmp(optarg, "icmp") == 0) {
+ proto = IPPROTO_ICMP;
+ } else if (strcmp(optarg, "icmpv6") == 0 ||
+ strcmp(optarg, "icmp6") == 0) {
+ v4compat = 0; /* Overridden */
+ proto = IPPROTO_ICMPV6;
+ } else if (strcmp(optarg, "igmp") == 0) {
+ proto = IPPROTO_IGMP;
+ } else if (strcmp(optarg, "udp") == 0) {
+ proto = IPPROTO_UDP;
+ } else if (strcmp(optarg, "tcp") == 0) {
+ proto = IPPROTO_TCP;
+ } else if (strcmp(optarg, "sctp") == 0) {
+ proto = IPPROTO_SCTP;
+ } else if (strcmp(optarg, "raw") == 0 ||
+ strcmp(optarg, "rawip") == 0) {
+ proto = IPPROTO_RAW;
+ } else {
+ fatal(1, "%s: unknown protocol.\n", optarg);
+ }
+ break;
+
+ case 'I':
+ ifname = optarg;
+ Iflag = B_TRUE;
+ IFLAGMOD(Iflag_only, -1, 1); /* see macro def'n */
+ break;
+
+ case 'D':
+ DHCPflag = B_TRUE;
+ Iflag_only = 0;
+ break;
+
+ case '?':
+ default:
+ usage(name);
+ }
+ }
+
+ /*
+ * Handle other arguments: find interval, count; the
+ * flags that accept 'interval' and 'count' are OR'd
+ * in the outermost 'if'; more flags may be added as
+ * required
+ */
+ if (Iflag || Sflag || Mflag) {
+ for (d = optind; d < argc; d++) {
+ if (isnum(argv[d])) {
+ interval = atoi(argv[d]);
+ if (d + 1 < argc &&
+ isnum(argv[d + 1])) {
+ count = atoi(argv[d + 1]);
+ optind++;
+ }
+ optind++;
+ if (interval == 0 || count == 0)
+ usage(name);
+ break;
+ }
+ }
+ }
+ if (optind < argc) {
+ if (Iflag && isnum(argv[optind])) {
+ count = atoi(argv[optind]);
+ if (count == 0)
+ usage(name);
+ optind++;
+ }
+ }
+ if (optind < argc) {
+ (void) fprintf(stderr,
+ "%s: extra arguments\n", name);
+ usage(name);
+ }
+ if (interval)
+ setbuf(stdout, NULL);
+
+ if (DHCPflag) {
+ dhcp_report(Iflag ? ifname : NULL);
+ exit(0);
+ }
+
+ /* Get data structures: priming before iteration */
+ if (family_selected(AF_INET) || family_selected(AF_INET6)) {
+ sd = mibopen();
+ if (sd == -1)
+ fatal(1, "can't open mib stream\n");
+ if ((item = mibget(sd)) == NULL) {
+ (void) close(sd);
+ fatal(1, "mibget() failed\n");
+ }
+ /* Extract constant sizes - need do once only */
+ mib_get_constants(item);
+ }
+ if ((kc = kstat_open()) == NULL) {
+ mibfree(item);
+ (void) close(sd);
+ fail(1, "kstat_open(): can't open /dev/kstat");
+ }
+
+ if (interval <= 0) {
+ count = 1;
+ once_only = B_TRUE;
+ }
+ /* 'for' loop 1: */
+ for (;;) {
+ mib_item_t *curritem = NULL; /* only for -[M]s */
+
+ /* netstat: AF_INET[6] behaviour */
+ if (family_selected(AF_INET) || family_selected(AF_INET6)) {
+ if (Sflag) {
+ curritem = mib_item_diff(previtem, item);
+ if (curritem == NULL)
+ fatal(1, "can't process mib data, "
+ "out of memory\n");
+ mib_item_destroy(&previtem);
+ }
+
+ if (!(Iflag || Rflag || Sflag || Mflag ||
+ MMflag || Pflag || Gflag || DHCPflag)) {
+ if (protocol_selected(IPPROTO_UDP))
+ udp_report(item);
+ if (protocol_selected(IPPROTO_TCP))
+ tcp_report(item);
+ if (protocol_selected(IPPROTO_SCTP))
+ sctp_report(item);
+ }
+ if (Iflag)
+ if_report(item, ifname, Iflag_only, once_only);
+ if (Mflag)
+ m_report();
+ if (Rflag)
+ ire_report(item);
+ if (Sflag && MMflag) {
+ mrt_stat_report(curritem);
+ } else {
+ if (Sflag)
+ stat_report(curritem);
+ if (MMflag)
+ mrt_report(item);
+ }
+ if (Gflag)
+ group_report(item);
+ if (Pflag) {
+ if (family_selected(AF_INET))
+ arp_report(item);
+ if (family_selected(AF_INET6))
+ ndp_report(item);
+ }
+ mib_item_destroy(&curritem);
+ }
+
+ /* netstat: AF_UNIX behaviour */
+ if (family_selected(AF_UNIX) &&
+ (!(Iflag || Rflag || Sflag || Mflag ||
+ MMflag || Pflag || Gflag)))
+ unixpr(kc);
+ (void) kstat_close(kc);
+
+ /* iteration handling code */
+ if (count > 0 && --count == 0)
+ break;
+ (void) sleep(interval);
+
+ /* re-populating of data structures */
+ if (family_selected(AF_INET) || family_selected(AF_INET6)) {
+ if (Sflag) {
+ /* previtem is a cut-down list */
+ previtem = mib_item_dup(item);
+ if (previtem == NULL)
+ fatal(1, "can't process mib data, "
+ "out of memory\n");
+ }
+ mibfree(item);
+ (void) close(sd);
+ if ((sd = mibopen()) == -1)
+ fatal(1, "can't open mib stream anymore\n");
+ if ((item = mibget(sd)) == NULL) {
+ (void) close(sd);
+ fatal(1, "mibget() failed\n");
+ }
+ }
+ if ((kc = kstat_open()) == NULL)
+ fail(1, "kstat_open(): can't open /dev/kstat");
+
+ } /* 'for' loop 1 ends */
+ mibfree(item);
+ (void) close(sd);
+
+ return (0);
+}
+
+
+static int
+isnum(char *p)
+{
+ int len;
+ int i;
+
+ len = strlen(p);
+ for (i = 0; i < len; i++)
+ if (!isdigit(p[i]))
+ return (0);
+ return (1);
+}
+
+
+/* --------------------------------- MIBGET -------------------------------- */
+
+static mib_item_t *
+mibget(int sd)
+{
+ /*
+ * buf is an automatic for this function, so the
+ * compiler has complete control over its alignment;
+ * it is assumed this alignment is satisfactory for
+ * it to be casted to certain other struct pointers
+ * here, such as struct T_optmgmt_ack * .
+ */
+ uintptr_t buf[512 / sizeof (uintptr_t)];
+ int flags;
+ int i, j, getcode;
+ struct strbuf ctlbuf, databuf;
+ struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf;
+ struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf;
+ struct T_error_ack *tea = (struct T_error_ack *)buf;
+ struct opthdr *req;
+ mib_item_t *first_item = NULL;
+ mib_item_t *last_item = NULL;
+ mib_item_t *temp;
+
+ tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
+ tor->OPT_offset = sizeof (struct T_optmgmt_req);
+ tor->OPT_length = sizeof (struct opthdr);
+ tor->MGMT_flags = T_CURRENT;
+ req = (struct opthdr *)&tor[1];
+ req->level = MIB2_IP; /* any MIB2_xxx value ok here */
+ req->name = 0;
+ req->len = 0;
+
+ ctlbuf.buf = (char *)buf;
+ ctlbuf.len = tor->OPT_length + tor->OPT_offset;
+ flags = 0;
+ if (putmsg(sd, &ctlbuf, (struct strbuf *)0, flags) == -1) {
+ perror("mibget: putmsg(ctl) failed");
+ goto error_exit;
+ }
+
+ /*
+ * Each reply consists of a ctl part for one fixed structure
+ * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK,
+ * containing an opthdr structure. level/name identify the entry,
+ * len is the size of the data part of the message.
+ */
+ req = (struct opthdr *)&toa[1];
+ ctlbuf.maxlen = sizeof (buf);
+ j = 1;
+ for (;;) {
+ flags = 0;
+ getcode = getmsg(sd, &ctlbuf, (struct strbuf *)0, &flags);
+ if (getcode == -1) {
+ perror("mibget getmsg(ctl) failed");
+ if (Dflag) {
+ (void) fputs("# level name len\n",
+ stderr);
+ i = 0;
+ for (last_item = first_item; last_item;
+ last_item = last_item->next_item)
+ (void) printf("%d %4d %5d %d\n",
+ ++i,
+ last_item->group,
+ last_item->mib_id,
+ last_item->length);
+ }
+ goto error_exit;
+ }
+ if (getcode == 0 &&
+ ctlbuf.len >= sizeof (struct T_optmgmt_ack) &&
+ toa->PRIM_type == T_OPTMGMT_ACK &&
+ toa->MGMT_flags == T_SUCCESS &&
+ req->len == 0) {
+ if (Dflag)
+ (void) printf("mibget getmsg() %d returned "
+ "EOD (level %ld, name %ld)\n",
+ j, req->level, req->name);
+ return (first_item); /* this is EOD msg */
+ }
+
+ if (ctlbuf.len >= sizeof (struct T_error_ack) &&
+ tea->PRIM_type == T_ERROR_ACK) {
+ (void) fprintf(stderr,
+ "mibget %d gives T_ERROR_ACK: TLI_error = 0x%lx, "
+ "UNIX_error = 0x%lx\n",
+ j, tea->TLI_error, tea->UNIX_error);
+
+ errno = (tea->TLI_error == TSYSERR) ?
+ tea->UNIX_error : EPROTO;
+ goto error_exit;
+ }
+
+ if (getcode != MOREDATA ||
+ ctlbuf.len < sizeof (struct T_optmgmt_ack) ||
+ toa->PRIM_type != T_OPTMGMT_ACK ||
+ toa->MGMT_flags != T_SUCCESS) {
+ (void) printf("mibget getmsg(ctl) %d returned %d, "
+ "ctlbuf.len = %d, PRIM_type = %ld\n",
+ j, getcode, ctlbuf.len, toa->PRIM_type);
+
+ if (toa->PRIM_type == T_OPTMGMT_ACK)
+ (void) printf("T_OPTMGMT_ACK: "
+ "MGMT_flags = 0x%lx, req->len = %ld\n",
+ toa->MGMT_flags, req->len);
+ errno = ENOMSG;
+ goto error_exit;
+ }
+
+ temp = (mib_item_t *)malloc(sizeof (mib_item_t));
+ if (temp == NULL) {
+ perror("mibget malloc failed");
+ goto error_exit;
+ }
+ if (last_item != NULL)
+ last_item->next_item = temp;
+ else
+ first_item = temp;
+ last_item = temp;
+ last_item->next_item = NULL;
+ last_item->group = req->level;
+ last_item->mib_id = req->name;
+ last_item->length = req->len;
+ last_item->valp = malloc((int)req->len);
+ if (last_item->valp == NULL)
+ goto error_exit;
+ if (Dflag)
+ (void) printf("msg %d: group = %4d mib_id = %5d"
+ "length = %d\n",
+ j, last_item->group, last_item->mib_id,
+ last_item->length);
+
+ databuf.maxlen = last_item->length;
+ databuf.buf = (char *)last_item->valp;
+ databuf.len = 0;
+ flags = 0;
+ getcode = getmsg(sd, (struct strbuf *)0, &databuf, &flags);
+ if (getcode == -1) {
+ perror("mibget getmsg(data) failed");
+ goto error_exit;
+ } else if (getcode != 0) {
+ (void) printf("mibget getmsg(data) returned %d, "
+ "databuf.maxlen = %d, databuf.len = %d\n",
+ getcode, databuf.maxlen, databuf.len);
+ goto error_exit;
+ }
+ j++;
+ }
+ /* NOTREACHED */
+
+error_exit:;
+ mibfree(first_item);
+ return (NULL);
+}
+
+/*
+ * mibfree: frees a linked list of type (mib_item_t *)
+ * returned by mibget(); this is NOT THE SAME AS
+ * mib_item_destroy(), so should be used for objects
+ * returned by mibget() only
+ */
+static void
+mibfree(mib_item_t *firstitem)
+{
+ mib_item_t *lastitem;
+
+ while (firstitem != NULL) {
+ lastitem = firstitem;
+ firstitem = firstitem->next_item;
+ if (lastitem->valp != NULL)
+ free(lastitem->valp);
+ free(lastitem);
+ }
+}
+
+static int
+mibopen(void)
+{
+ int sd;
+
+ sd = open("/dev/arp", O_RDWR);
+ if (sd == -1) {
+ perror("arp open");
+ return (-1);
+ }
+ if (ioctl(sd, I_PUSH, "tcp") == -1) {
+ perror("tcp I_PUSH");
+ (void) close(sd);
+ return (-1);
+ }
+ if (ioctl(sd, I_PUSH, "udp") == -1) {
+ perror("udp I_PUSH");
+ (void) close(sd);
+ return (-1);
+ }
+ if (ioctl(sd, I_PUSH, "icmp") == -1) {
+ perror("icmp I_PUSH");
+ (void) close(sd);
+ return (-1);
+ }
+ return (sd);
+}
+
+/*
+ * mib_item_dup: returns a clean mib_item_t * linked
+ * list, so that for every element item->mib_id is 0;
+ * to deallocate this linked list, use mib_item_destroy
+ */
+static mib_item_t *
+mib_item_dup(mib_item_t *item)
+{
+ int c = 0;
+ mib_item_t *localp;
+ mib_item_t *tempp;
+
+ for (tempp = item; tempp; tempp = tempp->next_item)
+ if (tempp->mib_id == 0)
+ c++;
+ tempp = NULL;
+
+ localp = (mib_item_t *)malloc(c * sizeof (mib_item_t));
+ if (localp == NULL)
+ return (NULL);
+ c = 0;
+ for (; item; item = item->next_item) {
+ if (item->mib_id == 0) {
+ /* Replicate item in localp */
+ (localp[c]).next_item = NULL;
+ (localp[c]).group = item->group;
+ (localp[c]).mib_id = item->mib_id;
+ (localp[c]).length = item->length;
+ (localp[c]).valp = (uintptr_t *)malloc(
+ item->length);
+ if ((localp[c]).valp == NULL) {
+ mib_item_destroy(&localp);
+ return (NULL);
+ }
+ (void *) memcpy((localp[c]).valp,
+ item->valp,
+ item->length);
+ tempp = &(localp[c]);
+ if (c > 0)
+ (localp[c - 1]).next_item = tempp;
+ c++;
+ }
+ }
+ return (localp);
+}
+
+/*
+ * mib_item_diff: takes two (mib_item_t *) linked lists
+ * item1 and item2 and computes the difference between
+ * differentiable values in item2 against item1 for every
+ * given member of item2; returns an mib_item_t * linked
+ * list of diff's, or a copy of item2 if item1 is NULL;
+ * will return NULL if system out of memory; works only
+ * for item->mib_id == 0
+ */
+static mib_item_t *
+mib_item_diff(mib_item_t *item1, mib_item_t *item2) {
+ int nitems = 0; /* no. of items in item2 */
+ mib_item_t *tempp2; /* walking copy of item2 */
+ mib_item_t *tempp1; /* walking copy of item1 */
+ mib_item_t *diffp;
+ mib_item_t *diffptr; /* walking copy of diffp */
+ mib_item_t *prevp = NULL;
+
+ if (item1 == NULL) {
+ diffp = mib_item_dup(item2);
+ return (diffp);
+ }
+
+ for (tempp2 = item2;
+ tempp2;
+ tempp2 = tempp2->next_item) {
+ if (tempp2->mib_id == 0)
+ switch (tempp2->group) {
+ /*
+ * upon adding a case here, the same
+ * must also be added in the next
+ * switch statement, alongwith
+ * appropriate code
+ */
+ case MIB2_IP:
+ case MIB2_IP6:
+ case EXPER_DVMRP:
+ case EXPER_IGMP:
+ case MIB2_ICMP:
+ case MIB2_ICMP6:
+ case MIB2_TCP:
+ case MIB2_UDP:
+ case MIB2_SCTP:
+ case EXPER_RAWIP:
+ nitems++;
+ }
+ }
+ tempp2 = NULL;
+ if (nitems == 0) {
+ diffp = mib_item_dup(item2);
+ return (diffp);
+ }
+
+ diffp = (mib_item_t *)calloc(nitems, sizeof (mib_item_t));
+ if (diffp == NULL)
+ return (NULL);
+ diffptr = diffp;
+ /* 'for' loop 1: */
+ for (tempp2 = item2; tempp2 != NULL; tempp2 = tempp2->next_item) {
+ if (tempp2->mib_id != 0)
+ continue; /* 'for' loop 1 */
+ /* 'for' loop 2: */
+ for (tempp1 = item1; tempp1 != NULL;
+ tempp1 = tempp1->next_item) {
+ if (!(tempp1->mib_id == 0 &&
+ tempp1->group == tempp2->group &&
+ tempp1->mib_id == tempp2->mib_id))
+ continue; /* 'for' loop 2 */
+ /* found comparable data sets */
+ if (prevp != NULL)
+ prevp->next_item = diffptr;
+ switch (tempp2->group) {
+ /*
+ * Indenting note: Because of long variable names
+ * in cases MIB2_IP6 and MIB2_ICMP6, their contents
+ * have been indented by one tab space only
+ */
+ case MIB2_IP: {
+ mib2_ip_t *i2 = (mib2_ip_t *)tempp2->valp;
+ mib2_ip_t *i1 = (mib2_ip_t *)tempp1->valp;
+ mib2_ip_t *d;
+
+ diffptr->group = tempp2->group;
+ diffptr->mib_id = tempp2->mib_id;
+ diffptr->length = tempp2->length;
+ d = (mib2_ip_t *)calloc(tempp2->length, 1);
+ if (d == NULL)
+ goto mibdiff_out_of_memory;
+ diffptr->valp = d;
+ d->ipForwarding = i2->ipForwarding;
+ d->ipDefaultTTL = i2->ipDefaultTTL;
+ MDIFF(d, i2, i1, ipInReceives);
+ MDIFF(d, i2, i1, ipInHdrErrors);
+ MDIFF(d, i2, i1, ipInAddrErrors);
+ MDIFF(d, i2, i1, ipInCksumErrs);
+ MDIFF(d, i2, i1, ipForwDatagrams);
+ MDIFF(d, i2, i1, ipForwProhibits);
+ MDIFF(d, i2, i1, ipInUnknownProtos);
+ MDIFF(d, i2, i1, ipInDiscards);
+ MDIFF(d, i2, i1, ipInDelivers);
+ MDIFF(d, i2, i1, ipOutRequests);
+ MDIFF(d, i2, i1, ipOutDiscards);
+ MDIFF(d, i2, i1, ipOutNoRoutes);
+ MDIFF(d, i2, i1, ipReasmTimeout);
+ MDIFF(d, i2, i1, ipReasmReqds);
+ MDIFF(d, i2, i1, ipReasmOKs);
+ MDIFF(d, i2, i1, ipReasmFails);
+ MDIFF(d, i2, i1, ipReasmDuplicates);
+ MDIFF(d, i2, i1, ipReasmPartDups);
+ MDIFF(d, i2, i1, ipFragOKs);
+ MDIFF(d, i2, i1, ipFragFails);
+ MDIFF(d, i2, i1, ipFragCreates);
+ MDIFF(d, i2, i1, ipRoutingDiscards);
+ MDIFF(d, i2, i1, tcpInErrs);
+ MDIFF(d, i2, i1, udpNoPorts);
+ MDIFF(d, i2, i1, udpInCksumErrs);
+ MDIFF(d, i2, i1, udpInOverflows);
+ MDIFF(d, i2, i1, rawipInOverflows);
+ MDIFF(d, i2, i1, ipsecInSucceeded);
+ MDIFF(d, i2, i1, ipsecInFailed);
+ MDIFF(d, i2, i1, ipInIPv6);
+ MDIFF(d, i2, i1, ipOutIPv6);
+ MDIFF(d, i2, i1, ipOutSwitchIPv6);
+ prevp = diffptr++;
+ break;
+ }
+ case MIB2_IP6: {
+ mib2_ipv6IfStatsEntry_t *i2;
+ mib2_ipv6IfStatsEntry_t *i1;
+ mib2_ipv6IfStatsEntry_t *d;
+
+ i2 = (mib2_ipv6IfStatsEntry_t *)tempp2->valp;
+ i1 = (mib2_ipv6IfStatsEntry_t *)tempp1->valp;
+ diffptr->group = tempp2->group;
+ diffptr->mib_id = tempp2->mib_id;
+ diffptr->length = tempp2->length;
+ d = (mib2_ipv6IfStatsEntry_t *)calloc(
+ tempp2->length, 1);
+ if (d == NULL)
+ goto mibdiff_out_of_memory;
+ diffptr->valp = d;
+ d->ipv6Forwarding = i2->ipv6Forwarding;
+ d->ipv6DefaultHopLimit =
+ i2->ipv6DefaultHopLimit;
+
+ MDIFF(d, i2, i1, ipv6InReceives);
+ MDIFF(d, i2, i1, ipv6InHdrErrors);
+ MDIFF(d, i2, i1, ipv6InTooBigErrors);
+ MDIFF(d, i2, i1, ipv6InNoRoutes);
+ MDIFF(d, i2, i1, ipv6InAddrErrors);
+ MDIFF(d, i2, i1, ipv6InUnknownProtos);
+ MDIFF(d, i2, i1, ipv6InTruncatedPkts);
+ MDIFF(d, i2, i1, ipv6InDiscards);
+ MDIFF(d, i2, i1, ipv6InDelivers);
+ MDIFF(d, i2, i1, ipv6OutForwDatagrams);
+ MDIFF(d, i2, i1, ipv6OutRequests);
+ MDIFF(d, i2, i1, ipv6OutDiscards);
+ MDIFF(d, i2, i1, ipv6OutNoRoutes);
+ MDIFF(d, i2, i1, ipv6OutFragOKs);
+ MDIFF(d, i2, i1, ipv6OutFragFails);
+ MDIFF(d, i2, i1, ipv6OutFragCreates);
+ MDIFF(d, i2, i1, ipv6ReasmReqds);
+ MDIFF(d, i2, i1, ipv6ReasmOKs);
+ MDIFF(d, i2, i1, ipv6ReasmFails);
+ MDIFF(d, i2, i1, ipv6InMcastPkts);
+ MDIFF(d, i2, i1, ipv6OutMcastPkts);
+ MDIFF(d, i2, i1, ipv6ReasmDuplicates);
+ MDIFF(d, i2, i1, ipv6ReasmPartDups);
+ MDIFF(d, i2, i1, ipv6ForwProhibits);
+ MDIFF(d, i2, i1, udpInCksumErrs);
+ MDIFF(d, i2, i1, udpInOverflows);
+ MDIFF(d, i2, i1, rawipInOverflows);
+ MDIFF(d, i2, i1, ipv6InIPv4);
+ MDIFF(d, i2, i1, ipv6OutIPv4);
+ MDIFF(d, i2, i1, ipv6OutSwitchIPv4);
+ prevp = diffptr++;
+ break;
+ }
+ case EXPER_DVMRP: {
+ struct mrtstat *m2;
+ struct mrtstat *m1;
+ struct mrtstat *d;
+
+ m2 = (struct mrtstat *)tempp2->valp;
+ m1 = (struct mrtstat *)tempp1->valp;
+ diffptr->group = tempp2->group;
+ diffptr->mib_id = tempp2->mib_id;
+ diffptr->length = tempp2->length;
+ d = (struct mrtstat *)calloc(tempp2->length, 1);
+ if (d == NULL)
+ goto mibdiff_out_of_memory;
+ diffptr->valp = d;
+ MDIFF(d, m2, m1, mrts_mfc_hits);
+ MDIFF(d, m2, m1, mrts_mfc_misses);
+ MDIFF(d, m2, m1, mrts_fwd_in);
+ MDIFF(d, m2, m1, mrts_fwd_out);
+ d->mrts_upcalls = m2->mrts_upcalls;
+ MDIFF(d, m2, m1, mrts_fwd_drop);
+ MDIFF(d, m2, m1, mrts_bad_tunnel);
+ MDIFF(d, m2, m1, mrts_cant_tunnel);
+ MDIFF(d, m2, m1, mrts_wrong_if);
+ MDIFF(d, m2, m1, mrts_upq_ovflw);
+ MDIFF(d, m2, m1, mrts_cache_cleanups);
+ MDIFF(d, m2, m1, mrts_drop_sel);
+ MDIFF(d, m2, m1, mrts_q_overflow);
+ MDIFF(d, m2, m1, mrts_pkt2large);
+ MDIFF(d, m2, m1, mrts_pim_badversion);
+ MDIFF(d, m2, m1, mrts_pim_rcv_badcsum);
+ MDIFF(d, m2, m1, mrts_pim_badregisters);
+ MDIFF(d, m2, m1, mrts_pim_regforwards);
+ MDIFF(d, m2, m1, mrts_pim_regsend_drops);
+ MDIFF(d, m2, m1, mrts_pim_malformed);
+ MDIFF(d, m2, m1, mrts_pim_nomemory);
+ prevp = diffptr++;
+ break;
+ }
+ case EXPER_IGMP: {
+ struct igmpstat *i2;
+ struct igmpstat *i1;
+ struct igmpstat *d;
+
+ i2 = (struct igmpstat *)tempp2->valp;
+ i1 = (struct igmpstat *)tempp1->valp;
+ diffptr->group = tempp2->group;
+ diffptr->mib_id = tempp2->mib_id;
+ diffptr->length = tempp2->length;
+ d = (struct igmpstat *)calloc(
+ tempp2->length, 1);
+ if (d == NULL)
+ goto mibdiff_out_of_memory;
+ diffptr->valp = d;
+ MDIFF(d, i2, i1, igps_rcv_total);
+ MDIFF(d, i2, i1, igps_rcv_tooshort);
+ MDIFF(d, i2, i1, igps_rcv_badsum);
+ MDIFF(d, i2, i1, igps_rcv_queries);
+ MDIFF(d, i2, i1, igps_rcv_badqueries);
+ MDIFF(d, i2, i1, igps_rcv_reports);
+ MDIFF(d, i2, i1, igps_rcv_badreports);
+ MDIFF(d, i2, i1, igps_rcv_ourreports);
+ MDIFF(d, i2, i1, igps_snd_reports);
+ prevp = diffptr++;
+ break;
+ }
+ case MIB2_ICMP: {
+ mib2_icmp_t *i2;
+ mib2_icmp_t *i1;
+ mib2_icmp_t *d;
+
+ i2 = (mib2_icmp_t *)tempp2->valp;
+ i1 = (mib2_icmp_t *)tempp1->valp;
+ diffptr->group = tempp2->group;
+ diffptr->mib_id = tempp2->mib_id;
+ diffptr->length = tempp2->length;
+ d = (mib2_icmp_t *)calloc(tempp2->length, 1);
+ if (d == NULL)
+ goto mibdiff_out_of_memory;
+ diffptr->valp = d;
+ MDIFF(d, i2, i1, icmpInMsgs);
+ MDIFF(d, i2, i1, icmpInErrors);
+ MDIFF(d, i2, i1, icmpInCksumErrs);
+ MDIFF(d, i2, i1, icmpInUnknowns);
+ MDIFF(d, i2, i1, icmpInDestUnreachs);
+ MDIFF(d, i2, i1, icmpInTimeExcds);
+ MDIFF(d, i2, i1, icmpInParmProbs);
+ MDIFF(d, i2, i1, icmpInSrcQuenchs);
+ MDIFF(d, i2, i1, icmpInRedirects);
+ MDIFF(d, i2, i1, icmpInBadRedirects);
+ MDIFF(d, i2, i1, icmpInEchos);
+ MDIFF(d, i2, i1, icmpInEchoReps);
+ MDIFF(d, i2, i1, icmpInTimestamps);
+ MDIFF(d, i2, i1, icmpInAddrMasks);
+ MDIFF(d, i2, i1, icmpInAddrMaskReps);
+ MDIFF(d, i2, i1, icmpInFragNeeded);
+ MDIFF(d, i2, i1, icmpOutMsgs);
+ MDIFF(d, i2, i1, icmpOutDrops);
+ MDIFF(d, i2, i1, icmpOutErrors);
+ MDIFF(d, i2, i1, icmpOutDestUnreachs);
+ MDIFF(d, i2, i1, icmpOutTimeExcds);
+ MDIFF(d, i2, i1, icmpOutParmProbs);
+ MDIFF(d, i2, i1, icmpOutSrcQuenchs);
+ MDIFF(d, i2, i1, icmpOutRedirects);
+ MDIFF(d, i2, i1, icmpOutEchos);
+ MDIFF(d, i2, i1, icmpOutEchoReps);
+ MDIFF(d, i2, i1, icmpOutTimestamps);
+ MDIFF(d, i2, i1, icmpOutTimestampReps);
+ MDIFF(d, i2, i1, icmpOutAddrMasks);
+ MDIFF(d, i2, i1, icmpOutAddrMaskReps);
+ MDIFF(d, i2, i1, icmpOutFragNeeded);
+ MDIFF(d, i2, i1, icmpInOverflows);
+ prevp = diffptr++;
+ break;
+ }
+ case MIB2_ICMP6: {
+ mib2_ipv6IfIcmpEntry_t *i2;
+ mib2_ipv6IfIcmpEntry_t *i1;
+ mib2_ipv6IfIcmpEntry_t *d;
+
+ i2 = (mib2_ipv6IfIcmpEntry_t *)tempp2->valp;
+ i1 = (mib2_ipv6IfIcmpEntry_t *)tempp1->valp;
+ diffptr->group = tempp2->group;
+ diffptr->mib_id = tempp2->mib_id;
+ diffptr->length = tempp2->length;
+ d = (mib2_ipv6IfIcmpEntry_t *)calloc(tempp2->length, 1);
+ if (d == NULL)
+ goto mibdiff_out_of_memory;
+ diffptr->valp = d;
+ MDIFF(d, i2, i1, ipv6IfIcmpInMsgs);
+ MDIFF(d, i2, i1, ipv6IfIcmpInErrors);
+ MDIFF(d, i2, i1, ipv6IfIcmpInDestUnreachs);
+ MDIFF(d, i2, i1, ipv6IfIcmpInAdminProhibs);
+ MDIFF(d, i2, i1, ipv6IfIcmpInTimeExcds);
+ MDIFF(d, i2, i1, ipv6IfIcmpInParmProblems);
+ MDIFF(d, i2, i1, ipv6IfIcmpInPktTooBigs);
+ MDIFF(d, i2, i1, ipv6IfIcmpInEchos);
+ MDIFF(d, i2, i1, ipv6IfIcmpInEchoReplies);
+ MDIFF(d, i2, i1, ipv6IfIcmpInRouterSolicits);
+ MDIFF(d, i2, i1, ipv6IfIcmpInRouterAdvertisements);
+ MDIFF(d, i2, i1, ipv6IfIcmpInNeighborSolicits);
+ MDIFF(d, i2, i1, ipv6IfIcmpInNeighborAdvertisements);
+ MDIFF(d, i2, i1, ipv6IfIcmpInRedirects);
+ MDIFF(d, i2, i1, ipv6IfIcmpInBadRedirects);
+ MDIFF(d, i2, i1, ipv6IfIcmpInGroupMembQueries);
+ MDIFF(d, i2, i1, ipv6IfIcmpInGroupMembResponses);
+ MDIFF(d, i2, i1, ipv6IfIcmpInGroupMembReductions);
+ MDIFF(d, i2, i1, ipv6IfIcmpInOverflows);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutMsgs);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutErrors);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutDestUnreachs);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutAdminProhibs);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutTimeExcds);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutParmProblems);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutPktTooBigs);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutEchos);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutEchoReplies);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutRouterSolicits);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutRouterAdvertisements);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutNeighborSolicits);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutNeighborAdvertisements);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutRedirects);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutGroupMembQueries);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutGroupMembResponses);
+ MDIFF(d, i2, i1, ipv6IfIcmpOutGroupMembReductions);
+ prevp = diffptr++;
+ break;
+ }
+ case MIB2_TCP: {
+ mib2_tcp_t *t2;
+ mib2_tcp_t *t1;
+ mib2_tcp_t *d;
+
+ t2 = (mib2_tcp_t *)tempp2->valp;
+ t1 = (mib2_tcp_t *)tempp1->valp;
+ diffptr->group = tempp2->group;
+ diffptr->mib_id = tempp2->mib_id;
+ diffptr->length = tempp2->length;
+ d = (mib2_tcp_t *)calloc(tempp2->length, 1);
+ if (d == NULL)
+ goto mibdiff_out_of_memory;
+ diffptr->valp = d;
+ d->tcpRtoMin = t2->tcpRtoMin;
+ d->tcpRtoMax = t2->tcpRtoMax;
+ d->tcpMaxConn = t2->tcpMaxConn;
+ MDIFF(d, t2, t1, tcpActiveOpens);
+ MDIFF(d, t2, t1, tcpPassiveOpens);
+ MDIFF(d, t2, t1, tcpAttemptFails);
+ MDIFF(d, t2, t1, tcpEstabResets);
+ d->tcpCurrEstab = t2->tcpCurrEstab;
+ MDIFF(d, t2, t1, tcpOutSegs);
+ MDIFF(d, t2, t1, tcpOutDataSegs);
+ MDIFF(d, t2, t1, tcpOutDataBytes);
+ MDIFF(d, t2, t1, tcpRetransSegs);
+ MDIFF(d, t2, t1, tcpRetransBytes);
+ MDIFF(d, t2, t1, tcpOutAck);
+ MDIFF(d, t2, t1, tcpOutAckDelayed);
+ MDIFF(d, t2, t1, tcpOutUrg);
+ MDIFF(d, t2, t1, tcpOutWinUpdate);
+ MDIFF(d, t2, t1, tcpOutWinProbe);
+ MDIFF(d, t2, t1, tcpOutControl);
+ MDIFF(d, t2, t1, tcpOutRsts);
+ MDIFF(d, t2, t1, tcpOutFastRetrans);
+ MDIFF(d, t2, t1, tcpInSegs);
+ MDIFF(d, t2, t1, tcpInAckSegs);
+ MDIFF(d, t2, t1, tcpInAckBytes);
+ MDIFF(d, t2, t1, tcpInDupAck);
+ MDIFF(d, t2, t1, tcpInAckUnsent);
+ MDIFF(d, t2, t1, tcpInDataInorderSegs);
+ MDIFF(d, t2, t1, tcpInDataInorderBytes);
+ MDIFF(d, t2, t1, tcpInDataUnorderSegs);
+ MDIFF(d, t2, t1, tcpInDataUnorderBytes);
+ MDIFF(d, t2, t1, tcpInDataDupSegs);
+ MDIFF(d, t2, t1, tcpInDataDupBytes);
+ MDIFF(d, t2, t1, tcpInDataPartDupSegs);
+ MDIFF(d, t2, t1, tcpInDataPartDupBytes);
+ MDIFF(d, t2, t1, tcpInDataPastWinSegs);
+ MDIFF(d, t2, t1, tcpInDataPastWinBytes);
+ MDIFF(d, t2, t1, tcpInWinProbe);
+ MDIFF(d, t2, t1, tcpInWinUpdate);
+ MDIFF(d, t2, t1, tcpInClosed);
+ MDIFF(d, t2, t1, tcpRttNoUpdate);
+ MDIFF(d, t2, t1, tcpRttUpdate);
+ MDIFF(d, t2, t1, tcpTimRetrans);
+ MDIFF(d, t2, t1, tcpTimRetransDrop);
+ MDIFF(d, t2, t1, tcpTimKeepalive);
+ MDIFF(d, t2, t1, tcpTimKeepaliveProbe);
+ MDIFF(d, t2, t1, tcpTimKeepaliveDrop);
+ MDIFF(d, t2, t1, tcpListenDrop);
+ MDIFF(d, t2, t1, tcpListenDropQ0);
+ MDIFF(d, t2, t1, tcpHalfOpenDrop);
+ MDIFF(d, t2, t1, tcpOutSackRetransSegs);
+ prevp = diffptr++;
+ break;
+ }
+ case MIB2_UDP: {
+ mib2_udp_t *u2;
+ mib2_udp_t *u1;
+ mib2_udp_t *d;
+
+ u2 = (mib2_udp_t *)tempp2->valp;
+ u1 = (mib2_udp_t *)tempp1->valp;
+ diffptr->group = tempp2->group;
+ diffptr->mib_id = tempp2->mib_id;
+ diffptr->length = tempp2->length;
+ d = (mib2_udp_t *)calloc(tempp2->length, 1);
+ if (d == NULL)
+ goto mibdiff_out_of_memory;
+ diffptr->valp = d;
+ MDIFF(d, u2, u1, udpInDatagrams);
+ MDIFF(d, u2, u1, udpInErrors);
+ MDIFF(d, u2, u1, udpOutDatagrams);
+ MDIFF(d, u2, u1, udpOutErrors);
+ prevp = diffptr++;
+ break;
+ }
+ case MIB2_SCTP: {
+ mib2_sctp_t *s2;
+ mib2_sctp_t *s1;
+ mib2_sctp_t *d;
+
+ s2 = (mib2_sctp_t *)tempp2->valp;
+ s1 = (mib2_sctp_t *)tempp1->valp;
+ diffptr->group = tempp2->group;
+ diffptr->mib_id = tempp2->mib_id;
+ diffptr->length = tempp2->length;
+ d = (mib2_sctp_t *)calloc(tempp2->length, 1);
+ if (d == NULL)
+ goto mibdiff_out_of_memory;
+ diffptr->valp = d;
+ d->sctpRtoAlgorithm = s2->sctpRtoAlgorithm;
+ d->sctpRtoMin = s2->sctpRtoMin;
+ d->sctpRtoMax = s2->sctpRtoMax;
+ d->sctpRtoInitial = s2->sctpRtoInitial;
+ d->sctpMaxAssocs = s2->sctpMaxAssocs;
+ d->sctpValCookieLife = s2->sctpValCookieLife;
+ d->sctpMaxInitRetr = s2->sctpMaxInitRetr;
+ d->sctpCurrEstab = s2->sctpCurrEstab;
+ MDIFF(d, s2, s1, sctpActiveEstab);
+ MDIFF(d, s2, s1, sctpPassiveEstab);
+ MDIFF(d, s2, s1, sctpAborted);
+ MDIFF(d, s2, s1, sctpShutdowns);
+ MDIFF(d, s2, s1, sctpOutOfBlue);
+ MDIFF(d, s2, s1, sctpChecksumError);
+ MDIFF(d, s2, s1, sctpOutCtrlChunks);
+ MDIFF(d, s2, s1, sctpOutOrderChunks);
+ MDIFF(d, s2, s1, sctpOutUnorderChunks);
+ MDIFF(d, s2, s1, sctpRetransChunks);
+ MDIFF(d, s2, s1, sctpOutAck);
+ MDIFF(d, s2, s1, sctpOutAckDelayed);
+ MDIFF(d, s2, s1, sctpOutWinUpdate);
+ MDIFF(d, s2, s1, sctpOutFastRetrans);
+ MDIFF(d, s2, s1, sctpOutWinProbe);
+ MDIFF(d, s2, s1, sctpInCtrlChunks);
+ MDIFF(d, s2, s1, sctpInOrderChunks);
+ MDIFF(d, s2, s1, sctpInUnorderChunks);
+ MDIFF(d, s2, s1, sctpInAck);
+ MDIFF(d, s2, s1, sctpInDupAck);
+ MDIFF(d, s2, s1, sctpInAckUnsent);
+ MDIFF(d, s2, s1, sctpFragUsrMsgs);
+ MDIFF(d, s2, s1, sctpReasmUsrMsgs);
+ MDIFF(d, s2, s1, sctpOutSCTPPkts);
+ MDIFF(d, s2, s1, sctpInSCTPPkts);
+ MDIFF(d, s2, s1, sctpInInvalidCookie);
+ MDIFF(d, s2, s1, sctpTimRetrans);
+ MDIFF(d, s2, s1, sctpTimRetransDrop);
+ MDIFF(d, s2, s1, sctpTimHeartBeatProbe);
+ MDIFF(d, s2, s1, sctpTimHeartBeatDrop);
+ MDIFF(d, s2, s1, sctpListenDrop);
+ MDIFF(d, s2, s1, sctpInClosed);
+ prevp = diffptr++;
+ break;
+ }
+ case EXPER_RAWIP: {
+ mib2_rawip_t *r2;
+ mib2_rawip_t *r1;
+ mib2_rawip_t *d;
+
+ r2 = (mib2_rawip_t *)tempp2->valp;
+ r1 = (mib2_rawip_t *)tempp1->valp;
+ diffptr->group = tempp2->group;
+ diffptr->mib_id = tempp2->mib_id;
+ diffptr->length = tempp2->length;
+ d = (mib2_rawip_t *)calloc(tempp2->length, 1);
+ if (d == NULL)
+ goto mibdiff_out_of_memory;
+ diffptr->valp = d;
+ MDIFF(d, r2, r1, rawipInDatagrams);
+ MDIFF(d, r2, r1, rawipInErrors);
+ MDIFF(d, r2, r1, rawipInCksumErrs);
+ MDIFF(d, r2, r1, rawipOutDatagrams);
+ MDIFF(d, r2, r1, rawipOutErrors);
+ prevp = diffptr++;
+ break;
+ }
+ /*
+ * there are more "group" types but they aren't
+ * required for the -s and -Ms options
+ */
+ }
+ } /* 'for' loop 2 ends */
+ tempp1 = NULL;
+ } /* 'for' loop 1 ends */
+ tempp2 = NULL;
+ diffptr--;
+ diffptr->next_item = NULL;
+ return (diffp);
+
+mibdiff_out_of_memory:;
+ mib_item_destroy(&diffp);
+ return (NULL);
+}
+
+/*
+ * mib_item_destroy: cleans up a mib_item_t *
+ * that was created by calling mib_item_dup or
+ * mib_item_diff
+ */
+static void
+mib_item_destroy(mib_item_t **itemp) {
+ int nitems = 0;
+ int c = 0;
+ mib_item_t *tempp;
+
+ if (itemp == NULL || *itemp == NULL)
+ return;
+
+ for (tempp = *itemp; tempp != NULL; tempp = tempp->next_item)
+ if (tempp->mib_id == 0)
+ nitems++;
+ else
+ return; /* cannot destroy! */
+
+ if (nitems == 0)
+ return; /* cannot destroy! */
+
+ for (c = nitems - 1; c >= 0; c--) {
+ if ((itemp[0][c]).valp != NULL)
+ free((itemp[0][c]).valp);
+ }
+ free(*itemp);
+
+ *itemp = NULL;
+}
+
+/* Compare two Octet_ts. Return B_TRUE if they match, B_FALSE if not. */
+static boolean_t
+octetstrmatch(const Octet_t *a, const Octet_t *b)
+{
+ if (a == NULL || b == NULL)
+ return (B_FALSE);
+
+ if (a->o_length != b->o_length)
+ return (B_FALSE);
+
+ return (memcmp(a->o_bytes, b->o_bytes, a->o_length) == 0);
+}
+
+/* If octetstr() changes make an appropriate change to STR_EXPAND */
+static char *
+octetstr(Octet_t *op, int code, char *dst, uint_t dstlen)
+{
+ int i;
+ char *cp;
+
+ cp = dst;
+ if (op) {
+ for (i = 0; i < op->o_length; i++) {
+ switch (code) {
+ case 'd':
+ if (cp - dst + 4 > dstlen) {
+ *cp = '\0';
+ return (dst);
+ }
+ (void) snprintf(cp, 5, "%d.",
+ 0xff & op->o_bytes[i]);
+ cp = strchr(cp, '\0');
+ break;
+ case 'a':
+ if (cp - dst + 1 > dstlen) {
+ *cp = '\0';
+ return (dst);
+ }
+ *cp++ = op->o_bytes[i];
+ break;
+ case 'h':
+ default:
+ if (cp - dst + 3 > dstlen) {
+ *cp = '\0';
+ return (dst);
+ }
+ (void) snprintf(cp, 4, "%02x:",
+ 0xff & op->o_bytes[i]);
+ cp += 3;
+ break;
+ }
+ }
+ }
+ if (code != 'a' && cp != dst)
+ cp--;
+ *cp = '\0';
+ return (dst);
+}
+
+static char *
+mitcp_state(int state)
+{
+static char tcpsbuf[50];
+ char *cp;
+
+ switch (state) {
+ case TCPS_CLOSED:
+ cp = "CLOSED";
+ break;
+ case TCPS_IDLE:
+ cp = "IDLE";
+ break;
+ case TCPS_BOUND:
+ cp = "BOUND";
+ break;
+ case TCPS_LISTEN:
+ cp = "LISTEN";
+ break;
+ case TCPS_SYN_SENT:
+ cp = "SYN_SENT";
+ break;
+ case TCPS_SYN_RCVD:
+ cp = "SYN_RCVD";
+ break;
+ case TCPS_ESTABLISHED:
+ cp = "ESTABLISHED";
+ break;
+ case TCPS_CLOSE_WAIT:
+ cp = "CLOSE_WAIT";
+ break;
+ case TCPS_FIN_WAIT_1:
+ cp = "FIN_WAIT_1";
+ break;
+ case TCPS_CLOSING:
+ cp = "CLOSING";
+ break;
+ case TCPS_LAST_ACK:
+ cp = "LAST_ACK";
+ break;
+ case TCPS_FIN_WAIT_2:
+ cp = "FIN_WAIT_2";
+ break;
+ case TCPS_TIME_WAIT:
+ cp = "TIME_WAIT";
+ break;
+ default:
+ (void) snprintf(tcpsbuf, sizeof (tcpsbuf),
+ "UnknownState(%d)", state);
+ cp = tcpsbuf;
+ break;
+ }
+ return (cp);
+}
+
+static int odd;
+
+static void
+prval_init(void)
+{
+ odd = 0;
+}
+
+static void
+prval(char *str, Counter val)
+{
+ (void) printf("\t%-20s=%6u", str, val);
+ if (odd++ & 1)
+ (void) putchar('\n');
+}
+
+static void
+prval64(char *str, Counter64 val)
+{
+ (void) printf("\t%-20s=%6llu", str, val);
+ if (odd++ & 1)
+ (void) putchar('\n');
+}
+
+static void
+pr_int_val(char *str, int val)
+{
+ (void) printf("\t%-20s=%6d", str, val);
+ if (odd++ & 1)
+ (void) putchar('\n');
+}
+
+static void
+pr_sctp_rtoalgo(char *str, int val)
+{
+ (void) printf("\t%-20s=", str);
+ switch (val) {
+ case MIB2_SCTP_RTOALGO_OTHER:
+ (void) printf("%6.6s", "other");
+ break;
+
+ case MIB2_SCTP_RTOALGO_VANJ:
+ (void) printf("%6.6s", "vanj");
+ break;
+
+ default:
+ (void) printf("%6d", val);
+ break;
+ }
+ if (odd++ & 1)
+ (void) putchar('\n');
+}
+
+static void
+prval_end(void)
+{
+ if (odd++ & 1)
+ (void) putchar('\n');
+}
+
+/* Extract constant sizes */
+static void
+mib_get_constants(mib_item_t *item)
+{
+ /* 'for' loop 1: */
+ for (; item; item = item->next_item) {
+ if (item->mib_id != 0)
+ continue; /* 'for' loop 1 */
+
+ switch (item->group) {
+ case MIB2_IP: {
+ mib2_ip_t *ip = (mib2_ip_t *)item->valp;
+
+ ipAddrEntrySize = ip->ipAddrEntrySize;
+ ipRouteEntrySize = ip->ipRouteEntrySize;
+ ipNetToMediaEntrySize = ip->ipNetToMediaEntrySize;
+ ipMemberEntrySize = ip->ipMemberEntrySize;
+ ipGroupSourceEntrySize = ip->ipGroupSourceEntrySize;
+ assert(IS_P2ALIGNED(ipAddrEntrySize,
+ sizeof (mib2_ipAddrEntry_t *)) &&
+ IS_P2ALIGNED(ipRouteEntrySize,
+ sizeof (mib2_ipRouteEntry_t *)) &&
+ IS_P2ALIGNED(ipNetToMediaEntrySize,
+ sizeof (mib2_ipNetToMediaEntry_t *)) &&
+ IS_P2ALIGNED(ipMemberEntrySize,
+ sizeof (ip_member_t *)) &&
+ IS_P2ALIGNED(ipGroupSourceEntrySize,
+ sizeof (ip_grpsrc_t *)));
+ break;
+ }
+ case EXPER_DVMRP: {
+ struct mrtstat *mrts = (struct mrtstat *)item->valp;
+
+ vifctlSize = mrts->mrts_vifctlSize;
+ mfcctlSize = mrts->mrts_mfcctlSize;
+ assert(IS_P2ALIGNED(vifctlSize,
+ sizeof (struct vifclt *)) &&
+ IS_P2ALIGNED(mfcctlSize, sizeof (struct mfcctl *)));
+ break;
+ }
+ case MIB2_IP6: {
+ mib2_ipv6IfStatsEntry_t *ip6;
+ /* Just use the first entry */
+
+ ip6 = (mib2_ipv6IfStatsEntry_t *)item->valp;
+ ipv6IfStatsEntrySize = ip6->ipv6IfStatsEntrySize;
+ ipv6AddrEntrySize = ip6->ipv6AddrEntrySize;
+ ipv6RouteEntrySize = ip6->ipv6RouteEntrySize;
+ ipv6NetToMediaEntrySize = ip6->ipv6NetToMediaEntrySize;
+ ipv6MemberEntrySize = ip6->ipv6MemberEntrySize;
+ ipv6GroupSourceEntrySize =
+ ip6->ipv6GroupSourceEntrySize;
+ assert(IS_P2ALIGNED(ipv6IfStatsEntrySize,
+ sizeof (mib2_ipv6IfStatsEntry_t *)) &&
+ IS_P2ALIGNED(ipv6AddrEntrySize,
+ sizeof (mib2_ipv6AddrEntry_t *)) &&
+ IS_P2ALIGNED(ipv6RouteEntrySize,
+ sizeof (mib2_ipv6RouteEntry_t *)) &&
+ IS_P2ALIGNED(ipv6NetToMediaEntrySize,
+ sizeof (mib2_ipv6NetToMediaEntry_t *)) &&
+ IS_P2ALIGNED(ipv6MemberEntrySize,
+ sizeof (ipv6_member_t *)) &&
+ IS_P2ALIGNED(ipv6GroupSourceEntrySize,
+ sizeof (ipv6_grpsrc_t *)));
+ break;
+ }
+ case MIB2_ICMP6: {
+ mib2_ipv6IfIcmpEntry_t *icmp6;
+ /* Just use the first entry */
+
+ icmp6 = (mib2_ipv6IfIcmpEntry_t *)item->valp;
+ ipv6IfIcmpEntrySize = icmp6->ipv6IfIcmpEntrySize;
+ assert(IS_P2ALIGNED(ipv6IfIcmpEntrySize,
+ sizeof (mib2_ipv6IfIcmpEntry_t *)));
+ break;
+ }
+ case MIB2_TCP: {
+ mib2_tcp_t *tcp = (mib2_tcp_t *)item->valp;
+
+ tcpConnEntrySize = tcp->tcpConnTableSize;
+ tcp6ConnEntrySize = tcp->tcp6ConnTableSize;
+ assert(IS_P2ALIGNED(tcpConnEntrySize,
+ sizeof (mib2_tcpConnEntry_t *)) &&
+ IS_P2ALIGNED(tcp6ConnEntrySize,
+ sizeof (mib2_tcp6ConnEntry_t *)));
+ break;
+ }
+ case MIB2_UDP: {
+ mib2_udp_t *udp = (mib2_udp_t *)item->valp;
+
+ udpEntrySize = udp->udpEntrySize;
+ udp6EntrySize = udp->udp6EntrySize;
+ assert(IS_P2ALIGNED(udpEntrySize,
+ sizeof (mib2_udpEntry_t *)) &&
+ IS_P2ALIGNED(udp6EntrySize,
+ sizeof (mib2_udp6Entry_t *)));
+ break;
+ }
+ case MIB2_SCTP: {
+ mib2_sctp_t *sctp = (mib2_sctp_t *)item->valp;
+
+ sctpEntrySize = sctp->sctpEntrySize;
+ sctpLocalEntrySize = sctp->sctpLocalEntrySize;
+ sctpRemoteEntrySize = sctp->sctpRemoteEntrySize;
+ break;
+ }
+ }
+ } /* 'for' loop 1 ends */
+
+ if (Dflag) {
+ (void) puts("mib_get_constants:");
+ (void) printf("\tipv6IfStatsEntrySize %d\n",
+ ipv6IfStatsEntrySize);
+ (void) printf("\tipAddrEntrySize %d\n", ipAddrEntrySize);
+ (void) printf("\tipRouteEntrySize %d\n", ipRouteEntrySize);
+ (void) printf("\tipNetToMediaEntrySize %d\n",
+ ipNetToMediaEntrySize);
+ (void) printf("\tipMemberEntrySize %d\n", ipMemberEntrySize);
+ (void) printf("\tvifctlSize %d\n", vifctlSize);
+ (void) printf("\tmfcctlSize %d\n", mfcctlSize);
+
+ (void) printf("\tipv6AddrEntrySize %d\n", ipv6AddrEntrySize);
+ (void) printf("\tipv6RouteEntrySize %d\n", ipv6RouteEntrySize);
+ (void) printf("\tipv6NetToMediaEntrySize %d\n",
+ ipv6NetToMediaEntrySize);
+ (void) printf("\tipv6MemberEntrySize %d\n",
+ ipv6MemberEntrySize);
+ (void) printf("\tipv6IfIcmpEntrySize %d\n",
+ ipv6IfIcmpEntrySize);
+ (void) printf("\ttcpConnEntrySize %d\n", tcpConnEntrySize);
+ (void) printf("\ttcp6ConnEntrySize %d\n", tcp6ConnEntrySize);
+ (void) printf("\tudpEntrySize %d\n", udpEntrySize);
+ (void) printf("\tudp6EntrySize %d\n", udp6EntrySize);
+ (void) printf("\tsctpEntrySize %d\n", sctpEntrySize);
+ (void) printf("\tsctpLocalEntrySize %d\n", sctpLocalEntrySize);
+ (void) printf("\tsctpRemoteEntrySize %d\n",
+ sctpRemoteEntrySize);
+ }
+}
+
+
+/* ----------------------------- STAT_REPORT ------------------------------- */
+
+static void
+stat_report(mib_item_t *item)
+{
+ int jtemp = 0;
+ char ifname[LIFNAMSIZ + 1];
+ char *ifnamep;
+
+ /* 'for' loop 1: */
+ for (; item; item = item->next_item) {
+ if (Dflag) {
+ (void) printf("\n--- Entry %d ---\n", ++jtemp);
+ (void) printf("Group = %d, mib_id = %d, "
+ "length = %d, valp = 0x%p\n",
+ item->group, item->mib_id,
+ item->length, item->valp);
+ }
+ if (item->mib_id != 0)
+ continue; /* 'for' loop 1 */
+
+ switch (item->group) {
+ case MIB2_IP: {
+ mib2_ip_t *ip = (mib2_ip_t *)item->valp;
+
+ if (protocol_selected(IPPROTO_IP) &&
+ family_selected(AF_INET)) {
+ (void) fputs(v4compat ? "\nIP" : "\nIPv4",
+ stdout);
+ print_ip_stats(ip);
+ }
+ break;
+ }
+ case MIB2_ICMP: {
+ mib2_icmp_t *icmp =
+ (mib2_icmp_t *)item->valp;
+
+ if (protocol_selected(IPPROTO_ICMP) &&
+ family_selected(AF_INET)) {
+ (void) fputs(v4compat ? "\nICMP" : "\nICMPv4",
+ stdout);
+ print_icmp_stats(icmp);
+ }
+ break;
+ }
+ case MIB2_IP6: {
+ mib2_ipv6IfStatsEntry_t *ip6;
+ mib2_ipv6IfStatsEntry_t sum6;
+
+ if (!(protocol_selected(IPPROTO_IPV6)) ||
+ !(family_selected(AF_INET6)))
+ break;
+ bzero(&sum6, sizeof (sum6));
+ /* 'for' loop 2a: */
+ for (ip6 = (mib2_ipv6IfStatsEntry_t *)item->valp;
+ (char *)ip6 < (char *)item->valp
+ + item->length;
+ /* LINTED: (note 1) */
+ ip6 = (mib2_ipv6IfStatsEntry_t *)((char *)ip6 +
+ ipv6IfStatsEntrySize)) {
+
+ if (ip6->ipv6IfIndex == 0) {
+ /*
+ * The "unknown interface" ip6
+ * mib. Just add to the sum.
+ */
+ sum_ip6_stats(ip6, &sum6);
+ continue; /* 'for' loop 2a */
+ }
+ ifnamep = if_indextoname(
+ ip6->ipv6IfIndex,
+ ifname);
+ if (ifnamep == NULL) {
+ (void) printf(
+ "Invalid ifindex %d\n",
+ ip6->ipv6IfIndex);
+ continue; /* 'for' loop 2a */
+ }
+
+ if (Aflag) {
+ (void) printf("\nIPv6 for %s\n",
+ ifnamep);
+ print_ip6_stats(ip6);
+ }
+ sum_ip6_stats(ip6, &sum6);
+ } /* 'for' loop 2a ends */
+ (void) fputs("\nIPv6", stdout);
+ print_ip6_stats(&sum6);
+ break;
+ }
+ case MIB2_ICMP6: {
+ mib2_ipv6IfIcmpEntry_t *icmp6;
+ mib2_ipv6IfIcmpEntry_t sum6;
+
+ if (!(protocol_selected(IPPROTO_ICMPV6)) ||
+ !(family_selected(AF_INET6)))
+ break;
+ bzero(&sum6, sizeof (sum6));
+ /* 'for' loop 2b: */
+ for (icmp6 =
+ (mib2_ipv6IfIcmpEntry_t *)item->valp;
+ (char *)icmp6 < (char *)item->valp
+ + item->length;
+ icmp6 =
+ /* LINTED: (note 1) */
+ (mib2_ipv6IfIcmpEntry_t *)((char *)icmp6
+ + ipv6IfIcmpEntrySize)) {
+
+ if (icmp6->ipv6IfIcmpIfIndex == 0) {
+ /*
+ * The "unknown interface" icmp6
+ * mib. Just add to the sum.
+ */
+ sum_icmp6_stats(icmp6, &sum6);
+ continue; /* 'for' loop 2b: */
+ }
+ ifnamep = if_indextoname(
+ icmp6->ipv6IfIcmpIfIndex, ifname);
+ if (ifnamep == NULL) {
+ (void) printf(
+ "Invalid ifindex %d\n",
+ icmp6->ipv6IfIcmpIfIndex);
+ continue; /* 'for' loop 2b: */
+ }
+
+ if (Aflag) {
+ (void) printf(
+ "\nICMPv6 for %s\n",
+ ifnamep);
+ print_icmp6_stats(icmp6);
+ }
+ sum_icmp6_stats(icmp6, &sum6);
+ } /* 'for' loop 2b ends */
+ (void) fputs("\nICMPv6", stdout);
+ print_icmp6_stats(&sum6);
+ break;
+ }
+ case MIB2_TCP: {
+ mib2_tcp_t *tcp = (mib2_tcp_t *)item->valp;
+
+ if (protocol_selected(IPPROTO_TCP) &&
+ (family_selected(AF_INET) ||
+ family_selected(AF_INET6))) {
+ (void) fputs("\nTCP", stdout);
+ print_tcp_stats(tcp);
+ }
+ break;
+ }
+ case MIB2_UDP: {
+ mib2_udp_t *udp = (mib2_udp_t *)item->valp;
+
+ if (protocol_selected(IPPROTO_UDP) &&
+ (family_selected(AF_INET) ||
+ family_selected(AF_INET6))) {
+ (void) fputs("\nUDP", stdout);
+ print_udp_stats(udp);
+ }
+ break;
+ }
+ case MIB2_SCTP: {
+ mib2_sctp_t *sctp = (mib2_sctp_t *)item->valp;
+
+ if (protocol_selected(IPPROTO_SCTP) &&
+ (family_selected(AF_INET) ||
+ family_selected(AF_INET6))) {
+ (void) fputs("\nSCTP", stdout);
+ print_sctp_stats(sctp);
+ }
+ break;
+ }
+ case EXPER_RAWIP: {
+ mib2_rawip_t *rawip =
+ (mib2_rawip_t *)item->valp;
+
+ if (protocol_selected(IPPROTO_RAW) &&
+ (family_selected(AF_INET) ||
+ family_selected(AF_INET6))) {
+ (void) fputs("\nRAWIP", stdout);
+ print_rawip_stats(rawip);
+ }
+ break;
+ }
+ case EXPER_IGMP: {
+ struct igmpstat *igps =
+ (struct igmpstat *)item->valp;
+
+ if (protocol_selected(IPPROTO_IGMP) &&
+ (family_selected(AF_INET))) {
+ (void) fputs("\nIGMP:\n", stdout);
+ print_igmp_stats(igps);
+ }
+ break;
+ }
+ }
+ } /* 'for' loop 1 ends */
+ (void) putchar('\n');
+ (void) fflush(stdout);
+}
+
+static void
+print_ip_stats(mib2_ip_t *ip)
+{
+ prval_init();
+ pr_int_val("ipForwarding", ip->ipForwarding);
+ pr_int_val("ipDefaultTTL", ip->ipDefaultTTL);
+ prval("ipInReceives", ip->ipInReceives);
+ prval("ipInHdrErrors", ip->ipInHdrErrors);
+ prval("ipInAddrErrors", ip->ipInAddrErrors);
+ prval("ipInCksumErrs", ip->ipInCksumErrs);
+ prval("ipForwDatagrams", ip->ipForwDatagrams);
+ prval("ipForwProhibits", ip->ipForwProhibits);
+ prval("ipInUnknownProtos", ip->ipInUnknownProtos);
+ prval("ipInDiscards", ip->ipInDiscards);
+ prval("ipInDelivers", ip->ipInDelivers);
+ prval("ipOutRequests", ip->ipOutRequests);
+ prval("ipOutDiscards", ip->ipOutDiscards);
+ prval("ipOutNoRoutes", ip->ipOutNoRoutes);
+ pr_int_val("ipReasmTimeout", ip->ipReasmTimeout);
+ prval("ipReasmReqds", ip->ipReasmReqds);
+ prval("ipReasmOKs", ip->ipReasmOKs);
+ prval("ipReasmFails", ip->ipReasmFails);
+ prval("ipReasmDuplicates", ip->ipReasmDuplicates);
+ prval("ipReasmPartDups", ip->ipReasmPartDups);
+ prval("ipFragOKs", ip->ipFragOKs);
+ prval("ipFragFails", ip->ipFragFails);
+ prval("ipFragCreates", ip->ipFragCreates);
+ prval("ipRoutingDiscards", ip->ipRoutingDiscards);
+
+ prval("tcpInErrs", ip->tcpInErrs);
+ prval("udpNoPorts", ip->udpNoPorts);
+ prval("udpInCksumErrs", ip->udpInCksumErrs);
+ prval("udpInOverflows", ip->udpInOverflows);
+ prval("rawipInOverflows", ip->rawipInOverflows);
+ prval("ipsecInSucceeded", ip->ipsecInSucceeded);
+ prval("ipsecInFailed", ip->ipsecInFailed);
+ prval("ipInIPv6", ip->ipInIPv6);
+ prval("ipOutIPv6", ip->ipOutIPv6);
+ prval("ipOutSwitchIPv6", ip->ipOutSwitchIPv6);
+ prval_end();
+}
+
+static void
+print_icmp_stats(mib2_icmp_t *icmp)
+{
+ prval_init();
+ prval("icmpInMsgs", icmp->icmpInMsgs);
+ prval("icmpInErrors", icmp->icmpInErrors);
+ prval("icmpInCksumErrs", icmp->icmpInCksumErrs);
+ prval("icmpInUnknowns", icmp->icmpInUnknowns);
+ prval("icmpInDestUnreachs", icmp->icmpInDestUnreachs);
+ prval("icmpInTimeExcds", icmp->icmpInTimeExcds);
+ prval("icmpInParmProbs", icmp->icmpInParmProbs);
+ prval("icmpInSrcQuenchs", icmp->icmpInSrcQuenchs);
+ prval("icmpInRedirects", icmp->icmpInRedirects);
+ prval("icmpInBadRedirects", icmp->icmpInBadRedirects);
+ prval("icmpInEchos", icmp->icmpInEchos);
+ prval("icmpInEchoReps", icmp->icmpInEchoReps);
+ prval("icmpInTimestamps", icmp->icmpInTimestamps);
+ prval("icmpInTimestampReps", icmp->icmpInTimestampReps);
+ prval("icmpInAddrMasks", icmp->icmpInAddrMasks);
+ prval("icmpInAddrMaskReps", icmp->icmpInAddrMaskReps);
+ prval("icmpInFragNeeded", icmp->icmpInFragNeeded);
+ prval("icmpOutMsgs", icmp->icmpOutMsgs);
+ prval("icmpOutDrops", icmp->icmpOutDrops);
+ prval("icmpOutErrors", icmp->icmpOutErrors);
+ prval("icmpOutDestUnreachs", icmp->icmpOutDestUnreachs);
+ prval("icmpOutTimeExcds", icmp->icmpOutTimeExcds);
+ prval("icmpOutParmProbs", icmp->icmpOutParmProbs);
+ prval("icmpOutSrcQuenchs", icmp->icmpOutSrcQuenchs);
+ prval("icmpOutRedirects", icmp->icmpOutRedirects);
+ prval("icmpOutEchos", icmp->icmpOutEchos);
+ prval("icmpOutEchoReps", icmp->icmpOutEchoReps);
+ prval("icmpOutTimestamps", icmp->icmpOutTimestamps);
+ prval("icmpOutTimestampReps", icmp->icmpOutTimestampReps);
+ prval("icmpOutAddrMasks", icmp->icmpOutAddrMasks);
+ prval("icmpOutAddrMaskReps", icmp->icmpOutAddrMaskReps);
+ prval("icmpOutFragNeeded", icmp->icmpOutFragNeeded);
+ prval("icmpInOverflows", icmp->icmpInOverflows);
+ prval_end();
+}
+
+static void
+print_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6)
+{
+ prval_init();
+ prval("ipv6Forwarding", ip6->ipv6Forwarding);
+ prval("ipv6DefaultHopLimit", ip6->ipv6DefaultHopLimit);
+
+ prval("ipv6InReceives", ip6->ipv6InReceives);
+ prval("ipv6InHdrErrors", ip6->ipv6InHdrErrors);
+ prval("ipv6InTooBigErrors", ip6->ipv6InTooBigErrors);
+ prval("ipv6InNoRoutes", ip6->ipv6InNoRoutes);
+ prval("ipv6InAddrErrors", ip6->ipv6InAddrErrors);
+ prval("ipv6InUnknownProtos", ip6->ipv6InUnknownProtos);
+ prval("ipv6InTruncatedPkts", ip6->ipv6InTruncatedPkts);
+ prval("ipv6InDiscards", ip6->ipv6InDiscards);
+ prval("ipv6InDelivers", ip6->ipv6InDelivers);
+ prval("ipv6OutForwDatagrams", ip6->ipv6OutForwDatagrams);
+ prval("ipv6OutRequests", ip6->ipv6OutRequests);
+ prval("ipv6OutDiscards", ip6->ipv6OutDiscards);
+ prval("ipv6OutNoRoutes", ip6->ipv6OutNoRoutes);
+ prval("ipv6OutFragOKs", ip6->ipv6OutFragOKs);
+ prval("ipv6OutFragFails", ip6->ipv6OutFragFails);
+ prval("ipv6OutFragCreates", ip6->ipv6OutFragCreates);
+ prval("ipv6ReasmReqds", ip6->ipv6ReasmReqds);
+ prval("ipv6ReasmOKs", ip6->ipv6ReasmOKs);
+ prval("ipv6ReasmFails", ip6->ipv6ReasmFails);
+ prval("ipv6InMcastPkts", ip6->ipv6InMcastPkts);
+ prval("ipv6OutMcastPkts", ip6->ipv6OutMcastPkts);
+ prval("ipv6ReasmDuplicates", ip6->ipv6ReasmDuplicates);
+ prval("ipv6ReasmPartDups", ip6->ipv6ReasmPartDups);
+ prval("ipv6ForwProhibits", ip6->ipv6ForwProhibits);
+ prval("udpInCksumErrs", ip6->udpInCksumErrs);
+ prval("udpInOverflows", ip6->udpInOverflows);
+ prval("rawipInOverflows", ip6->rawipInOverflows);
+ prval("ipv6InIPv4", ip6->ipv6InIPv4);
+ prval("ipv6OutIPv4", ip6->ipv6OutIPv4);
+ prval("ipv6OutSwitchIPv4", ip6->ipv6OutSwitchIPv4);
+ prval_end();
+}
+
+static void
+print_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6)
+{
+ prval_init();
+ prval("icmp6InMsgs", icmp6->ipv6IfIcmpInMsgs);
+ prval("icmp6InErrors", icmp6->ipv6IfIcmpInErrors);
+ prval("icmp6InDestUnreachs", icmp6->ipv6IfIcmpInDestUnreachs);
+ prval("icmp6InAdminProhibs", icmp6->ipv6IfIcmpInAdminProhibs);
+ prval("icmp6InTimeExcds", icmp6->ipv6IfIcmpInTimeExcds);
+ prval("icmp6InParmProblems", icmp6->ipv6IfIcmpInParmProblems);
+ prval("icmp6InPktTooBigs", icmp6->ipv6IfIcmpInPktTooBigs);
+ prval("icmp6InEchos", icmp6->ipv6IfIcmpInEchos);
+ prval("icmp6InEchoReplies", icmp6->ipv6IfIcmpInEchoReplies);
+ prval("icmp6InRouterSols", icmp6->ipv6IfIcmpInRouterSolicits);
+ prval("icmp6InRouterAds",
+ icmp6->ipv6IfIcmpInRouterAdvertisements);
+ prval("icmp6InNeighborSols", icmp6->ipv6IfIcmpInNeighborSolicits);
+ prval("icmp6InNeighborAds",
+ icmp6->ipv6IfIcmpInNeighborAdvertisements);
+ prval("icmp6InRedirects", icmp6->ipv6IfIcmpInRedirects);
+ prval("icmp6InBadRedirects", icmp6->ipv6IfIcmpInBadRedirects);
+ prval("icmp6InGroupQueries", icmp6->ipv6IfIcmpInGroupMembQueries);
+ prval("icmp6InGroupResps", icmp6->ipv6IfIcmpInGroupMembResponses);
+ prval("icmp6InGroupReds", icmp6->ipv6IfIcmpInGroupMembReductions);
+ prval("icmp6InOverflows", icmp6->ipv6IfIcmpInOverflows);
+ prval_end();
+ prval_init();
+ prval("icmp6OutMsgs", icmp6->ipv6IfIcmpOutMsgs);
+ prval("icmp6OutErrors", icmp6->ipv6IfIcmpOutErrors);
+ prval("icmp6OutDestUnreachs", icmp6->ipv6IfIcmpOutDestUnreachs);
+ prval("icmp6OutAdminProhibs", icmp6->ipv6IfIcmpOutAdminProhibs);
+ prval("icmp6OutTimeExcds", icmp6->ipv6IfIcmpOutTimeExcds);
+ prval("icmp6OutParmProblems", icmp6->ipv6IfIcmpOutParmProblems);
+ prval("icmp6OutPktTooBigs", icmp6->ipv6IfIcmpOutPktTooBigs);
+ prval("icmp6OutEchos", icmp6->ipv6IfIcmpOutEchos);
+ prval("icmp6OutEchoReplies", icmp6->ipv6IfIcmpOutEchoReplies);
+ prval("icmp6OutRouterSols", icmp6->ipv6IfIcmpOutRouterSolicits);
+ prval("icmp6OutRouterAds",
+ icmp6->ipv6IfIcmpOutRouterAdvertisements);
+ prval("icmp6OutNeighborSols", icmp6->ipv6IfIcmpOutNeighborSolicits);
+ prval("icmp6OutNeighborAds",
+ icmp6->ipv6IfIcmpOutNeighborAdvertisements);
+ prval("icmp6OutRedirects", icmp6->ipv6IfIcmpOutRedirects);
+ prval("icmp6OutGroupQueries", icmp6->ipv6IfIcmpOutGroupMembQueries);
+ prval("icmp6OutGroupResps",
+ icmp6->ipv6IfIcmpOutGroupMembResponses);
+ prval("icmp6OutGroupReds",
+ icmp6->ipv6IfIcmpOutGroupMembReductions);
+ prval_end();
+}
+
+static void
+print_sctp_stats(mib2_sctp_t *sctp)
+{
+ prval_init();
+ pr_sctp_rtoalgo("sctpRtoAlgorithm", sctp->sctpRtoAlgorithm);
+ prval("sctpRtoMin", sctp->sctpRtoMin);
+ prval("sctpRtoMax", sctp->sctpRtoMax);
+ prval("sctpRtoInitial", sctp->sctpRtoInitial);
+ pr_int_val("sctpMaxAssocs", sctp->sctpMaxAssocs);
+ prval("sctpValCookieLife", sctp->sctpValCookieLife);
+ prval("sctpMaxInitRetr", sctp->sctpMaxInitRetr);
+ prval("sctpCurrEstab", sctp->sctpCurrEstab);
+ prval("sctpActiveEstab", sctp->sctpActiveEstab);
+ prval("sctpPassiveEstab", sctp->sctpPassiveEstab);
+ prval("sctpAborted", sctp->sctpAborted);
+ prval("sctpShutdowns", sctp->sctpShutdowns);
+ prval("sctpOutOfBlue", sctp->sctpOutOfBlue);
+ prval("sctpChecksumError", sctp->sctpChecksumError);
+ prval64("sctpOutCtrlChunks", sctp->sctpOutCtrlChunks);
+ prval64("sctpOutOrderChunks", sctp->sctpOutOrderChunks);
+ prval64("sctpOutUnorderChunks", sctp->sctpOutUnorderChunks);
+ prval64("sctpRetransChunks", sctp->sctpRetransChunks);
+ prval("sctpOutAck", sctp->sctpOutAck);
+ prval("sctpOutAckDelayed", sctp->sctpOutAckDelayed);
+ prval("sctpOutWinUpdate", sctp->sctpOutWinUpdate);
+ prval("sctpOutFastRetrans", sctp->sctpOutFastRetrans);
+ prval("sctpOutWinProbe", sctp->sctpOutWinProbe);
+ prval64("sctpInCtrlChunks", sctp->sctpInCtrlChunks);
+ prval64("sctpInOrderChunks", sctp->sctpInOrderChunks);
+ prval64("sctpInUnorderChunks", sctp->sctpInUnorderChunks);
+ prval("sctpInAck", sctp->sctpInAck);
+ prval("sctpInDupAck", sctp->sctpInDupAck);
+ prval("sctpInAckUnsent", sctp->sctpInAckUnsent);
+ prval64("sctpFragUsrMsgs", sctp->sctpFragUsrMsgs);
+ prval64("sctpReasmUsrMsgs", sctp->sctpReasmUsrMsgs);
+ prval64("sctpOutSCTPPkts", sctp->sctpOutSCTPPkts);
+ prval64("sctpInSCTPPkts", sctp->sctpInSCTPPkts);
+ prval("sctpInInvalidCookie", sctp->sctpInInvalidCookie);
+ prval("sctpTimRetrans", sctp->sctpTimRetrans);
+ prval("sctpTimRetransDrop", sctp->sctpTimRetransDrop);
+ prval("sctpTimHearBeatProbe", sctp->sctpTimHeartBeatProbe);
+ prval("sctpTimHearBeatDrop", sctp->sctpTimHeartBeatDrop);
+ prval("sctpListenDrop", sctp->sctpListenDrop);
+ prval("sctpInClosed", sctp->sctpInClosed);
+ prval_end();
+}
+
+static void
+print_tcp_stats(mib2_tcp_t *tcp)
+{
+ prval_init();
+ pr_int_val("tcpRtoAlgorithm", tcp->tcpRtoAlgorithm);
+ pr_int_val("tcpRtoMin", tcp->tcpRtoMin);
+ pr_int_val("tcpRtoMax", tcp->tcpRtoMax);
+ pr_int_val("tcpMaxConn", tcp->tcpMaxConn);
+ prval("tcpActiveOpens", tcp->tcpActiveOpens);
+ prval("tcpPassiveOpens", tcp->tcpPassiveOpens);
+ prval("tcpAttemptFails", tcp->tcpAttemptFails);
+ prval("tcpEstabResets", tcp->tcpEstabResets);
+ prval("tcpCurrEstab", tcp->tcpCurrEstab);
+ prval("tcpOutSegs", tcp->tcpOutSegs);
+ prval("tcpOutDataSegs", tcp->tcpOutDataSegs);
+ prval("tcpOutDataBytes", tcp->tcpOutDataBytes);
+ prval("tcpRetransSegs", tcp->tcpRetransSegs);
+ prval("tcpRetransBytes", tcp->tcpRetransBytes);
+ prval("tcpOutAck", tcp->tcpOutAck);
+ prval("tcpOutAckDelayed", tcp->tcpOutAckDelayed);
+ prval("tcpOutUrg", tcp->tcpOutUrg);
+ prval("tcpOutWinUpdate", tcp->tcpOutWinUpdate);
+ prval("tcpOutWinProbe", tcp->tcpOutWinProbe);
+ prval("tcpOutControl", tcp->tcpOutControl);
+ prval("tcpOutRsts", tcp->tcpOutRsts);
+ prval("tcpOutFastRetrans", tcp->tcpOutFastRetrans);
+ prval("tcpInSegs", tcp->tcpInSegs);
+ prval_end();
+ prval("tcpInAckSegs", tcp->tcpInAckSegs);
+ prval("tcpInAckBytes", tcp->tcpInAckBytes);
+ prval("tcpInDupAck", tcp->tcpInDupAck);
+ prval("tcpInAckUnsent", tcp->tcpInAckUnsent);
+ prval("tcpInInorderSegs", tcp->tcpInDataInorderSegs);
+ prval("tcpInInorderBytes", tcp->tcpInDataInorderBytes);
+ prval("tcpInUnorderSegs", tcp->tcpInDataUnorderSegs);
+ prval("tcpInUnorderBytes", tcp->tcpInDataUnorderBytes);
+ prval("tcpInDupSegs", tcp->tcpInDataDupSegs);
+ prval("tcpInDupBytes", tcp->tcpInDataDupBytes);
+ prval("tcpInPartDupSegs", tcp->tcpInDataPartDupSegs);
+ prval("tcpInPartDupBytes", tcp->tcpInDataPartDupBytes);
+ prval("tcpInPastWinSegs", tcp->tcpInDataPastWinSegs);
+ prval("tcpInPastWinBytes", tcp->tcpInDataPastWinBytes);
+ prval("tcpInWinProbe", tcp->tcpInWinProbe);
+ prval("tcpInWinUpdate", tcp->tcpInWinUpdate);
+ prval("tcpInClosed", tcp->tcpInClosed);
+ prval("tcpRttNoUpdate", tcp->tcpRttNoUpdate);
+ prval("tcpRttUpdate", tcp->tcpRttUpdate);
+ prval("tcpTimRetrans", tcp->tcpTimRetrans);
+ prval("tcpTimRetransDrop", tcp->tcpTimRetransDrop);
+ prval("tcpTimKeepalive", tcp->tcpTimKeepalive);
+ prval("tcpTimKeepaliveProbe", tcp->tcpTimKeepaliveProbe);
+ prval("tcpTimKeepaliveDrop", tcp->tcpTimKeepaliveDrop);
+ prval("tcpListenDrop", tcp->tcpListenDrop);
+ prval("tcpListenDropQ0", tcp->tcpListenDropQ0);
+ prval("tcpHalfOpenDrop", tcp->tcpHalfOpenDrop);
+ prval("tcpOutSackRetrans", tcp->tcpOutSackRetransSegs);
+ prval_end();
+
+}
+
+static void
+print_udp_stats(mib2_udp_t *udp)
+{
+ prval_init();
+ prval("udpInDatagrams", udp->udpInDatagrams);
+ prval("udpInErrors", udp->udpInErrors);
+ prval("udpOutDatagrams", udp->udpOutDatagrams);
+ prval("udpOutErrors", udp->udpOutErrors);
+ prval_end();
+}
+
+static void
+print_rawip_stats(mib2_rawip_t *rawip)
+{
+ prval_init();
+ prval("rawipInDatagrams", rawip->rawipInDatagrams);
+ prval("rawipInErrors", rawip->rawipInErrors);
+ prval("rawipInCksumErrs", rawip->rawipInCksumErrs);
+ prval("rawipOutDatagrams", rawip->rawipOutDatagrams);
+ prval("rawipOutErrors", rawip->rawipOutErrors);
+ prval_end();
+}
+
+void
+print_igmp_stats(struct igmpstat *igps)
+{
+ (void) printf(" %10u message%s received\n",
+ igps->igps_rcv_total, PLURAL(igps->igps_rcv_total));
+ (void) printf(" %10u message%s received with too few bytes\n",
+ igps->igps_rcv_tooshort, PLURAL(igps->igps_rcv_tooshort));
+ (void) printf(" %10u message%s received with bad checksum\n",
+ igps->igps_rcv_badsum, PLURAL(igps->igps_rcv_badsum));
+ (void) printf(" %10u membership quer%s received\n",
+ igps->igps_rcv_queries, PLURALY(igps->igps_rcv_queries));
+ (void) printf(" %10u membership quer%s received with invalid "
+ "field(s)\n",
+ igps->igps_rcv_badqueries, PLURALY(igps->igps_rcv_badqueries));
+ (void) printf(" %10u membership report%s received\n",
+ igps->igps_rcv_reports, PLURAL(igps->igps_rcv_reports));
+ (void) printf(" %10u membership report%s received with invalid "
+ "field(s)\n",
+ igps->igps_rcv_badreports, PLURAL(igps->igps_rcv_badreports));
+ (void) printf(" %10u membership report%s received for groups to "
+ "which we belong\n",
+ igps->igps_rcv_ourreports, PLURAL(igps->igps_rcv_ourreports));
+ (void) printf(" %10u membership report%s sent\n",
+ igps->igps_snd_reports, PLURAL(igps->igps_snd_reports));
+}
+
+static void
+print_mrt_stats(struct mrtstat *mrts)
+{
+ (void) puts("DVMRP multicast routing:");
+ (void) printf(" %10u hit%s - kernel forwarding cache hits\n",
+ mrts->mrts_mfc_hits, PLURAL(mrts->mrts_mfc_hits));
+ (void) printf(" %10u miss%s - kernel forwarding cache misses\n",
+ mrts->mrts_mfc_misses, PLURALES(mrts->mrts_mfc_misses));
+ (void) printf(" %10u packet%s potentially forwarded\n",
+ mrts->mrts_fwd_in, PLURAL(mrts->mrts_fwd_in));
+ (void) printf(" %10u packet%s actually sent out\n",
+ mrts->mrts_fwd_out, PLURAL(mrts->mrts_fwd_out));
+ (void) printf(" %10u upcall%s - upcalls made to mrouted\n",
+ mrts->mrts_upcalls, PLURAL(mrts->mrts_upcalls));
+ (void) printf(" %10u packet%s not sent out due to lack of resources\n",
+ mrts->mrts_fwd_drop, PLURAL(mrts->mrts_fwd_drop));
+ (void) printf(" %10u datagram%s with malformed tunnel options\n",
+ mrts->mrts_bad_tunnel, PLURAL(mrts->mrts_bad_tunnel));
+ (void) printf(" %10u datagram%s with no room for tunnel options\n",
+ mrts->mrts_cant_tunnel, PLURAL(mrts->mrts_cant_tunnel));
+ (void) printf(" %10u datagram%s arrived on wrong interface\n",
+ mrts->mrts_wrong_if, PLURAL(mrts->mrts_wrong_if));
+ (void) printf(" %10u datagram%s dropped due to upcall Q overflow\n",
+ mrts->mrts_upq_ovflw, PLURAL(mrts->mrts_upq_ovflw));
+ (void) printf(" %10u datagram%s cleaned up by the cache\n",
+ mrts->mrts_cache_cleanups, PLURAL(mrts->mrts_cache_cleanups));
+ (void) printf(" %10u datagram%s dropped selectively by ratelimiter\n",
+ mrts->mrts_drop_sel, PLURAL(mrts->mrts_drop_sel));
+ (void) printf(" %10u datagram%s dropped - bucket Q overflow\n",
+ mrts->mrts_q_overflow, PLURAL(mrts->mrts_q_overflow));
+ (void) printf(" %10u datagram%s dropped - larger than bkt size\n",
+ mrts->mrts_pkt2large, PLURAL(mrts->mrts_pkt2large));
+ (void) printf("\nPIM multicast routing:\n");
+ (void) printf(" %10u datagram%s dropped - bad version number\n",
+ mrts->mrts_pim_badversion, PLURAL(mrts->mrts_pim_badversion));
+ (void) printf(" %10u datagram%s dropped - bad checksum\n",
+ mrts->mrts_pim_rcv_badcsum, PLURAL(mrts->mrts_pim_rcv_badcsum));
+ (void) printf(" %10u datagram%s dropped - bad register packets\n",
+ mrts->mrts_pim_badregisters,
+ PLURAL(mrts->mrts_pim_badregisters));
+ (void) printf(
+ " %10u datagram%s potentially forwarded - register packets\n",
+ mrts->mrts_pim_regforwards, PLURAL(mrts->mrts_pim_regforwards));
+ (void) printf(" %10u datagram%s dropped - register send drops\n",
+ mrts->mrts_pim_regsend_drops,
+ PLURAL(mrts->mrts_pim_regsend_drops));
+ (void) printf(" %10u datagram%s dropped - packet malformed\n",
+ mrts->mrts_pim_malformed, PLURAL(mrts->mrts_pim_malformed));
+ (void) printf(" %10u datagram%s dropped - no memory to forward\n",
+ mrts->mrts_pim_nomemory, PLURAL(mrts->mrts_pim_nomemory));
+}
+
+static void
+sum_ip6_stats(mib2_ipv6IfStatsEntry_t *ip6, mib2_ipv6IfStatsEntry_t *sum6)
+{
+ /* First few are not additive */
+ sum6->ipv6Forwarding = ip6->ipv6Forwarding;
+ sum6->ipv6DefaultHopLimit = ip6->ipv6DefaultHopLimit;
+
+ sum6->ipv6InReceives += ip6->ipv6InReceives;
+ sum6->ipv6InHdrErrors += ip6->ipv6InHdrErrors;
+ sum6->ipv6InTooBigErrors += ip6->ipv6InTooBigErrors;
+ sum6->ipv6InNoRoutes += ip6->ipv6InNoRoutes;
+ sum6->ipv6InAddrErrors += ip6->ipv6InAddrErrors;
+ sum6->ipv6InUnknownProtos += ip6->ipv6InUnknownProtos;
+ sum6->ipv6InTruncatedPkts += ip6->ipv6InTruncatedPkts;
+ sum6->ipv6InDiscards += ip6->ipv6InDiscards;
+ sum6->ipv6InDelivers += ip6->ipv6InDelivers;
+ sum6->ipv6OutForwDatagrams += ip6->ipv6OutForwDatagrams;
+ sum6->ipv6OutRequests += ip6->ipv6OutRequests;
+ sum6->ipv6OutDiscards += ip6->ipv6OutDiscards;
+ sum6->ipv6OutFragOKs += ip6->ipv6OutFragOKs;
+ sum6->ipv6OutFragFails += ip6->ipv6OutFragFails;
+ sum6->ipv6OutFragCreates += ip6->ipv6OutFragCreates;
+ sum6->ipv6ReasmReqds += ip6->ipv6ReasmReqds;
+ sum6->ipv6ReasmOKs += ip6->ipv6ReasmOKs;
+ sum6->ipv6ReasmFails += ip6->ipv6ReasmFails;
+ sum6->ipv6InMcastPkts += ip6->ipv6InMcastPkts;
+ sum6->ipv6OutMcastPkts += ip6->ipv6OutMcastPkts;
+ sum6->ipv6OutNoRoutes += ip6->ipv6OutNoRoutes;
+ sum6->ipv6ReasmDuplicates += ip6->ipv6ReasmDuplicates;
+ sum6->ipv6ReasmPartDups += ip6->ipv6ReasmPartDups;
+ sum6->ipv6ForwProhibits += ip6->ipv6ForwProhibits;
+ sum6->udpInCksumErrs += ip6->udpInCksumErrs;
+ sum6->udpInOverflows += ip6->udpInOverflows;
+ sum6->rawipInOverflows += ip6->rawipInOverflows;
+}
+
+static void
+sum_icmp6_stats(mib2_ipv6IfIcmpEntry_t *icmp6, mib2_ipv6IfIcmpEntry_t *sum6)
+{
+ sum6->ipv6IfIcmpInMsgs += icmp6->ipv6IfIcmpInMsgs;
+ sum6->ipv6IfIcmpInErrors += icmp6->ipv6IfIcmpInErrors;
+ sum6->ipv6IfIcmpInDestUnreachs += icmp6->ipv6IfIcmpInDestUnreachs;
+ sum6->ipv6IfIcmpInAdminProhibs += icmp6->ipv6IfIcmpInAdminProhibs;
+ sum6->ipv6IfIcmpInTimeExcds += icmp6->ipv6IfIcmpInTimeExcds;
+ sum6->ipv6IfIcmpInParmProblems += icmp6->ipv6IfIcmpInParmProblems;
+ sum6->ipv6IfIcmpInPktTooBigs += icmp6->ipv6IfIcmpInPktTooBigs;
+ sum6->ipv6IfIcmpInEchos += icmp6->ipv6IfIcmpInEchos;
+ sum6->ipv6IfIcmpInEchoReplies += icmp6->ipv6IfIcmpInEchoReplies;
+ sum6->ipv6IfIcmpInRouterSolicits += icmp6->ipv6IfIcmpInRouterSolicits;
+ sum6->ipv6IfIcmpInRouterAdvertisements +=
+ icmp6->ipv6IfIcmpInRouterAdvertisements;
+ sum6->ipv6IfIcmpInNeighborSolicits +=
+ icmp6->ipv6IfIcmpInNeighborSolicits;
+ sum6->ipv6IfIcmpInNeighborAdvertisements +=
+ icmp6->ipv6IfIcmpInNeighborAdvertisements;
+ sum6->ipv6IfIcmpInRedirects += icmp6->ipv6IfIcmpInRedirects;
+ sum6->ipv6IfIcmpInGroupMembQueries +=
+ icmp6->ipv6IfIcmpInGroupMembQueries;
+ sum6->ipv6IfIcmpInGroupMembResponses +=
+ icmp6->ipv6IfIcmpInGroupMembResponses;
+ sum6->ipv6IfIcmpInGroupMembReductions +=
+ icmp6->ipv6IfIcmpInGroupMembReductions;
+ sum6->ipv6IfIcmpOutMsgs += icmp6->ipv6IfIcmpOutMsgs;
+ sum6->ipv6IfIcmpOutErrors += icmp6->ipv6IfIcmpOutErrors;
+ sum6->ipv6IfIcmpOutDestUnreachs += icmp6->ipv6IfIcmpOutDestUnreachs;
+ sum6->ipv6IfIcmpOutAdminProhibs += icmp6->ipv6IfIcmpOutAdminProhibs;
+ sum6->ipv6IfIcmpOutTimeExcds += icmp6->ipv6IfIcmpOutTimeExcds;
+ sum6->ipv6IfIcmpOutParmProblems += icmp6->ipv6IfIcmpOutParmProblems;
+ sum6->ipv6IfIcmpOutPktTooBigs += icmp6->ipv6IfIcmpOutPktTooBigs;
+ sum6->ipv6IfIcmpOutEchos += icmp6->ipv6IfIcmpOutEchos;
+ sum6->ipv6IfIcmpOutEchoReplies += icmp6->ipv6IfIcmpOutEchoReplies;
+ sum6->ipv6IfIcmpOutRouterSolicits +=
+ icmp6->ipv6IfIcmpOutRouterSolicits;
+ sum6->ipv6IfIcmpOutRouterAdvertisements +=
+ icmp6->ipv6IfIcmpOutRouterAdvertisements;
+ sum6->ipv6IfIcmpOutNeighborSolicits +=
+ icmp6->ipv6IfIcmpOutNeighborSolicits;
+ sum6->ipv6IfIcmpOutNeighborAdvertisements +=
+ icmp6->ipv6IfIcmpOutNeighborAdvertisements;
+ sum6->ipv6IfIcmpOutRedirects += icmp6->ipv6IfIcmpOutRedirects;
+ sum6->ipv6IfIcmpOutGroupMembQueries +=
+ icmp6->ipv6IfIcmpOutGroupMembQueries;
+ sum6->ipv6IfIcmpOutGroupMembResponses +=
+ icmp6->ipv6IfIcmpOutGroupMembResponses;
+ sum6->ipv6IfIcmpOutGroupMembReductions +=
+ icmp6->ipv6IfIcmpOutGroupMembReductions;
+ sum6->ipv6IfIcmpInOverflows += icmp6->ipv6IfIcmpInOverflows;
+}
+
+/* ----------------------------- MRT_STAT_REPORT --------------------------- */
+
+static void
+mrt_stat_report(mib_item_t *curritem)
+{
+ int jtemp = 0;
+ mib_item_t *tempitem;
+
+ if (!(family_selected(AF_INET)))
+ return;
+
+ (void) putchar('\n');
+ /* 'for' loop 1: */
+ for (tempitem = curritem;
+ tempitem;
+ tempitem = tempitem->next_item) {
+ if (Dflag) {
+ (void) printf("\n--- Entry %d ---\n", ++jtemp);
+ (void) printf("Group = %d, mib_id = %d, "
+ "length = %d, valp = 0x%p\n",
+ tempitem->group, tempitem->mib_id,
+ tempitem->length, tempitem->valp);
+ }
+
+ if (tempitem->mib_id == 0) {
+ switch (tempitem->group) {
+ case EXPER_DVMRP: {
+ struct mrtstat *mrts;
+ mrts = (struct mrtstat *)tempitem->valp;
+
+ if (!(family_selected(AF_INET)))
+ continue; /* 'for' loop 1 */
+
+ print_mrt_stats(mrts);
+ break;
+ }
+ }
+ }
+ } /* 'for' loop 1 ends */
+ (void) putchar('\n');
+ (void) fflush(stdout);
+}
+
+/*
+ * if_stat_total() - Computes totals for interface statistics
+ * and returns result by updating sumstats.
+ */
+static void
+if_stat_total(struct ifstat *oldstats, struct ifstat *newstats,
+ struct ifstat *sumstats)
+{
+ sumstats->ipackets += newstats->ipackets - oldstats->ipackets;
+ sumstats->opackets += newstats->opackets - oldstats->opackets;
+ sumstats->ierrors += newstats->ierrors - oldstats->ierrors;
+ sumstats->oerrors += newstats->oerrors - oldstats->oerrors;
+ sumstats->collisions += newstats->collisions - oldstats->collisions;
+}
+
+/* --------------------- IF_REPORT (netstat -i) -------------------------- */
+
+static struct ifstat zerostat = {
+ 0LL, 0LL, 0LL, 0LL, 0LL
+};
+
+static void
+if_report(mib_item_t *item, char *matchname,
+ int Iflag_only, boolean_t once_only)
+{
+ static boolean_t reentry = B_FALSE;
+ boolean_t alreadydone = B_FALSE;
+ int jtemp = 0;
+ uint32_t ifindex_v4 = 0;
+ uint32_t ifindex_v6 = 0;
+
+ /* 'for' loop 1: */
+ for (; item; item = item->next_item) {
+ if (Dflag) {
+ (void) printf("\n--- Entry %d ---\n", ++jtemp);
+ (void) printf("Group = %d, mib_id = %d, "
+ "length = %d, valp = 0x%p\n",
+ item->group, item->mib_id, item->length,
+ item->valp);
+ }
+
+ switch (item->group) {
+ case MIB2_IP:
+ if (item->mib_id != MIB2_IP_ADDR ||
+ !family_selected(AF_INET))
+ continue; /* 'for' loop 1 */
+ {
+ static struct ifstat old = {0L, 0L, 0L, 0L, 0L};
+ static struct ifstat new = {0L, 0L, 0L, 0L, 0L};
+ struct ifstat sum;
+ struct iflist *newlist = NULL;
+ static struct iflist *oldlist = NULL;
+ kstat_t *ksp;
+
+ if (once_only) {
+ char ifname[LIFNAMSIZ + 1];
+ char logintname[LIFNAMSIZ + 1];
+ mib2_ipAddrEntry_t *ap;
+ struct ifstat stat = {0L, 0L, 0L, 0L, 0L};
+ boolean_t first = B_TRUE;
+ uint32_t new_ifindex;
+
+ if (Dflag)
+ (void) printf("if_report: %d items\n",
+ (item->length)
+ / sizeof (mib2_ipAddrEntry_t));
+
+ /* 'for' loop 2a: */
+ for (ap = (mib2_ipAddrEntry_t *)item->valp;
+ (char *)ap < (char *)item->valp
+ + item->length;
+ ap++) {
+ (void) octetstr(&ap->ipAdEntIfIndex,
+ 'a', logintname,
+ sizeof (logintname));
+ (void) strcpy(ifname, logintname);
+ (void) strtok(ifname, ":");
+ if (matchname != NULL &&
+ strcmp(matchname, ifname) != 0 &&
+ strcmp(matchname, logintname) != 0)
+ continue; /* 'for' loop 2a */
+ new_ifindex =
+ if_nametoindex(logintname);
+ if (new_ifindex != ifindex_v4 &&
+ (ksp = kstat_lookup(kc, NULL, -1,
+ ifname)) != NULL) {
+ (void) safe_kstat_read(kc, ksp,
+ NULL);
+ stat.ipackets =
+ kstat_named_value(ksp,
+ "ipackets");
+ stat.ierrors =
+ kstat_named_value(ksp,
+ "ierrors");
+ stat.opackets =
+ kstat_named_value(ksp,
+ "opackets");
+ stat.oerrors =
+ kstat_named_value(ksp,
+ "oerrors");
+ stat.collisions =
+ kstat_named_value(ksp,
+ "collisions");
+ if (first) {
+ (void) printf(
+ "%-5.5s %-5.5s%-13.13s "
+ "%-14.14s %-6.6s %-5.5s "
+ "%-6.6s %-5.5s %-6.6s "
+ "%-6.6s\n",
+ "Name", "Mtu", "Net/Dest",
+ "Address", "Ipkts",
+ "Ierrs", "Opkts", "Oerrs",
+ "Collis", "Queue");
+ first = B_FALSE;
+ }
+ if_report_ip4(ap, ifname,
+ logintname, &stat, B_TRUE);
+ ifindex_v4 = new_ifindex;
+ } else {
+ if_report_ip4(ap, ifname,
+ logintname, &stat, B_FALSE);
+ }
+ } /* 'for' loop 2a ends */
+ if (!first)
+ (void) putchar('\n');
+ } else if (!alreadydone) {
+ char ifname[LIFNAMSIZ + 1];
+ char buf[LIFNAMSIZ + 1];
+ mib2_ipAddrEntry_t *ap;
+ struct ifstat t;
+ struct iflist *tlp;
+ struct iflist **nextnew = &newlist;
+ struct iflist *walkold;
+ struct iflist *cleanlist;
+
+ alreadydone = B_TRUE; /* ignore other case */
+ /*
+ * 'for' loop 2b: find the "right" entry
+ */
+ for (ap = (mib2_ipAddrEntry_t *)item->valp;
+ (char *)ap < (char *)item->valp
+ + item->length;
+ ap++) {
+ (void) octetstr(&ap->ipAdEntIfIndex,
+ 'a', ifname, sizeof (ifname));
+ (void) strtok(ifname, ":");
+
+ if (matchname) {
+ if (strcmp(matchname,
+ ifname) == 0)
+ /* 'for' loop 2b */
+ break;
+ } else if (strcmp(ifname, "lo0") != 0) {
+ matchname = ifname;
+ break; /* 'for' loop 2b */
+ }
+ } /* 'for' loop 2b ends */
+
+ if (Iflag_only == 0 || !reentry) {
+ (void) printf(" input %-6.6s "
+ "output ",
+ matchname);
+ (void) printf(" input (Total) "
+ "output\n");
+ (void) printf("%-7.7s %-5.5s %-7.7s "
+ "%-5.5s %-6.6s ",
+ "packets", "errs", "packets",
+ "errs", "colls");
+ (void) printf("%-7.7s %-5.5s %-7.7s "
+ "%-5.5s %-6.6s\n",
+ "packets", "errs", "packets",
+ "errs", "colls");
+ }
+
+ sum = zerostat;
+
+ /* 'for' loop 2c: */
+ for (ap = (mib2_ipAddrEntry_t *)item->valp;
+ (char *)ap < (char *)item->valp
+ + item->length;
+ ap++) {
+ (void) octetstr(&ap->ipAdEntIfIndex,
+ 'a', buf, sizeof (buf));
+ (void) strtok(buf, ":");
+ ksp = kstat_lookup(kc, NULL, -1, buf);
+ if (ksp &&
+ ksp->ks_type == KSTAT_TYPE_NAMED)
+ (void) safe_kstat_read(kc, ksp,
+ NULL);
+
+ t.ipackets = kstat_named_value(ksp,
+ "ipackets");
+ t.ierrors = kstat_named_value(ksp,
+ "ierrors");
+ t.opackets = kstat_named_value(ksp,
+ "opackets");
+ t.oerrors = kstat_named_value(ksp,
+ "oerrors");
+ t.collisions = kstat_named_value(ksp,
+ "collisions");
+
+ if (strcmp(buf, matchname) == 0)
+ new = t;
+
+ /* Build the interface list */
+
+ tlp = malloc(sizeof (struct iflist));
+ (void) strlcpy(tlp->ifname, buf,
+ sizeof (tlp->ifname));
+ tlp->tot = t;
+ *nextnew = tlp;
+ nextnew = &tlp->next_if;
+
+ /*
+ * First time through.
+ * Just add up the interface stats.
+ */
+
+ if (oldlist == NULL) {
+ if_stat_total(&zerostat,
+ &t, &sum);
+ continue;
+ }
+
+ /*
+ * Walk old list for the interface.
+ *
+ * If found, add difference to total.
+ *
+ * If not, an interface has been plumbed
+ * up. In this case, we will simply
+ * ignore the new interface until the
+ * next interval; as there's no easy way
+ * to acquire statistics between time
+ * of the plumb and the next interval
+ * boundary. This results in inaccurate
+ * total values for current interval.
+ *
+ * Note the case when an interface is
+ * unplumbed; as similar problems exist.
+ * The unplumbed interface is not in the
+ * current list, and there's no easy way
+ * to account for the statistics between
+ * the previous interval and time of the
+ * unplumb. Therefore, we (in a sense)
+ * ignore the removed interface by only
+ * involving "current" interfaces when
+ * computing the total statistics.
+ * Unfortunately, this also results in
+ * inaccurate values for interval total.
+ */
+
+ for (walkold = oldlist;
+ walkold != NULL;
+ walkold = walkold->next_if) {
+ if (strcmp(walkold->ifname,
+ buf) == 0) {
+ if_stat_total(
+ &walkold->tot,
+ &t, &sum);
+ break;
+ }
+ }
+
+ } /* 'for' loop 2c ends */
+
+ *nextnew = NULL;
+
+ (void) printf("%-7llu %-5llu %-7llu "
+ "%-5llu %-6llu ",
+ new.ipackets - old.ipackets,
+ new.ierrors - old.ierrors,
+ new.opackets - old.opackets,
+ new.oerrors - old.oerrors,
+ new.collisions - old.collisions);
+
+ (void) printf("%-7llu %-5llu %-7llu "
+ "%-5llu %-6llu\n", sum.ipackets,
+ sum.ierrors, sum.opackets,
+ sum.oerrors, sum.collisions);
+
+ /*
+ * Tidy things up once finished.
+ */
+
+ old = new;
+ cleanlist = oldlist;
+ oldlist = newlist;
+ while (cleanlist != NULL) {
+ tlp = cleanlist->next_if;
+ free(cleanlist);
+ cleanlist = tlp;
+ }
+ }
+ break;
+ }
+ case MIB2_IP6:
+ if (item->mib_id != MIB2_IP6_ADDR ||
+ !family_selected(AF_INET6))
+ continue; /* 'for' loop 1 */
+ {
+ static struct ifstat old6 = {0L, 0L, 0L, 0L, 0L};
+ static struct ifstat new6 = {0L, 0L, 0L, 0L, 0L};
+ struct ifstat sum6;
+ struct iflist *newlist6 = NULL;
+ static struct iflist *oldlist6 = NULL;
+ kstat_t *ksp;
+
+ if (once_only) {
+ char ifname[LIFNAMSIZ + 1];
+ char logintname[LIFNAMSIZ + 1];
+ mib2_ipv6AddrEntry_t *ap6;
+ struct ifstat stat = {0L, 0L, 0L, 0L, 0L};
+ boolean_t first = B_TRUE;
+ uint32_t new_ifindex;
+
+ if (Dflag)
+ (void) printf("if_report: %d items\n",
+ (item->length)
+ / sizeof (mib2_ipv6AddrEntry_t));
+ /* 'for' loop 2d: */
+ for (ap6 = (mib2_ipv6AddrEntry_t *)item->valp;
+ (char *)ap6 < (char *)item->valp
+ + item->length;
+ ap6++) {
+ (void) octetstr(&ap6->ipv6AddrIfIndex,
+ 'a', logintname,
+ sizeof (logintname));
+ (void) strcpy(ifname, logintname);
+ (void) strtok(ifname, ":");
+ if (matchname != NULL &&
+ strcmp(matchname, ifname) != 0 &&
+ strcmp(matchname, logintname) != 0)
+ continue; /* 'for' loop 2d */
+ new_ifindex =
+ if_nametoindex(logintname);
+ if (new_ifindex != ifindex_v6 &&
+ (ksp = kstat_lookup(kc, NULL, -1,
+ ifname)) != NULL) {
+ (void) safe_kstat_read(kc, ksp,
+ NULL);
+ stat.ipackets =
+ kstat_named_value(ksp,
+ "ipackets");
+ stat.ierrors =
+ kstat_named_value(ksp,
+ "ierrors");
+ stat.opackets =
+ kstat_named_value(ksp,
+ "opackets");
+ stat.oerrors =
+ kstat_named_value(ksp,
+ "oerrors");
+ stat.collisions =
+ kstat_named_value(ksp,
+ "collisions");
+ if (first) {
+ (void) printf(
+ "%-5.5s %-5.5s%"
+ "-27.27s %-27.27s "
+ "%-6.6s %-5.5s "
+ "%-6.6s %-5.5s "
+ "%-6.6s\n",
+ "Name", "Mtu",
+ "Net/Dest",
+ "Address", "Ipkts",
+ "Ierrs", "Opkts",
+ "Oerrs", "Collis");
+ first = B_FALSE;
+ }
+ if_report_ip6(ap6, ifname,
+ logintname, &stat, B_TRUE);
+ ifindex_v6 = new_ifindex;
+ } else {
+ if_report_ip6(ap6, ifname,
+ logintname, &stat, B_FALSE);
+ }
+ } /* 'for' loop 2d ends */
+ if (!first)
+ (void) putchar('\n');
+ } else if (!alreadydone) {
+ char ifname[LIFNAMSIZ + 1];
+ char buf[IFNAMSIZ + 1];
+ mib2_ipv6AddrEntry_t *ap6;
+ struct ifstat t;
+ struct iflist *tlp;
+ struct iflist **nextnew = &newlist6;
+ struct iflist *walkold;
+ struct iflist *cleanlist;
+
+ alreadydone = B_TRUE; /* ignore other case */
+ /*
+ * 'for' loop 2e: find the "right" entry
+ */
+ for (ap6 = (mib2_ipv6AddrEntry_t *)item->valp;
+ (char *)ap6 < (char *)item->valp
+ + item->length;
+ ap6++) {
+ (void) octetstr(&ap6->ipv6AddrIfIndex,
+ 'a', ifname, sizeof (ifname));
+ (void) strtok(ifname, ":");
+
+ if (matchname) {
+ if (strcmp(matchname, ifname) ==
+ 0)
+ /* 'for' loop 2e */
+ break;
+ } else if (strcmp(ifname, "lo0") != 0) {
+ matchname = ifname;
+ break; /* 'for' loop 2e */
+ }
+ } /* 'for' loop 2e ends */
+
+ if (Iflag_only == 0 || !reentry) {
+ (void) printf(
+ " input %-6.6s"
+ " output ",
+ matchname);
+ (void) printf(" input (Total)"
+ " output\n");
+ (void) printf("%-7.7s %-5.5s %-7.7s "
+ "%-5.5s %-6.6s ",
+ "packets", "errs", "packets",
+ "errs", "colls");
+ (void) printf("%-7.7s %-5.5s %-7.7s "
+ "%-5.5s %-6.6s\n",
+ "packets", "errs", "packets",
+ "errs", "colls");
+ }
+
+ sum6 = zerostat;
+
+ /* 'for' loop 2f: */
+ for (ap6 = (mib2_ipv6AddrEntry_t *)item->valp;
+ (char *)ap6 < (char *)item->valp
+ + item->length;
+ ap6++) {
+ (void) octetstr(&ap6->ipv6AddrIfIndex,
+ 'a', buf, sizeof (buf));
+ (void) strtok(buf, ":");
+ ksp = kstat_lookup(kc, NULL, -1, buf);
+ if (ksp && ksp->ks_type ==
+ KSTAT_TYPE_NAMED)
+ (void) safe_kstat_read(kc,
+ ksp, NULL);
+
+ t.ipackets = kstat_named_value(ksp,
+ "ipackets");
+ t.ierrors = kstat_named_value(ksp,
+ "ierrors");
+ t.opackets = kstat_named_value(ksp,
+ "opackets");
+ t.oerrors = kstat_named_value(ksp,
+ "oerrors");
+ t.collisions = kstat_named_value(ksp,
+ "collisions");
+
+ if (strcmp(buf, matchname) == 0)
+ new6 = t;
+
+ /* Build the interface list */
+
+ tlp = malloc(sizeof (struct iflist));
+ (void) strlcpy(tlp->ifname, buf,
+ sizeof (tlp->ifname));
+ tlp->tot = t;
+ *nextnew = tlp;
+ nextnew = &tlp->next_if;
+
+ /*
+ * First time through.
+ * Just add up the interface stats.
+ */
+
+ if (oldlist6 == NULL) {
+ if_stat_total(&zerostat,
+ &t, &sum6);
+ continue;
+ }
+
+ /*
+ * Walk old list for the interface.
+ *
+ * If found, add difference to total.
+ *
+ * If not, an interface has been plumbed
+ * up. In this case, we will simply
+ * ignore the new interface until the
+ * next interval; as there's no easy way
+ * to acquire statistics between time
+ * of the plumb and the next interval
+ * boundary. This results in inaccurate
+ * total values for current interval.
+ *
+ * Note the case when an interface is
+ * unplumbed; as similar problems exist.
+ * The unplumbed interface is not in the
+ * current list, and there's no easy way
+ * to account for the statistics between
+ * the previous interval and time of the
+ * unplumb. Therefore, we (in a sense)
+ * ignore the removed interface by only
+ * involving "current" interfaces when
+ * computing the total statistics.
+ * Unfortunately, this also results in
+ * inaccurate values for interval total.
+ */
+
+ for (walkold = oldlist6;
+ walkold != NULL;
+ walkold = walkold->next_if) {
+ if (strcmp(walkold->ifname,
+ buf) == 0) {
+ if_stat_total(
+ &walkold->tot,
+ &t, &sum6);
+ break;
+ }
+ }
+
+ } /* 'for' loop 2f ends */
+
+ *nextnew = NULL;
+
+ (void) printf("%-7llu %-5llu %-7llu "
+ "%-5llu %-6llu ",
+ new6.ipackets - old6.ipackets,
+ new6.ierrors - old6.ierrors,
+ new6.opackets - old6.opackets,
+ new6.oerrors - old6.oerrors,
+ new6.collisions - old6.collisions);
+
+ (void) printf("%-7llu %-5llu %-7llu "
+ "%-5llu %-6llu\n", sum6.ipackets,
+ sum6.ierrors, sum6.opackets,
+ sum6.oerrors, sum6.collisions);
+
+ /*
+ * Tidy things up once finished.
+ */
+
+ old6 = new6;
+ cleanlist = oldlist6;
+ oldlist6 = newlist6;
+ while (cleanlist != NULL) {
+ tlp = cleanlist->next_if;
+ free(cleanlist);
+ cleanlist = tlp;
+ }
+ }
+ break;
+ }
+ }
+ if (Iflag_only == 0)
+ (void) putchar('\n');
+ (void) fflush(stdout);
+ } /* 'for' loop 1 ends */
+ reentry = B_TRUE;
+}
+
+static void
+if_report_ip4(mib2_ipAddrEntry_t *ap,
+ char ifname[], char logintname[], struct ifstat *statptr,
+ boolean_t ksp_not_null) {
+
+ char abuf[MAXHOSTNAMELEN + 1];
+ char dstbuf[MAXHOSTNAMELEN + 1];
+
+ if (ksp_not_null) {
+ (void) printf("%-5s %-5u",
+ ifname, ap->ipAdEntInfo.ae_mtu);
+ if (ap->ipAdEntInfo.ae_flags & IFF_POINTOPOINT)
+ (void) pr_addr(ap->ipAdEntInfo.ae_pp_dst_addr,
+ abuf, sizeof (abuf));
+ else
+ (void) pr_netaddr(ap->ipAdEntAddr,
+ ap->ipAdEntNetMask, abuf, sizeof (abuf));
+ (void) printf("%-13s %-14s %-6llu %-5llu %-6llu %-5llu "
+ "%-6llu %-6llu\n",
+ abuf, pr_addr(ap->ipAdEntAddr, dstbuf, sizeof (dstbuf)),
+ statptr->ipackets, statptr->ierrors,
+ statptr->opackets, statptr->oerrors,
+ statptr->collisions, 0LL);
+ }
+ /*
+ * Print logical interface info if Aflag set (including logical unit 0)
+ */
+ if (Aflag) {
+ *statptr = zerostat;
+ statptr->ipackets = ap->ipAdEntInfo.ae_ibcnt;
+ statptr->opackets = ap->ipAdEntInfo.ae_obcnt;
+
+ (void) printf("%-5s %-5u", logintname, ap->ipAdEntInfo.ae_mtu);
+ if (ap->ipAdEntInfo.ae_flags & IFF_POINTOPOINT)
+ (void) pr_addr(ap->ipAdEntInfo.ae_pp_dst_addr, abuf,
+ sizeof (abuf));
+ else
+ (void) pr_netaddr(ap->ipAdEntAddr, ap->ipAdEntNetMask,
+ abuf, sizeof (abuf));
+
+ (void) printf("%-13s %-14s %-6llu %-5s %-6llu "
+ "%-5s %-6s %-6llu\n", abuf,
+ pr_addr(ap->ipAdEntAddr, dstbuf, sizeof (dstbuf)),
+ statptr->ipackets, "N/A", statptr->opackets, "N/A", "N/A",
+ 0LL);
+ }
+}
+
+static void
+if_report_ip6(mib2_ipv6AddrEntry_t *ap6,
+ char ifname[], char logintname[], struct ifstat *statptr,
+ boolean_t ksp_not_null) {
+
+ char abuf[MAXHOSTNAMELEN + 1];
+ char dstbuf[MAXHOSTNAMELEN + 1];
+
+ if (ksp_not_null) {
+ (void) printf("%-5s %-5u", ifname, ap6->ipv6AddrInfo.ae_mtu);
+ if (ap6->ipv6AddrInfo.ae_flags &
+ IFF_POINTOPOINT) {
+ (void) pr_addr6(&ap6->ipv6AddrInfo.ae_pp_dst_addr,
+ abuf, sizeof (abuf));
+ } else {
+ (void) pr_prefix6(&ap6->ipv6AddrAddress,
+ ap6->ipv6AddrPfxLength, abuf,
+ sizeof (abuf));
+ }
+ (void) printf("%-27s %-27s %-6llu %-5llu "
+ "%-6llu %-5llu %-6llu\n",
+ abuf, pr_addr6(&ap6->ipv6AddrAddress, dstbuf,
+ sizeof (dstbuf)),
+ statptr->ipackets, statptr->ierrors, statptr->opackets,
+ statptr->oerrors, statptr->collisions);
+ }
+ /*
+ * Print logical interface info if Aflag set (including logical unit 0)
+ */
+ if (Aflag) {
+ *statptr = zerostat;
+ statptr->ipackets = ap6->ipv6AddrInfo.ae_ibcnt;
+ statptr->opackets = ap6->ipv6AddrInfo.ae_obcnt;
+
+ (void) printf("%-5s %-5u", logintname,
+ ap6->ipv6AddrInfo.ae_mtu);
+ if (ap6->ipv6AddrInfo.ae_flags & IFF_POINTOPOINT)
+ (void) pr_addr6(&ap6->ipv6AddrInfo.ae_pp_dst_addr,
+ abuf, sizeof (abuf));
+ else
+ (void) pr_prefix6(&ap6->ipv6AddrAddress,
+ ap6->ipv6AddrPfxLength, abuf, sizeof (abuf));
+ (void) printf("%-27s %-27s %-6llu %-5s %-6llu %-5s %-6s\n",
+ abuf, pr_addr6(&ap6->ipv6AddrAddress, dstbuf,
+ sizeof (dstbuf)),
+ statptr->ipackets, "N/A",
+ statptr->opackets, "N/A", "N/A");
+ }
+}
+
+/* --------------------- DHCP_REPORT (netstat -D) ------------------------- */
+
+dhcp_ipc_reply_t *
+dhcp_do_ipc(dhcp_ipc_type_t type, const char *ifname)
+{
+ dhcp_ipc_request_t *request;
+ dhcp_ipc_reply_t *reply;
+ int error;
+
+ request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE);
+ if (request == NULL)
+ fail(0, "dhcp_do_ipc: out of memory");
+
+ error = dhcp_ipc_make_request(request, &reply, DHCP_IPC_WAIT_DEFAULT);
+ if (error != 0) {
+ free(request);
+ fail(0, "dhcp_do_ipc: %s", dhcp_ipc_strerror(error));
+ }
+
+ free(request);
+ error = reply->return_code;
+ if (error != 0) {
+ free(reply);
+ fail(0, "dhcp_do_ipc: %s", dhcp_ipc_strerror(error));
+ }
+
+ return (reply);
+}
+
+/*
+ * get_ifnames: return a dynamically allocated string of all interface
+ * names which have all of the IFF_* flags listed in `flags_on' on and
+ * all of the IFF_* flags in `flags_off' off. If no such interfaces
+ * are found, "" is returned. If an unexpected failure occurs, NULL
+ * is returned.
+ */
+static char *
+get_ifnames(int flags_on, int flags_off)
+{
+ struct ifconf ifc;
+ int n_ifs, i, sock_fd;
+ char *ifnames;
+
+ sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock_fd == -1)
+ return (NULL);
+
+ if ((ioctl(sock_fd, SIOCGIFNUM, &n_ifs) == -1) || (n_ifs <= 0)) {
+ (void) close(sock_fd);
+ return (NULL);
+ }
+
+ ifnames = calloc(1, n_ifs * (IFNAMSIZ + 1));
+ ifc.ifc_len = n_ifs * sizeof (struct ifreq);
+ ifc.ifc_req = calloc(n_ifs, sizeof (struct ifreq));
+ if (ifc.ifc_req != NULL && ifnames != NULL) {
+
+ if (ioctl(sock_fd, SIOCGIFCONF, &ifc) == -1) {
+ (void) close(sock_fd);
+ free(ifnames);
+ free(ifc.ifc_req);
+ return (NULL);
+ }
+
+ /* 'for' loop 1: */
+ for (i = 0; i < n_ifs; i++) {
+
+ if (ioctl(sock_fd, SIOCGIFFLAGS, &ifc.ifc_req[i]) == 0)
+ if ((ifc.ifc_req[i].ifr_flags &
+ (flags_on | flags_off)) != flags_on)
+ continue; /* 'for' loop 1 */
+
+ (void) strcat(ifnames, ifc.ifc_req[i].ifr_name);
+ (void) strcat(ifnames, " ");
+ } /* 'for' loop 1 ends */
+
+ if (strlen(ifnames) > 1)
+ ifnames[strlen(ifnames) - 1] = '\0';
+ }
+
+ (void) close(sock_fd);
+ if (ifc.ifc_req != NULL)
+ free(ifc.ifc_req);
+ return (ifnames);
+}
+
+static void
+dhcp_report(char *ifname)
+{
+ int did_alloc = 0;
+ dhcp_ipc_reply_t *reply;
+
+ if (!(family_selected(AF_INET)))
+ return;
+
+ if (ifname == NULL) {
+ ifname = get_ifnames(IFF_DHCPRUNNING, 0);
+ if (ifname == NULL)
+ fail(0, "dhcp_report: unable to retrieve list of"
+ " interfaces using DHCP");
+ did_alloc++;
+ }
+
+ (void) printf("%s", dhcp_status_hdr_string());
+
+ for (ifname = strtok(ifname, " ");
+ ifname != NULL;
+ ifname = strtok(NULL, " ")) {
+ reply = dhcp_do_ipc(DHCP_STATUS, ifname);
+ (void) printf("%s", dhcp_status_reply_to_string(reply));
+ free(reply);
+ }
+
+ if (did_alloc)
+ free(ifname);
+}
+
+/* --------------------- GROUP_REPORT (netstat -g) ------------------------- */
+
+static void
+group_report(mib_item_t *item)
+{
+ mib_item_t *v4grp = NULL, *v4src = NULL;
+ mib_item_t *v6grp = NULL, *v6src = NULL;
+ int jtemp = 0;
+ char ifname[LIFNAMSIZ + 1];
+ char abuf[MAXHOSTNAMELEN + 1];
+ ip_member_t *ipmp;
+ ip_grpsrc_t *ips;
+ ipv6_member_t *ipmp6;
+ ipv6_grpsrc_t *ips6;
+ char *ifnamep;
+ boolean_t first, first_src;
+
+ /* 'for' loop 1: */
+ for (; item; item = item->next_item) {
+ if (Dflag) {
+ (void) printf("\n--- Entry %d ---\n", ++jtemp);
+ (void) printf("Group = %d, mib_id = %d, "
+ "length = %d, valp = 0x%p\n",
+ item->group, item->mib_id, item->length,
+ item->valp);
+ }
+ if (item->group == MIB2_IP && family_selected(AF_INET)) {
+ switch (item->mib_id) {
+ case EXPER_IP_GROUP_MEMBERSHIP:
+ v4grp = item;
+ if (Dflag)
+ (void) printf("item is v4grp info\n");
+ break;
+ case EXPER_IP_GROUP_SOURCES:
+ v4src = item;
+ if (Dflag)
+ (void) printf("item is v4src info\n");
+ break;
+ default:
+ continue;
+ }
+ continue;
+ }
+ if (item->group == MIB2_IP6 && family_selected(AF_INET6)) {
+ switch (item->mib_id) {
+ case EXPER_IP6_GROUP_MEMBERSHIP:
+ v6grp = item;
+ if (Dflag)
+ (void) printf("item is v6grp info\n");
+ break;
+ case EXPER_IP6_GROUP_SOURCES:
+ v6src = item;
+ if (Dflag)
+ (void) printf("item is v6src info\n");
+ break;
+ default:
+ continue;
+ }
+ }
+ }
+
+ if (family_selected(AF_INET) && v4grp != NULL) {
+ if (Dflag)
+ (void) printf("%u records for ipGroupMember:\n",
+ v4grp->length / sizeof (ip_member_t));
+
+ first = B_TRUE;
+ for (ipmp = (ip_member_t *)v4grp->valp;
+ (char *)ipmp < (char *)v4grp->valp + v4grp->length;
+ /* LINTED: (note 1) */
+ ipmp = (ip_member_t *)((char *)ipmp + ipMemberEntrySize)) {
+ if (first) {
+ (void) puts(v4compat ?
+ "Group Memberships" :
+ "Group Memberships: IPv4");
+ (void) puts("Interface "
+ "Group RefCnt");
+ (void) puts("--------- "
+ "-------------------- ------");
+ first = B_FALSE;
+ }
+
+ (void) printf("%-9s %-20s %6u\n",
+ octetstr(&ipmp->ipGroupMemberIfIndex, 'a',
+ ifname, sizeof (ifname)),
+ pr_addr(ipmp->ipGroupMemberAddress,
+ abuf, sizeof (abuf)),
+ ipmp->ipGroupMemberRefCnt);
+
+
+ if (!Vflag || v4src == NULL)
+ continue;
+
+ if (Dflag)
+ (void) printf("scanning %u ipGroupSource "
+ "records...\n",
+ v4src->length/sizeof (ip_grpsrc_t));
+
+ first_src = B_TRUE;
+ for (ips = (ip_grpsrc_t *)v4src->valp;
+ (char *)ips < (char *)v4src->valp + v4src->length;
+ /* LINTED: (note 1) */
+ ips = (ip_grpsrc_t *)((char *)ips +
+ ipGroupSourceEntrySize)) {
+ /*
+ * We assume that all source addrs for a given
+ * interface/group pair are contiguous, so on
+ * the first non-match after we've found at
+ * least one, we bail.
+ */
+ if ((ipmp->ipGroupMemberAddress !=
+ ips->ipGroupSourceGroup) ||
+ (!octetstrmatch(&ipmp->ipGroupMemberIfIndex,
+ &ips->ipGroupSourceIfIndex))) {
+ if (first_src)
+ continue;
+ else
+ break;
+ }
+ if (first_src) {
+ (void) printf("\t%s: %s\n",
+ fmodestr(
+ ipmp->ipGroupMemberFilterMode),
+ pr_addr(ips->ipGroupSourceAddress,
+ abuf, sizeof (abuf)));
+ first_src = B_FALSE;
+ continue;
+ }
+
+ (void) printf("\t %s\n",
+ pr_addr(ips->ipGroupSourceAddress, abuf,
+ sizeof (abuf)));
+ }
+ }
+ (void) putchar('\n');
+ }
+
+ if (family_selected(AF_INET6) && v6grp != NULL) {
+ if (Dflag)
+ (void) printf("%u records for ipv6GroupMember:\n",
+ v6grp->length / sizeof (ipv6_member_t));
+
+ first = B_TRUE;
+ for (ipmp6 = (ipv6_member_t *)v6grp->valp;
+ (char *)ipmp6 < (char *)v6grp->valp + v6grp->length;
+ /* LINTED: (note 1) */
+ ipmp6 = (ipv6_member_t *)((char *)ipmp6 +
+ ipv6MemberEntrySize)) {
+ if (first) {
+ (void) puts("Group Memberships: "
+ "IPv6");
+ (void) puts(" If "
+ "Group RefCnt");
+ (void) puts("----- "
+ "--------------------------- ------");
+ first = B_FALSE;
+ }
+
+ ifnamep = if_indextoname(
+ ipmp6->ipv6GroupMemberIfIndex, ifname);
+ if (ifnamep == NULL) {
+ (void) printf("Invalid ifindex %d\n",
+ ipmp6->ipv6GroupMemberIfIndex);
+ continue;
+ }
+ (void) printf("%-5s %-27s %5u\n",
+ ifnamep,
+ pr_addr6(&ipmp6->ipv6GroupMemberAddress,
+ abuf, sizeof (abuf)),
+ ipmp6->ipv6GroupMemberRefCnt);
+
+ if (!Vflag || v6src == NULL)
+ continue;
+
+ if (Dflag)
+ (void) printf("scanning %u ipv6GroupSource "
+ "records...\n",
+ v6src->length/sizeof (ipv6_grpsrc_t));
+
+ first_src = B_TRUE;
+ for (ips6 = (ipv6_grpsrc_t *)v6src->valp;
+ (char *)ips6 < (char *)v6src->valp + v6src->length;
+ /* LINTED: (note 1) */
+ ips6 = (ipv6_grpsrc_t *)((char *)ips6 +
+ ipv6GroupSourceEntrySize)) {
+ /* same assumption as in the v4 case above */
+ if ((ipmp6->ipv6GroupMemberIfIndex !=
+ ips6->ipv6GroupSourceIfIndex) ||
+ (!IN6_ARE_ADDR_EQUAL(
+ &ipmp6->ipv6GroupMemberAddress,
+ &ips6->ipv6GroupSourceGroup))) {
+ if (first_src)
+ continue;
+ else
+ break;
+ }
+ if (first_src) {
+ (void) printf("\t%s: %s\n",
+ fmodestr(
+ ipmp6->ipv6GroupMemberFilterMode),
+ pr_addr6(
+ &ips6->ipv6GroupSourceAddress,
+ abuf, sizeof (abuf)));
+ first_src = B_FALSE;
+ continue;
+ }
+
+ (void) printf("\t %s\n",
+ pr_addr6(&ips6->ipv6GroupSourceAddress,
+ abuf, sizeof (abuf)));
+ }
+ }
+ (void) putchar('\n');
+ }
+
+ (void) putchar('\n');
+ (void) fflush(stdout);
+}
+
+/* --------------------- ARP_REPORT (netstat -p) -------------------------- */
+
+static void
+arp_report(mib_item_t *item)
+{
+ int jtemp = 0;
+ char ifname[LIFNAMSIZ + 1];
+ char abuf[MAXHOSTNAMELEN + 1];
+ char maskbuf[STR_EXPAND * OCTET_LENGTH + 1];
+ char flbuf[32]; /* ACE_F_ flags */
+ char xbuf[STR_EXPAND * OCTET_LENGTH + 1];
+ mib2_ipNetToMediaEntry_t *np;
+ int flags;
+ boolean_t first;
+
+ if (!(family_selected(AF_INET)))
+ return;
+
+ /* 'for' loop 1: */
+ for (; item; item = item->next_item) {
+ if (Dflag) {
+ (void) printf("\n--- Entry %d ---\n", ++jtemp);
+ (void) printf("Group = %d, mib_id = %d, "
+ "length = %d, valp = 0x%p\n",
+ item->group, item->mib_id, item->length,
+ item->valp);
+ }
+ if (!(item->group == MIB2_IP && item->mib_id == MIB2_IP_MEDIA))
+ continue; /* 'for' loop 1 */
+
+ if (Dflag)
+ (void) printf("%u records for "
+ "ipNetToMediaEntryTable:\n",
+ item->length/sizeof (mib2_ipNetToMediaEntry_t));
+
+ first = B_TRUE;
+ /* 'for' loop 2: */
+ for (np = (mib2_ipNetToMediaEntry_t *)item->valp;
+ (char *)np < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ np = (mib2_ipNetToMediaEntry_t *)((char *)np +
+ ipNetToMediaEntrySize)) {
+ if (first) {
+ (void) puts(v4compat ?
+ "Net to Media Table" :
+ "Net to Media Table: IPv4");
+ (void) fputs("Device "
+ "IP Address Mask ",
+ stdout);
+ (void) puts("Flags Phys Addr ");
+ (void) puts("------ -------------------- "
+ "--------------- ----- ---------------");
+ first = B_FALSE;
+ }
+
+ flbuf[0] = '\0';
+ flags = np->ipNetToMediaInfo.ntm_flags;
+ if (flags & ACE_F_PERMANENT)
+ (void) strcat(flbuf, "S");
+ if (flags & ACE_F_PUBLISH)
+ (void) strcat(flbuf, "P");
+ if (flags & ACE_F_DYING)
+ (void) strcat(flbuf, "D");
+ if (!(flags & ACE_F_RESOLVED))
+ (void) strcat(flbuf, "U");
+ if (flags & ACE_F_MAPPING)
+ (void) strcat(flbuf, "M");
+ (void) printf("%-6s %-20s %-15s %-5s %s\n",
+ octetstr(&np->ipNetToMediaIfIndex, 'a',
+ ifname, sizeof (ifname)),
+ pr_addr(np->ipNetToMediaNetAddress,
+ abuf, sizeof (abuf)),
+ octetstr(&np->ipNetToMediaInfo.ntm_mask, 'd',
+ maskbuf, sizeof (maskbuf)),
+ flbuf,
+ octetstr(&np->ipNetToMediaPhysAddress, 'h',
+ xbuf, sizeof (xbuf)));
+ } /* 'for' loop 2 ends */
+ } /* 'for' loop 1 ends */
+ (void) fflush(stdout);
+}
+
+/* --------------------- NDP_REPORT (netstat -p) -------------------------- */
+
+static void
+ndp_report(mib_item_t *item)
+{
+ int jtemp = 0;
+ char abuf[MAXHOSTNAMELEN + 1];
+ char *state;
+ char *type;
+ char xbuf[STR_EXPAND * OCTET_LENGTH + 1];
+ mib2_ipv6NetToMediaEntry_t *np6;
+ char ifname[LIFNAMSIZ + 1];
+ char *ifnamep;
+ boolean_t first;
+
+ if (!(family_selected(AF_INET6)))
+ return;
+
+ /* 'for' loop 1: */
+ for (; item; item = item->next_item) {
+ if (Dflag) {
+ (void) printf("\n--- Entry %d ---\n", ++jtemp);
+ (void) printf("Group = %d, mib_id = %d, "
+ "length = %d, valp = 0x%p\n",
+ item->group, item->mib_id, item->length,
+ item->valp);
+ }
+ if (!(item->group == MIB2_IP6 &&
+ item->mib_id == MIB2_IP6_MEDIA))
+ continue; /* 'for' loop 1 */
+
+ first = B_TRUE;
+ /* 'for' loop 2: */
+ for (np6 = (mib2_ipv6NetToMediaEntry_t *)item->valp;
+ (char *)np6 < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ np6 = (mib2_ipv6NetToMediaEntry_t *)((char *)np6 +
+ ipv6NetToMediaEntrySize)) {
+ if (first) {
+ (void) puts("\nNet to Media Table: IPv6");
+ (void) puts(" If Physical Address "
+ " Type State Destination/Mask");
+ (void) puts("----- ----------------- "
+ "------- ------------ "
+ "---------------------------");
+ first = B_FALSE;
+ }
+
+ ifnamep = if_indextoname(np6->ipv6NetToMediaIfIndex,
+ ifname);
+ if (ifnamep == NULL) {
+ (void) printf("Invalid ifindex %d\n",
+ np6->ipv6NetToMediaIfIndex);
+ continue; /* 'for' loop 2 */
+ }
+ switch (np6->ipv6NetToMediaState) {
+ case ND_INCOMPLETE:
+ state = "INCOMPLETE";
+ break;
+ case ND_REACHABLE:
+ state = "REACHABLE";
+ break;
+ case ND_STALE:
+ state = "STALE";
+ break;
+ case ND_DELAY:
+ state = "DELAY";
+ break;
+ case ND_PROBE:
+ state = "PROBE";
+ break;
+ case ND_UNREACHABLE:
+ state = "UNREACHABLE";
+ break;
+ default:
+ state = "UNKNOWN";
+ }
+
+ switch (np6->ipv6NetToMediaType) {
+ case 1:
+ type = "other";
+ break;
+ case 2:
+ type = "dynamic";
+ break;
+ case 3:
+ type = "static";
+ break;
+ case 4:
+ type = "local";
+ break;
+ }
+ (void) printf("%-5s %-17s %-7s %-12s %-27s\n",
+ ifnamep,
+ octetstr(&np6->ipv6NetToMediaPhysAddress, 'h',
+ xbuf, sizeof (xbuf)),
+ type,
+ state,
+ pr_addr6(&np6->ipv6NetToMediaNetAddress,
+ abuf, sizeof (abuf)));
+ } /* 'for' loop 2 ends */
+ } /* 'for' loop 1 ends */
+ (void) putchar('\n');
+ (void) fflush(stdout);
+}
+
+/* ------------------------- ire_report (netstat -r) ------------------------ */
+
+static boolean_t ire_report_item_v4(mib2_ipRouteEntry_t *rp, boolean_t first);
+static boolean_t ire_report_item_v4src(mib2_ipRouteEntry_t *rp,
+ boolean_t first);
+static boolean_t ire_report_item_v6(mib2_ipv6RouteEntry_t *rp6,
+ boolean_t first);
+
+static void
+ire_report(mib_item_t *item)
+{
+ int jtemp = 0;
+ boolean_t print_hdr_once_v4 = B_TRUE;
+ boolean_t print_hdr_once_v6 = B_TRUE;
+ mib2_ipRouteEntry_t *rp;
+ mib2_ipv6RouteEntry_t *rp6;
+
+ /* 'for' loop 1: */
+ for (; item; item = item->next_item) {
+ if (Dflag) {
+ (void) printf("\n--- Entry %d ---\n", ++jtemp);
+ (void) printf("Group = %d, mib_id = %d, "
+ "length = %d, valp = 0x%p\n",
+ item->group, item->mib_id,
+ item->length, item->valp);
+ }
+ if (!((item->group == MIB2_IP &&
+ item->mib_id == MIB2_IP_ROUTE) ||
+ (item->group == MIB2_IP6 &&
+ item->mib_id == MIB2_IP6_ROUTE)))
+ continue; /* 'for' loop 1 */
+
+ if (item->group == MIB2_IP && !family_selected(AF_INET))
+ continue; /* 'for' loop 1 */
+ else if (item->group == MIB2_IP6 && !family_selected(AF_INET6))
+ continue; /* 'for' loop 1 */
+
+ if (Dflag) {
+ if (item->group == MIB2_IP) {
+ (void) printf("%u records for "
+ "ipRouteEntryTable:\n",
+ item->length/sizeof (mib2_ipRouteEntry_t));
+ } else {
+ (void) printf("%u records for "
+ "ipv6RouteEntryTable:\n",
+ item->length/
+ sizeof (mib2_ipv6RouteEntry_t));
+ }
+ }
+
+ if (item->group == MIB2_IP) {
+ for (rp = (mib2_ipRouteEntry_t *)item->valp;
+ (char *)rp < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ rp = (mib2_ipRouteEntry_t *)((char *)rp +
+ ipRouteEntrySize)) {
+ print_hdr_once_v4 = ire_report_item_v4(rp,
+ print_hdr_once_v4);
+ }
+ print_hdr_once_v4 = B_TRUE;
+ for (rp = (mib2_ipRouteEntry_t *)item->valp;
+ (char *)rp < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ rp = (mib2_ipRouteEntry_t *)((char *)rp +
+ ipRouteEntrySize)) {
+ print_hdr_once_v4 = ire_report_item_v4src(rp,
+ print_hdr_once_v4);
+ }
+ } else {
+ for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp;
+ (char *)rp6 < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ rp6 = (mib2_ipv6RouteEntry_t *)((char *)rp6 +
+ ipv6RouteEntrySize)) {
+ print_hdr_once_v6 = ire_report_item_v6(rp6,
+ print_hdr_once_v6);
+ }
+ }
+ } /* 'for' loop 1 ends */
+ (void) fflush(stdout);
+}
+
+/*
+ * Match a user-supplied device name. We do this by string because
+ * the MIB2 interface gives us interface name strings rather than
+ * ifIndex numbers. The "none" rule matches only routes with no
+ * interface. The "any" rule matches routes with any non-blank
+ * interface. A base name ("hme0") matches all aliases as well
+ * ("hme0:1").
+ */
+static boolean_t
+dev_name_match(const DeviceName *devnam, const char *ifname)
+{
+ int iflen;
+
+ if (ifname == NULL)
+ return (devnam->o_length == 0); /* "none" */
+ if (*ifname == '\0')
+ return (devnam->o_length != 0); /* "any" */
+ iflen = strlen(ifname);
+ /* The check for ':' here supports interface aliases. */
+ if (iflen > devnam->o_length ||
+ (iflen < devnam->o_length && devnam->o_bytes[iflen] != ':'))
+ return (B_FALSE);
+ return (strncmp(ifname, devnam->o_bytes, iflen) == 0);
+}
+
+/*
+ * Match a user-supplied IP address list. The "any" rule matches any
+ * non-zero address. The "none" rule matches only the zero address.
+ * IPv6 addresses supplied by the user are ignored. If the user
+ * supplies a subnet mask, then match routes that are at least that
+ * specific (use the user's mask). If the user supplies only an
+ * address, then select any routes that would match (use the route's
+ * mask).
+ */
+static boolean_t
+v4_addr_match(IpAddress addr, IpAddress mask, const filter_t *fp)
+{
+ char **app;
+ char *aptr;
+ in_addr_t faddr, fmask;
+
+ if (fp->u.a.f_address == NULL) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&fp->u.a.f_mask))
+ return (addr != INADDR_ANY); /* "any" */
+ else
+ return (addr == INADDR_ANY); /* "none" */
+ }
+ if (!IN6_IS_V4MASK(fp->u.a.f_mask))
+ return (B_FALSE);
+ IN6_V4MAPPED_TO_IPADDR(&fp->u.a.f_mask, fmask);
+ if (fmask != IP_HOST_MASK) {
+ if (fmask > mask)
+ return (B_FALSE);
+ mask = fmask;
+ }
+ for (app = fp->u.a.f_address->h_addr_list; (aptr = *app) != NULL; app++)
+ /* LINTED: (note 1) */
+ if (IN6_IS_ADDR_V4MAPPED((in6_addr_t *)aptr)) {
+ /* LINTED: (note 1) */
+ IN6_V4MAPPED_TO_IPADDR((in6_addr_t *)aptr, faddr);
+ if (((faddr ^ addr) & mask) == 0)
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Run through the filter list for an IPv4 MIB2 route entry. If all
+ * filters of a given type fail to match, then the route is filtered
+ * out (not displayed). If no filter is given or at least one filter
+ * of each type matches, then display the route.
+ */
+static boolean_t
+ire_filter_match_v4(mib2_ipRouteEntry_t *rp, uint_t flag_b)
+{
+ filter_t *fp;
+ int idx;
+
+ /* 'for' loop 1: */
+ for (idx = 0; idx < NFILTERKEYS; idx++)
+ if ((fp = filters[idx]) != NULL) {
+ /* 'for' loop 2: */
+ for (; fp != NULL; fp = fp->f_next) {
+ switch (idx) {
+ case FK_AF:
+ if (fp->u.f_family != AF_INET)
+ continue; /* 'for' loop 2 */
+ break;
+ case FK_INIF:
+ if (!dev_name_match(&rp->ipRouteInfo.
+ re_in_ill, fp->u.f_ifname))
+ continue; /* 'for' loop 2 */
+ break;
+ case FK_OUTIF:
+ if (!dev_name_match(&rp->ipRouteIfIndex,
+ fp->u.f_ifname))
+ continue; /* 'for' loop 2 */
+ break;
+ case FK_SRC:
+ if (!v4_addr_match(rp->ipRouteInfo.
+ re_in_src_addr, IP_HOST_MASK, fp))
+ continue; /* 'for' loop 2 */
+ break;
+ case FK_DST:
+ if (!v4_addr_match(rp->ipRouteDest,
+ rp->ipRouteMask, fp))
+ continue; /* 'for' loop 2 */
+ break;
+ case FK_FLAGS:
+ if ((flag_b & fp->u.f.f_flagset) !=
+ fp->u.f.f_flagset ||
+ (flag_b & fp->u.f.f_flagclear))
+ continue; /* 'for' loop 2 */
+ break;
+ }
+ break;
+ } /* 'for' loop 2 ends */
+ if (fp == NULL)
+ return (B_FALSE);
+ }
+ /* 'for' loop 1 ends */
+ return (B_TRUE);
+}
+
+/*
+ * Given an IPv4 MIB2 route entry, form the list of flags for the
+ * route.
+ */
+static uint_t
+form_v4_route_flags(mib2_ipRouteEntry_t *rp, char *flags)
+{
+ uint_t flag_b;
+
+ flag_b = FLF_U;
+ (void) strcpy(flags, "U");
+ if (rp->ipRouteInfo.re_ire_type == IRE_DEFAULT ||
+ rp->ipRouteInfo.re_ire_type == IRE_PREFIX ||
+ rp->ipRouteInfo.re_ire_type == IRE_HOST ||
+ rp->ipRouteInfo.re_ire_type == IRE_HOST_REDIRECT) {
+ (void) strcat(flags, "G");
+ flag_b |= FLF_G;
+ }
+ if (rp->ipRouteMask == IP_HOST_MASK) {
+ (void) strcat(flags, "H");
+ flag_b |= FLF_H;
+ }
+ if (rp->ipRouteInfo.re_ire_type == IRE_HOST_REDIRECT) {
+ (void) strcat(flags, "D");
+ flag_b |= FLF_D;
+ }
+ if (rp->ipRouteInfo.re_ire_type == IRE_CACHE) {
+ /* Address resolution */
+ (void) strcat(flags, "A");
+ flag_b |= FLF_A;
+ }
+ if (rp->ipRouteInfo.re_ire_type == IRE_BROADCAST) { /* Broadcast */
+ (void) strcat(flags, "B");
+ flag_b |= FLF_B;
+ }
+ if (rp->ipRouteInfo.re_ire_type == IRE_LOCAL) { /* Local */
+ (void) strcat(flags, "L");
+ flag_b |= FLF_L;
+ }
+ if (rp->ipRouteInfo.re_flags & RTF_MULTIRT) {
+ (void) strcat(flags, "M"); /* Multiroute */
+ flag_b |= FLF_M;
+ }
+ if (rp->ipRouteInfo.re_flags & RTF_SETSRC) {
+ (void) strcat(flags, "S"); /* Setsrc */
+ flag_b |= FLF_S;
+ }
+ return (flag_b);
+}
+
+static boolean_t
+ire_report_item_v4(mib2_ipRouteEntry_t *rp, boolean_t first)
+{
+ char dstbuf[MAXHOSTNAMELEN + 1];
+ char maskbuf[MAXHOSTNAMELEN + 1];
+ char gwbuf[MAXHOSTNAMELEN + 1];
+ char ifname[LIFNAMSIZ + 1];
+ char flags[10]; /* RTF_ flags */
+ uint_t flag_b;
+
+ if (rp->ipRouteInfo.re_in_src_addr != 0 ||
+ rp->ipRouteInfo.re_in_ill.o_length != 0 ||
+ !(Aflag || (rp->ipRouteInfo.re_ire_type != IRE_CACHE &&
+ rp->ipRouteInfo.re_ire_type != IRE_BROADCAST &&
+ rp->ipRouteInfo.re_ire_type != IRE_LOCAL))) {
+ return (first);
+ }
+
+ flag_b = form_v4_route_flags(rp, flags);
+
+ if (!ire_filter_match_v4(rp, flag_b))
+ return (first);
+
+ if (first) {
+ if (Vflag) {
+ (void) puts(v4compat ?
+ "\nIRE Table:" :
+ "\nIRE Table: IPv4");
+ (void) puts(" Destination Mask "
+ " Gateway "
+ "Device Mxfrg Rtt Ref Flg Out "
+ "In/Fwd");
+ (void) puts("-------------------- --------------- "
+ "-------------------- "
+ "------ ----- ----- --- --- ----- "
+ "------");
+ } else {
+ (void) puts(v4compat ?
+ "\nRouting Table:" :
+ "\nRouting Table: IPv4");
+ (void) puts(" Destination "
+ " Gateway Flags Ref Use "
+ "Interface");
+ (void) puts("-------------------- "
+ "-------------------- ----- ----- ------ "
+ "---------");
+ }
+ first = B_FALSE;
+ }
+
+ if (flag_b & FLF_H) {
+ (void) pr_addr(rp->ipRouteDest, dstbuf, sizeof (dstbuf));
+ } else {
+ (void) pr_net(rp->ipRouteDest, rp->ipRouteMask,
+ dstbuf, sizeof (dstbuf));
+ }
+ if (Vflag) {
+ (void) printf("%-20s %-15s %-20s %-6s %5u%c %4u %3u "
+ "%-4s%6u%6u\n",
+ dstbuf,
+ pr_mask(rp->ipRouteMask, maskbuf, sizeof (maskbuf)),
+ pr_addrnz(rp->ipRouteNextHop, gwbuf, sizeof (gwbuf)),
+ octetstr(&rp->ipRouteIfIndex, 'a', ifname, sizeof (ifname)),
+ rp->ipRouteInfo.re_max_frag,
+ rp->ipRouteInfo.re_frag_flag ? '*' : ' ',
+ rp->ipRouteInfo.re_rtt,
+ rp->ipRouteInfo.re_ref,
+ flags,
+ rp->ipRouteInfo.re_obpkt,
+ rp->ipRouteInfo.re_ibpkt);
+ } else {
+ (void) printf("%-20s %-20s %-5s %4u%7u %s\n",
+ dstbuf,
+ pr_addrnz(rp->ipRouteNextHop, gwbuf, sizeof (gwbuf)),
+ flags,
+ rp->ipRouteInfo.re_ref,
+ rp->ipRouteInfo.re_obpkt + rp->ipRouteInfo.re_ibpkt,
+ octetstr(&rp->ipRouteIfIndex, 'a',
+ ifname, sizeof (ifname)));
+ }
+ return (first);
+}
+
+/*
+ * Report a source-specific route.
+ */
+static boolean_t
+ire_report_item_v4src(mib2_ipRouteEntry_t *rp, boolean_t first)
+{
+ char dstbuf[MAXHOSTNAMELEN + 1];
+ char srcbuf[MAXHOSTNAMELEN + 1];
+ char gwbuf[MAXHOSTNAMELEN + 1];
+ char inif[LIFNAMSIZ + 1];
+ char outif[LIFNAMSIZ + 1];
+ uint_t flag_b;
+ char flags[10];
+
+ /*
+ * If this isn't a source specific route, or if it's filtered
+ * out, then ignore it.
+ */
+ if ((rp->ipRouteInfo.re_in_src_addr == 0 &&
+ rp->ipRouteInfo.re_in_ill.o_length == 0) ||
+ !(Aflag || (rp->ipRouteInfo.re_ire_type != IRE_CACHE &&
+ rp->ipRouteInfo.re_ire_type != IRE_BROADCAST &&
+ rp->ipRouteInfo.re_ire_type != IRE_LOCAL))) {
+ return (first);
+ }
+
+ flag_b = form_v4_route_flags(rp, flags);
+
+ if (!ire_filter_match_v4(rp, flag_b))
+ return (first);
+
+ if (first) {
+ if (Vflag) {
+ (void) printf("\nIRE Table: %sSource-Specific\n",
+ v4compat ? "" : "IPv4 ");
+ (void) puts(" Destination In If "
+ " Source Gateway "
+ " Out If Mxfrg Rtt Ref Flg Out In/Fwd");
+ (void) puts("------------------ ----------- "
+ "----------------- ----------------- "
+ "----------- ----- ----- --- --- ----- ------");
+ } else {
+ (void) printf("\nRouting Table: %sSource-Specific\n",
+ v4compat ? "" : "IPv4 ");
+ (void) puts(" Destination In If "
+ " Source Gateway Flags Use "
+ " Out If");
+ (void) puts("--------------- -------- "
+ "--------------- --------------- ----- ------ "
+ "--------");
+ }
+ first = B_FALSE;
+ }
+
+ /*
+ * This is special-cased here because the kernel doesn't actually
+ * pay any attention to the destination address on mrtun entries.
+ * Saying "default" would be misleading, though technically correct.
+ */
+ if (rp->ipRouteInfo.re_in_src_addr != 0 && rp->ipRouteDest == 0 &&
+ rp->ipRouteMask == 0)
+ (void) strlcpy(dstbuf, " --", sizeof (dstbuf));
+ else
+ (void) pr_netclassless(rp->ipRouteDest, rp->ipRouteMask,
+ dstbuf, sizeof (dstbuf));
+ (void) octetstr(&rp->ipRouteInfo.re_in_ill, 'a', inif, sizeof (inif));
+ (void) pr_addrnz(rp->ipRouteInfo.re_in_src_addr, srcbuf,
+ sizeof (srcbuf));
+ (void) octetstr(&rp->ipRouteIfIndex, 'a', outif, sizeof (outif));
+ (void) pr_addrnz(rp->ipRouteNextHop, gwbuf, sizeof (gwbuf));
+ if (Vflag) {
+ (void) printf("%-18s %-11s %-17s %-17s %-11s %4u%c %5u %3u "
+ "%-3s %5u %6u\n",
+ dstbuf, inif, srcbuf, gwbuf, outif,
+ rp->ipRouteInfo.re_max_frag,
+ rp->ipRouteInfo.re_frag_flag ? '*' : ' ',
+ rp->ipRouteInfo.re_rtt, rp->ipRouteInfo.re_ref, flags,
+ rp->ipRouteInfo.re_obpkt, rp->ipRouteInfo.re_ibpkt);
+ } else {
+ (void) printf("%-15s %-8s %-15s %-15s %-5s %6u %-8s\n", dstbuf,
+ inif, srcbuf, gwbuf, flags,
+ rp->ipRouteInfo.re_obpkt + rp->ipRouteInfo.re_ibpkt,
+ outif);
+ }
+ return (first);
+}
+
+/*
+ * Match a user-supplied IP address list against an IPv6 route entry.
+ * If the user specified "any," then any non-zero address matches. If
+ * the user specified "none," then only the zero address matches. If
+ * the user specified a subnet mask length, then use that in matching
+ * routes (select routes that are at least as specific). If the user
+ * specified only an address, then use the route's mask (select routes
+ * that would match that address). IPv4 addresses are ignored.
+ */
+static boolean_t
+v6_addr_match(const Ip6Address *addr, int masklen, const filter_t *fp)
+{
+ const uint8_t *ucp;
+ int fmasklen;
+ int i;
+ char **app;
+ char *aptr;
+
+ if (fp->u.a.f_address == NULL) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&fp->u.a.f_mask)) /* any */
+ return (!IN6_IS_ADDR_UNSPECIFIED(addr));
+ return (IN6_IS_ADDR_UNSPECIFIED(addr)); /* "none" */
+ }
+ fmasklen = 0;
+ /* 'for' loop 1a: */
+ for (ucp = fp->u.a.f_mask.s6_addr;
+ ucp < fp->u.a.f_mask.s6_addr + sizeof (fp->u.a.f_mask.s6_addr);
+ ucp++) {
+ if (*ucp != 0xff) {
+ if (*ucp != 0)
+ fmasklen += 9 - ffs(*ucp);
+ break; /* 'for' loop 1a */
+ }
+ fmasklen += 8;
+ } /* 'for' loop 1a ends */
+ if (fmasklen != IPV6_ABITS) {
+ if (fmasklen > masklen)
+ return (B_FALSE);
+ masklen = fmasklen;
+ }
+ /* 'for' loop 1b: */
+ for (app = fp->u.a.f_address->h_addr_list; (aptr = *app) != NULL;
+ app++) {
+ /* LINTED: (note 1) */
+ if (IN6_IS_ADDR_V4MAPPED((in6_addr_t *)aptr))
+ continue; /* 'for' loop 1b */
+ ucp = addr->s6_addr;
+ for (i = masklen; i >= 8; i -= 8)
+ if (*ucp++ != *aptr++)
+ break; /* 'for' loop 1b */
+ if (i == 0 ||
+ (i < 8 && ((*ucp ^ *aptr) & ~(0xff >> i)) == 0))
+ return (B_TRUE);
+ } /* 'for' loop 1b ends */
+ return (B_FALSE);
+}
+
+/*
+ * Run through the filter list for an IPv6 MIB2 IRE. For a given
+ * type, if there's at least one filter and all filters of that type
+ * fail to match, then the route doesn't match and isn't displayed.
+ * If at least one matches, or none are specified, for each of the
+ * types, then the route is selected and displayed.
+ */
+static boolean_t
+ire_filter_match_v6(mib2_ipv6RouteEntry_t *rp6, uint_t flag_b)
+{
+ filter_t *fp;
+ int idx;
+
+ /* 'for' loop 1: */
+ for (idx = 0; idx < NFILTERKEYS; idx++)
+ if ((fp = filters[idx]) != NULL) {
+ /* 'for' loop 2: */
+ for (; fp != NULL; fp = fp->f_next) {
+ switch (idx) {
+ case FK_AF:
+ if (fp->u.f_family != AF_INET6)
+ /* 'for' loop 2 */
+ continue;
+ break;
+ case FK_INIF:
+ if (fp->u.f_ifname != NULL)
+ /* 'for' loop 2 */
+ continue;
+ break;
+ case FK_OUTIF:
+ if (!dev_name_match(&rp6->
+ ipv6RouteIfIndex, fp->u.f_ifname))
+ /* 'for' loop 2 */
+ continue;
+ break;
+ case FK_SRC:
+ if (!v6_addr_match(&rp6->ipv6RouteInfo.
+ re_src_addr, IPV6_ABITS, fp))
+ /* 'for' loop 2 */
+ continue;
+ break;
+ case FK_DST:
+ if (!v6_addr_match(&rp6->ipv6RouteDest,
+ rp6->ipv6RoutePfxLength, fp))
+ /* 'for' loop 2 */
+ continue;
+ break;
+ case FK_FLAGS:
+ if ((flag_b & fp->u.f.f_flagset) !=
+ fp->u.f.f_flagset ||
+ (flag_b & fp->u.f.f_flagclear))
+ /* 'for' loop 2 */
+ continue;
+ break;
+ }
+ break;
+ } /* 'for' loop 2 ends */
+ if (fp == NULL)
+ return (B_FALSE);
+ }
+ /* 'for' loop 1 ends */
+ return (B_TRUE);
+}
+
+static boolean_t
+ire_report_item_v6(mib2_ipv6RouteEntry_t *rp6, boolean_t first)
+{
+ char dstbuf[MAXHOSTNAMELEN + 1];
+ char gwbuf[MAXHOSTNAMELEN + 1];
+ char ifname[LIFNAMSIZ + 1];
+ char flags[10]; /* RTF_ flags */
+ uint_t flag_b;
+
+ if (!(Aflag || (rp6->ipv6RouteInfo.re_ire_type != IRE_CACHE &&
+ rp6->ipv6RouteInfo.re_ire_type != IRE_LOCAL))) {
+ return (first);
+ }
+
+ flag_b = FLF_U;
+ (void) strcpy(flags, "U");
+ if (rp6->ipv6RouteInfo.re_ire_type == IRE_DEFAULT ||
+ rp6->ipv6RouteInfo.re_ire_type == IRE_PREFIX ||
+ rp6->ipv6RouteInfo.re_ire_type == IRE_HOST ||
+ rp6->ipv6RouteInfo.re_ire_type == IRE_HOST_REDIRECT) {
+ (void) strcat(flags, "G");
+ flag_b |= FLF_G;
+ }
+
+ if (rp6->ipv6RoutePfxLength == IPV6_ABITS) {
+ (void) strcat(flags, "H");
+ flag_b |= FLF_H;
+ }
+
+ if (rp6->ipv6RouteInfo.re_ire_type == IRE_HOST_REDIRECT) {
+ (void) strcat(flags, "D");
+ flag_b |= FLF_D;
+ }
+ if (rp6->ipv6RouteInfo.re_ire_type == IRE_CACHE) {
+ /* Address resolution */
+ (void) strcat(flags, "A");
+ flag_b |= FLF_A;
+ }
+ if (rp6->ipv6RouteInfo.re_ire_type == IRE_LOCAL) { /* Local */
+ (void) strcat(flags, "L");
+ flag_b |= FLF_L;
+ }
+ if (rp6->ipv6RouteInfo.re_flags & RTF_MULTIRT) {
+ (void) strcat(flags, "M"); /* Multiroute */
+ flag_b |= FLF_M;
+ }
+ if (rp6->ipv6RouteInfo.re_flags & RTF_SETSRC) {
+ (void) strcat(flags, "S"); /* Setsrc */
+ flag_b |= FLF_S;
+ }
+
+ if (!ire_filter_match_v6(rp6, flag_b))
+ return (first);
+
+ if (first) {
+ if (Vflag) {
+ (void) puts("\nIRE Table: IPv6");
+ (void) puts(" Destination/Mask "
+ " Gateway "
+ " If PMTU Rtt Ref Flags Out In/Fwd");
+ (void) puts("--------------------------- "
+ "--------------------------- "
+ "----- ------ ----- --- ----- ------ ------");
+ } else {
+ (void) puts("\nRouting Table: IPv6");
+ (void) puts(" Destination/Mask "
+ " Gateway Flags Ref Use "
+ " If ");
+ (void) puts("--------------------------- "
+ "--------------------------- ----- --- ------ "
+ "-----");
+ }
+ first = B_FALSE;
+ }
+
+ if (Vflag) {
+ (void) printf("%-27s %-27s %-5s %5u%c %5u %3u "
+ "%-5s %6u %6u\n",
+ pr_prefix6(&rp6->ipv6RouteDest,
+ rp6->ipv6RoutePfxLength, dstbuf, sizeof (dstbuf)),
+ IN6_IS_ADDR_UNSPECIFIED(&rp6->ipv6RouteNextHop) ?
+ " --" :
+ pr_addr6(&rp6->ipv6RouteNextHop, gwbuf, sizeof (gwbuf)),
+ octetstr(&rp6->ipv6RouteIfIndex, 'a',
+ ifname, sizeof (ifname)),
+ rp6->ipv6RouteInfo.re_max_frag,
+ rp6->ipv6RouteInfo.re_frag_flag ? '*' : ' ',
+ rp6->ipv6RouteInfo.re_rtt,
+ rp6->ipv6RouteInfo.re_ref,
+ flags,
+ rp6->ipv6RouteInfo.re_obpkt,
+ rp6->ipv6RouteInfo.re_ibpkt);
+ } else {
+ (void) printf("%-27s %-27s %-5s %3u %6u %-5s\n",
+ pr_prefix6(&rp6->ipv6RouteDest,
+ rp6->ipv6RoutePfxLength, dstbuf, sizeof (dstbuf)),
+ IN6_IS_ADDR_UNSPECIFIED(&rp6->ipv6RouteNextHop) ?
+ " --" :
+ pr_addr6(&rp6->ipv6RouteNextHop, gwbuf, sizeof (gwbuf)),
+ flags,
+ rp6->ipv6RouteInfo.re_ref,
+ rp6->ipv6RouteInfo.re_obpkt + rp6->ipv6RouteInfo.re_ibpkt,
+ octetstr(&rp6->ipv6RouteIfIndex, 'a',
+ ifname, sizeof (ifname)));
+ }
+ return (first);
+}
+
+/* ------------------------------ TCP_REPORT------------------------------- */
+
+static const char tcp_hdr_v4[] =
+"\nTCP: IPv4\n";
+static const char tcp_hdr_v4_compat[] =
+"\nTCP\n";
+static const char tcp_hdr_v4_verbose[] =
+"Local/Remote Address Swind Snext Suna Rwind Rnext Rack "
+" Rto Mss State\n"
+"-------------------- ----- -------- -------- ----- -------- -------- "
+"----- ----- -----\n";
+static const char tcp_hdr_v4_normal[] =
+" Local Address Remote Address Swind Send-Q Rwind Recv-Q State\n"
+"-------------------- -------------------- ----- ------ ----- ------ -------\n";
+
+static const char tcp_hdr_v6[] =
+"\nTCP: IPv6\n";
+static const char tcp_hdr_v6_verbose[] =
+"Local/Remote Address Swind Snext Suna Rwind Rnext "
+" Rack Rto Mss State If \n"
+"--------------------------------- ----- -------- -------- ----- -------- "
+"-------- ----- ----- ----------- -----\n";
+static const char tcp_hdr_v6_normal[] =
+" Local Address Remote Address "
+"Swind Send-Q Rwind Recv-Q State If \n"
+"--------------------------------- --------------------------------- "
+"----- ------ ----- ------ ----------- -----\n";
+
+static boolean_t tcp_report_item_v4(mib2_tcpConnEntry_t *tp, boolean_t first);
+static boolean_t tcp_report_item_v6(mib2_tcp6ConnEntry_t *tp6, boolean_t first);
+
+static void
+tcp_report(mib_item_t *item)
+{
+ int jtemp = 0;
+ boolean_t print_hdr_once_v4 = B_TRUE;
+ boolean_t print_hdr_once_v6 = B_TRUE;
+ mib2_tcpConnEntry_t *tp;
+ mib2_tcp6ConnEntry_t *tp6;
+
+ if (!protocol_selected(IPPROTO_TCP))
+ return;
+
+ /* 'for' loop 1: */
+ for (; item; item = item->next_item) {
+ if (Dflag) {
+ (void) printf("\n--- Entry %d ---\n", ++jtemp);
+ (void) printf("Group = %d, mib_id = %d, "
+ "length = %d, valp = 0x%p\n",
+ item->group, item->mib_id,
+ item->length, item->valp);
+ }
+
+ if (!((item->group == MIB2_TCP &&
+ item->mib_id == MIB2_TCP_CONN) ||
+ (item->group == MIB2_TCP6 &&
+ item->mib_id == MIB2_TCP6_CONN)))
+ continue; /* 'for' loop 1 */
+
+ if (item->group == MIB2_TCP && !family_selected(AF_INET))
+ continue; /* 'for' loop 1 */
+ else if (item->group == MIB2_TCP6 && !family_selected(AF_INET6))
+ continue; /* 'for' loop 1 */
+
+ if (item->group == MIB2_TCP) {
+ for (tp = (mib2_tcpConnEntry_t *)item->valp;
+ (char *)tp < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ tp = (mib2_tcpConnEntry_t *)((char *)tp +
+ tcpConnEntrySize)) {
+ print_hdr_once_v4 = tcp_report_item_v4(tp,
+ print_hdr_once_v4);
+ }
+ } else {
+ for (tp6 = (mib2_tcp6ConnEntry_t *)item->valp;
+ (char *)tp6 < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ tp6 = (mib2_tcp6ConnEntry_t *)((char *)tp6 +
+ tcp6ConnEntrySize)) {
+ print_hdr_once_v6 = tcp_report_item_v6(tp6,
+ print_hdr_once_v6);
+ }
+ }
+ } /* 'for' loop 1 ends */
+ (void) fflush(stdout);
+}
+
+static boolean_t
+tcp_report_item_v4(mib2_tcpConnEntry_t *tp, boolean_t first)
+{
+ /*
+ * lname and fname below are for the hostname as well as the portname
+ * There is no limit on portname length so we assume MAXHOSTNAMELEN
+ * as the limit
+ */
+ char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
+ char fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
+
+ if (!(Aflag || tp->tcpConnEntryInfo.ce_state >= TCPS_ESTABLISHED))
+ return (first); /* Nothing to print */
+
+ if (first) {
+ (void) fputs(v4compat ? tcp_hdr_v4_compat : tcp_hdr_v4, stdout);
+ (void) fputs(Vflag ? tcp_hdr_v4_verbose : tcp_hdr_v4_normal,
+ stdout);
+ first = B_FALSE;
+ }
+
+ if (Vflag) {
+ (void) printf("%-20s\n%-20s %5u %08x %08x %5u %08x %08x "
+ "%5u %5u %s\n",
+ pr_ap(tp->tcpConnLocalAddress,
+ tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
+ pr_ap(tp->tcpConnRemAddress,
+ tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
+ tp->tcpConnEntryInfo.ce_swnd,
+ tp->tcpConnEntryInfo.ce_snxt,
+ tp->tcpConnEntryInfo.ce_suna,
+ tp->tcpConnEntryInfo.ce_rwnd,
+ tp->tcpConnEntryInfo.ce_rnxt,
+ tp->tcpConnEntryInfo.ce_rack,
+ tp->tcpConnEntryInfo.ce_rto,
+ tp->tcpConnEntryInfo.ce_mss,
+ mitcp_state(tp->tcpConnEntryInfo.ce_state));
+ } else {
+ int sq = (int)tp->tcpConnEntryInfo.ce_snxt -
+ (int)tp->tcpConnEntryInfo.ce_suna - 1;
+ int rq = (int)tp->tcpConnEntryInfo.ce_rnxt -
+ (int)tp->tcpConnEntryInfo.ce_rack;
+
+ (void) printf("%-20s %-20s %5u %6d %5u %6d %s\n",
+ pr_ap(tp->tcpConnLocalAddress,
+ tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
+ pr_ap(tp->tcpConnRemAddress,
+ tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
+ tp->tcpConnEntryInfo.ce_swnd,
+ (sq >= 0) ? sq : 0,
+ tp->tcpConnEntryInfo.ce_rwnd,
+ (rq >= 0) ? rq : 0,
+ mitcp_state(tp->tcpConnEntryInfo.ce_state));
+ }
+ return (first);
+}
+
+static boolean_t
+tcp_report_item_v6(mib2_tcp6ConnEntry_t *tp6, boolean_t first)
+{
+ /*
+ * lname and fname below are for the hostname as well as the portname
+ * There is no limit on portname length so we assume MAXHOSTNAMELEN
+ * as the limit
+ */
+ char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
+ char fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
+ char ifname[LIFNAMSIZ + 1];
+ char *ifnamep;
+
+ if (!(Aflag || tp6->tcp6ConnEntryInfo.ce_state >= TCPS_ESTABLISHED))
+ return (first); /* Nothing to print */
+
+ if (first) {
+ (void) fputs(tcp_hdr_v6, stdout);
+ (void) fputs(Vflag ? tcp_hdr_v6_verbose : tcp_hdr_v6_normal,
+ stdout);
+ first = B_FALSE;
+ }
+
+ ifnamep = (tp6->tcp6ConnIfIndex != 0) ?
+ if_indextoname(tp6->tcp6ConnIfIndex, ifname) : NULL;
+
+ if (Vflag) {
+ (void) printf("%-33s\n%-33s %5u %08x %08x %5u %08x %08x "
+ "%5u %5u %-11s %-5s\n",
+ pr_ap6(&tp6->tcp6ConnLocalAddress,
+ tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
+ pr_ap6(&tp6->tcp6ConnRemAddress,
+ tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
+ tp6->tcp6ConnEntryInfo.ce_swnd,
+ tp6->tcp6ConnEntryInfo.ce_snxt,
+ tp6->tcp6ConnEntryInfo.ce_suna,
+ tp6->tcp6ConnEntryInfo.ce_rwnd,
+ tp6->tcp6ConnEntryInfo.ce_rnxt,
+ tp6->tcp6ConnEntryInfo.ce_rack,
+ tp6->tcp6ConnEntryInfo.ce_rto,
+ tp6->tcp6ConnEntryInfo.ce_mss,
+ mitcp_state(tp6->tcp6ConnEntryInfo.ce_state),
+ (ifnamep == NULL) ? "" : ifnamep);
+ } else {
+ int sq = (int)tp6->tcp6ConnEntryInfo.ce_snxt -
+ (int)tp6->tcp6ConnEntryInfo.ce_suna - 1;
+ int rq = (int)tp6->tcp6ConnEntryInfo.ce_rnxt -
+ (int)tp6->tcp6ConnEntryInfo.ce_rack;
+
+ (void) printf("%-33s %-33s %5u %6d %5u %6d %-11s %-5s\n",
+ pr_ap6(&tp6->tcp6ConnLocalAddress,
+ tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
+ pr_ap6(&tp6->tcp6ConnRemAddress,
+ tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
+ tp6->tcp6ConnEntryInfo.ce_swnd,
+ (sq >= 0) ? sq : 0,
+ tp6->tcp6ConnEntryInfo.ce_rwnd,
+ (rq >= 0) ? rq : 0,
+ mitcp_state(tp6->tcp6ConnEntryInfo.ce_state),
+ (ifnamep == NULL) ? "" : ifnamep);
+ }
+ return (first);
+}
+
+/* ------------------------------- UDP_REPORT------------------------------- */
+
+static boolean_t udp_report_item_v4(mib2_udpEntry_t *ude, boolean_t first);
+static boolean_t udp_report_item_v6(mib2_udp6Entry_t *ude6, boolean_t first);
+
+static char *udp_hdr_v6 =
+" Local Address Remote Address "
+" State If \n"
+"--------------------------------- --------------------------------- "
+"---------- -----\n";
+
+static void
+udp_report(mib_item_t *item)
+{
+ int jtemp = 0;
+ boolean_t print_hdr_once_v4 = B_TRUE;
+ boolean_t print_hdr_once_v6 = B_TRUE;
+ mib2_udpEntry_t *ude;
+ mib2_udp6Entry_t *ude6;
+
+ if (!protocol_selected(IPPROTO_UDP))
+ return;
+
+ /* 'for' loop 1: */
+ for (; item; item = item->next_item) {
+ if (Dflag) {
+ (void) printf("\n--- Entry %d ---\n", ++jtemp);
+ (void) printf("Group = %d, mib_id = %d, "
+ "length = %d, valp = 0x%p\n",
+ item->group, item->mib_id,
+ item->length, item->valp);
+ }
+ if (!((item->group == MIB2_UDP &&
+ item->mib_id == MIB2_UDP_ENTRY) ||
+ (item->group == MIB2_UDP6 &&
+ item->mib_id == MIB2_UDP6_ENTRY)))
+ continue; /* 'for' loop 1 */
+
+ if (item->group == MIB2_UDP && !family_selected(AF_INET))
+ continue; /* 'for' loop 1 */
+ else if (item->group == MIB2_UDP6 && !family_selected(AF_INET6))
+ continue; /* 'for' loop 1 */
+
+ /* xxx.xxx.xxx.xxx,pppp sss... */
+ if (item->group == MIB2_UDP) {
+ for (ude = (mib2_udpEntry_t *)item->valp;
+ (char *)ude < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ ude = (mib2_udpEntry_t *)((char *)ude +
+ udpEntrySize)) {
+ print_hdr_once_v4 = udp_report_item_v4(ude,
+ print_hdr_once_v4);
+ }
+ } else {
+ for (ude6 = (mib2_udp6Entry_t *)item->valp;
+ (char *)ude6 < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ ude6 = (mib2_udp6Entry_t *)((char *)ude6 +
+ udp6EntrySize)) {
+ print_hdr_once_v6 = udp_report_item_v6(ude6,
+ print_hdr_once_v6);
+ }
+ }
+ } /* 'for' loop 1 ends */
+ (void) fflush(stdout);
+}
+
+static boolean_t
+udp_report_item_v4(mib2_udpEntry_t *ude, boolean_t first)
+{
+ char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
+ /* hostname + portname */
+ char *cp;
+
+ if (!(Aflag || ude->udpEntryInfo.ue_state >= MIB2_UDP_connected))
+ return (first); /* Nothing to print */
+
+ if (first) {
+ (void) puts(v4compat ? "\nUDP" : "\nUDP: IPv4");
+ (void) puts(
+ " Local Address Remote Address State");
+ (void) puts(
+ "-------------------- -------------------- -------");
+ first = B_FALSE;
+ }
+
+ switch (ude->udpEntryInfo.ue_state) {
+ case MIB2_UDP_unbound:
+ cp = "Unbound";
+ break;
+ case MIB2_UDP_idle:
+ cp = "Idle";
+ break;
+ case MIB2_UDP_connected:
+ cp = "Connected";
+ break;
+ default:
+ cp = "Unknown";
+ break;
+ }
+ (void) printf("%-20s ",
+ pr_ap(ude->udpLocalAddress, ude->udpLocalPort, "udp",
+ lname, sizeof (lname)));
+ if (ude->udpEntryInfo.ue_state == MIB2_UDP_connected) {
+ (void) printf("%-20s ",
+ pr_ap(ude->udpEntryInfo.ue_RemoteAddress,
+ ude->udpEntryInfo.ue_RemotePort, "udp",
+ lname, sizeof (lname)));
+ } else {
+ (void) printf("%-20s ", "");
+ }
+ (void) printf(" %s\n", cp);
+ return (first);
+}
+
+static boolean_t
+udp_report_item_v6(mib2_udp6Entry_t *ude6, boolean_t first)
+{
+ char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
+ /* hostname + portname */
+ char *cp;
+ char ifname[LIFNAMSIZ + 1];
+
+ if (!(Aflag || ude6->udp6EntryInfo.ue_state >= MIB2_UDP_connected))
+ return (first); /* Nothing to print */
+
+ if (first) {
+ (void) printf("\nUDP: IPv6\n%s", udp_hdr_v6);
+ first = B_FALSE;
+ }
+
+ switch (ude6->udp6EntryInfo.ue_state) {
+ case MIB2_UDP_unbound:
+ cp = "Unbound";
+ break;
+ case MIB2_UDP_idle:
+ cp = "Idle";
+ break;
+ case MIB2_UDP_connected:
+ cp = "Connected";
+ break;
+ default:
+ cp = "Unknown";
+ break;
+ }
+ (void) printf("%-33s ",
+ pr_ap6(&ude6->udp6LocalAddress,
+ ude6->udp6LocalPort, "udp", lname, sizeof (lname)));
+ if (ude6->udp6EntryInfo.ue_state == MIB2_UDP_connected) {
+ (void) printf("%-33s ",
+ pr_ap6(&ude6->udp6EntryInfo.ue_RemoteAddress,
+ ude6->udp6EntryInfo.ue_RemotePort, "udp",
+ lname, sizeof (lname)));
+ } else {
+ (void) printf("%-33s ", "");
+ }
+ if (ude6->udp6IfIndex != 0 &&
+ (if_indextoname(ude6->udp6IfIndex, ifname) != NULL)) {
+ (void) printf("%-10s %-5s\n", cp, ifname);
+ } else {
+ (void) printf("%-10s\n", cp);
+ }
+ return (first);
+}
+
+/* ------------------------------ SCTP_REPORT------------------------------- */
+
+static const char sctp_hdr[] =
+"\nSCTP:";
+static const char sctp_hdr_normal[] =
+" Local Address Remote Address "
+"Swind Send-Q Rwind Recv-Q StrsI/O State\n"
+"------------------------------- ------------------------------- "
+"------ ------ ------ ------ ------- -----------";
+
+static const char *
+nssctp_state(int state)
+{
+ switch (state) {
+ case MIB2_SCTP_closed:
+ return ("CLOSED");
+ case MIB2_SCTP_cookieWait:
+ return ("COOKIE_WAIT");
+ case MIB2_SCTP_cookieEchoed:
+ return ("COOKIE_ECHOED");
+ case MIB2_SCTP_established:
+ return ("ESTABLISHED");
+ case MIB2_SCTP_shutdownPending:
+ return ("SHUTDOWN_PENDING");
+ case MIB2_SCTP_shutdownSent:
+ return ("SHUTDOWN_SENT");
+ case MIB2_SCTP_shutdownReceived:
+ return ("SHUTDOWN_RECEIVED");
+ case MIB2_SCTP_shutdownAckSent:
+ return ("SHUTDOWN_ACK_SENT");
+ case MIB2_SCTP_listen:
+ return ("LISTEN");
+ default:
+ return ("UNKNOWN STATE");
+ }
+}
+
+static mib2_sctpConnRemoteEntry_t *
+sctp_getnext_rem(mib_item_t **itemp, mib2_sctpConnRemoteEntry_t *current,
+ uint32_t associd)
+{
+ mib_item_t *item = *itemp;
+ mib2_sctpConnRemoteEntry_t *sre;
+
+ for (; item != NULL; item = item->next_item, current = NULL) {
+ if (!(item->group == MIB2_SCTP &&
+ item->mib_id == MIB2_SCTP_CONN_REMOTE)) {
+ continue;
+ }
+
+ if (current != NULL) {
+ /* LINTED: (note 1) */
+ sre = (mib2_sctpConnRemoteEntry_t *)((char *)current +
+ sctpRemoteEntrySize);
+ } else {
+ sre = item->valp;
+ }
+ for (; (char *)sre < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ sre = (mib2_sctpConnRemoteEntry_t *)((char *)sre +
+ sctpRemoteEntrySize)) {
+ if (sre->sctpAssocId != associd) {
+ continue;
+ }
+ *itemp = item;
+ return (sre);
+ }
+ }
+ *itemp = NULL;
+ return (NULL);
+}
+
+static mib2_sctpConnLocalEntry_t *
+sctp_getnext_local(mib_item_t **itemp, mib2_sctpConnLocalEntry_t *current,
+ uint32_t associd)
+{
+ mib_item_t *item = *itemp;
+ mib2_sctpConnLocalEntry_t *sle;
+
+ for (; item != NULL; item = item->next_item, current = NULL) {
+ if (!(item->group == MIB2_SCTP &&
+ item->mib_id == MIB2_SCTP_CONN_LOCAL)) {
+ continue;
+ }
+
+ if (current != NULL) {
+ /* LINTED: (note 1) */
+ sle = (mib2_sctpConnLocalEntry_t *)((char *)current +
+ sctpLocalEntrySize);
+ } else {
+ sle = item->valp;
+ }
+ for (; (char *)sle < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ sle = (mib2_sctpConnLocalEntry_t *)((char *)sle +
+ sctpLocalEntrySize)) {
+ if (sle->sctpAssocId != associd) {
+ continue;
+ }
+ *itemp = item;
+ return (sle);
+ }
+ }
+ *itemp = NULL;
+ return (NULL);
+}
+
+static void
+sctp_pr_addr(int type, char *name, int namelen, const in6_addr_t *addr,
+ int port)
+{
+ ipaddr_t v4addr;
+ in6_addr_t v6addr;
+
+ /*
+ * Address is either a v4 mapped or v6 addr. If
+ * it's a v4 mapped, convert to v4 before
+ * displaying.
+ */
+ switch (type) {
+ case MIB2_SCTP_ADDR_V4:
+ /* v4 */
+ v6addr = *addr;
+
+ IN6_V4MAPPED_TO_IPADDR(&v6addr, v4addr);
+ if (port > 0) {
+ (void) pr_ap(v4addr, port, "sctp", name, namelen);
+ } else {
+ (void) pr_addr(v4addr, name, namelen);
+ }
+ break;
+
+ case MIB2_SCTP_ADDR_V6:
+ /* v6 */
+ if (port > 0) {
+ (void) pr_ap6(addr, port, "sctp", name, namelen);
+ } else {
+ (void) pr_addr6(addr, name, namelen);
+ }
+ break;
+
+ default:
+ (void) snprintf(name, namelen, "<unknown addr type>");
+ break;
+ }
+}
+
+static void
+sctp_conn_report_item(mib_item_t *head, mib2_sctpConnEntry_t *sp)
+{
+ char lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
+ char fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
+ mib2_sctpConnRemoteEntry_t *sre = NULL;
+ mib2_sctpConnLocalEntry_t *sle = NULL;
+ mib_item_t *local = head;
+ mib_item_t *remote = head;
+ uint32_t id = sp->sctpAssocId;
+ boolean_t printfirst = B_TRUE;
+
+ sctp_pr_addr(sp->sctpAssocRemPrimAddrType, fname, sizeof (fname),
+ &sp->sctpAssocRemPrimAddr, sp->sctpAssocRemPort);
+ sctp_pr_addr(sp->sctpAssocRemPrimAddrType, lname, sizeof (lname),
+ &sp->sctpAssocLocPrimAddr, sp->sctpAssocLocalPort);
+
+ (void) printf("%-31s %-31s %6u %6d %6u %6d %3d/%-3d %s\n",
+ lname, fname,
+ sp->sctpConnEntryInfo.ce_swnd,
+ sp->sctpConnEntryInfo.ce_sendq,
+ sp->sctpConnEntryInfo.ce_rwnd,
+ sp->sctpConnEntryInfo.ce_recvq,
+ sp->sctpAssocInStreams, sp->sctpAssocOutStreams,
+ nssctp_state(sp->sctpAssocState));
+
+ if (!Vflag) {
+ return;
+ }
+
+ /* Print remote addresses/local addresses on following lines */
+ while ((sre = sctp_getnext_rem(&remote, sre, id)) != NULL) {
+ if (!IN6_ARE_ADDR_EQUAL(&sre->sctpAssocRemAddr,
+ &sp->sctpAssocRemPrimAddr)) {
+ if (printfirst == B_TRUE) {
+ (void) fputs("\t<Remote: ", stdout);
+ printfirst = B_FALSE;
+ } else {
+ (void) fputs(", ", stdout);
+ }
+ sctp_pr_addr(sre->sctpAssocRemAddrType, fname,
+ sizeof (fname), &sre->sctpAssocRemAddr, -1);
+ if (sre->sctpAssocRemAddrActive == MIB2_SCTP_ACTIVE) {
+ (void) fputs(fname, stdout);
+ } else {
+ (void) printf("(%s)", fname);
+ }
+ }
+ }
+ if (printfirst == B_FALSE) {
+ (void) puts(">");
+ printfirst = B_TRUE;
+ }
+ while ((sle = sctp_getnext_local(&local, sle, id)) != NULL) {
+ if (!IN6_ARE_ADDR_EQUAL(&sle->sctpAssocLocalAddr,
+ &sp->sctpAssocLocPrimAddr)) {
+ if (printfirst == B_TRUE) {
+ (void) fputs("\t<Local: ", stdout);
+ printfirst = B_FALSE;
+ } else {
+ (void) fputs(", ", stdout);
+ }
+ sctp_pr_addr(sle->sctpAssocLocalAddrType, lname,
+ sizeof (lname), &sle->sctpAssocLocalAddr, -1);
+ (void) fputs(lname, stdout);
+ }
+ }
+ if (printfirst == B_FALSE) {
+ (void) puts(">");
+ }
+}
+
+static void
+sctp_report(mib_item_t *item)
+{
+ mib_item_t *head;
+ mib2_sctpConnEntry_t *sp;
+ boolean_t first = B_TRUE;
+
+ head = item;
+ for (; item != NULL; item = item->next_item) {
+
+ if (!(item->group == MIB2_SCTP &&
+ item->mib_id == MIB2_SCTP_CONN))
+ continue;
+
+ for (sp = item->valp;
+ (char *)sp < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ sp = (mib2_sctpConnEntry_t *)((char *)sp +
+ sctpEntrySize)) {
+
+ if (Aflag ||
+ sp->sctpAssocState >= MIB2_SCTP_established) {
+ if (first == B_TRUE) {
+ (void) puts(sctp_hdr);
+ (void) puts(sctp_hdr_normal);
+ first = B_FALSE;
+ }
+ sctp_conn_report_item(head, sp);
+ }
+ }
+ }
+}
+
+static char *
+plural(int n)
+{
+ return (n != 1 ? "s" : "");
+}
+
+static char *
+pluraly(int n)
+{
+ return (n != 1 ? "ies" : "y");
+}
+
+static char *
+plurales(int n)
+{
+ return (n != 1 ? "es" : "");
+}
+
+static char *
+pktscale(n)
+ int n;
+{
+ static char buf[6];
+ char t;
+
+ if (n < 1024) {
+ t = ' ';
+ } else if (n < 1024 * 1024) {
+ t = 'k';
+ n /= 1024;
+ } else if (n < 1024 * 1024 * 1024) {
+ t = 'm';
+ n /= 1024 * 1024;
+ } else {
+ t = 'g';
+ n /= 1024 * 1024 * 1024;
+ }
+
+ (void) snprintf(buf, sizeof (buf), "%4u%c", n, t);
+ return (buf);
+}
+
+/* --------------------- mrt_report (netstat -m) -------------------------- */
+
+static void
+mrt_report(mib_item_t *item)
+{
+ int jtemp = 0;
+ struct vifctl *vip;
+ vifi_t vifi;
+ struct mfcctl *mfccp;
+ int numvifs = 0;
+ int nmfc = 0;
+ char abuf[MAXHOSTNAMELEN + 1];
+
+ if (!(family_selected(AF_INET)))
+ return;
+
+ /* 'for' loop 1: */
+ for (; item; item = item->next_item) {
+ if (Dflag) {
+ (void) printf("\n--- Entry %d ---\n", ++jtemp);
+ (void) printf("Group = %d, mib_id = %d, "
+ "length = %d, valp = 0x%p\n",
+ item->group, item->mib_id, item->length,
+ item->valp);
+ }
+ if (item->group != EXPER_DVMRP)
+ continue; /* 'for' loop 1 */
+
+ switch (item->mib_id) {
+
+ case EXPER_DVMRP_VIF:
+ if (Dflag)
+ (void) printf("%u records for ipVifTable:\n",
+ item->length/sizeof (struct vifctl));
+ if (item->length/sizeof (struct vifctl) == 0) {
+ (void) puts("\nVirtual Interface Table is "
+ "empty");
+ break;
+ }
+
+ (void) puts("\nVirtual Interface Table\n"
+ " Vif Threshold Rate_Limit Local-Address"
+ " Remote-Address Pkt_in Pkt_out");
+
+ /* 'for' loop 2: */
+ for (vip = (struct vifctl *)item->valp;
+ (char *)vip < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ vip = (struct vifctl *)((char *)vip +
+ vifctlSize)) {
+ if (vip->vifc_lcl_addr.s_addr == 0)
+ continue; /* 'for' loop 2 */
+ /* numvifs = vip->vifc_vifi; */
+
+ numvifs++;
+ (void) printf(" %2u %3u "
+ "%4u %-15.15s",
+ vip->vifc_vifi,
+ vip->vifc_threshold,
+ vip->vifc_rate_limit,
+ pr_addr(vip->vifc_lcl_addr.s_addr,
+ abuf, sizeof (abuf)));
+ (void) printf(" %-15.15s %8u %8u\n",
+ (vip->vifc_flags & VIFF_TUNNEL) ?
+ pr_addr(vip->vifc_rmt_addr.s_addr,
+ abuf, sizeof (abuf)) : "",
+ vip->vifc_pkt_in,
+ vip->vifc_pkt_out);
+ } /* 'for' loop 2 ends */
+
+ (void) printf("Numvifs: %d\n", numvifs);
+ break;
+
+ case EXPER_DVMRP_MRT:
+ if (Dflag)
+ (void) printf("%u records for ipMfcTable:\n",
+ item->length/sizeof (struct vifctl));
+ if (item->length/sizeof (struct vifctl) == 0) {
+ (void) puts("\nMulticast Forwarding Cache is "
+ "empty");
+ break;
+ }
+
+ (void) puts("\nMulticast Forwarding Cache\n"
+ " Origin-Subnet Mcastgroup "
+ "# Pkts In-Vif Out-vifs/Forw-ttl");
+
+ for (mfccp = (struct mfcctl *)item->valp;
+ (char *)mfccp < (char *)item->valp + item->length;
+ /* LINTED: (note 1) */
+ mfccp = (struct mfcctl *)((char *)mfccp +
+ mfcctlSize)) {
+
+ nmfc++;
+ (void) printf(" %-30.15s",
+ pr_addr(mfccp->mfcc_origin.s_addr,
+ abuf, sizeof (abuf)));
+ (void) printf("%-15.15s %6s %3u ",
+ pr_net(mfccp->mfcc_mcastgrp.s_addr,
+ mfccp->mfcc_mcastgrp.s_addr,
+ abuf, sizeof (abuf)),
+ pktscale((int)mfccp->mfcc_pkt_cnt),
+ mfccp->mfcc_parent);
+
+ for (vifi = 0; vifi < MAXVIFS; ++vifi) {
+ if (mfccp->mfcc_ttls[vifi]) {
+ (void) printf(" %u (%u)",
+ vifi,
+ mfccp->mfcc_ttls[vifi]);
+ }
+
+ }
+ (void) putchar('\n');
+ }
+ (void) printf("\nTotal no. of entries in cache: %d\n",
+ nmfc);
+ break;
+ }
+ } /* 'for' loop 1 ends */
+ (void) putchar('\n');
+ (void) fflush(stdout);
+}
+
+/*
+ * Get the stats for the cache named 'name'. If prefix != 0, then
+ * interpret the name as a prefix, and sum up stats for all caches
+ * named 'name*'.
+ */
+static void
+kmem_cache_stats(char *title, char *name, int prefix, int64_t *total_bytes)
+{
+ int len;
+ int alloc;
+ int64_t total_alloc = 0;
+ int alloc_fail, total_alloc_fail = 0;
+ int buf_size = 0;
+ int buf_avail;
+ int buf_total;
+ int buf_max, total_buf_max = 0;
+ int buf_inuse, total_buf_inuse = 0;
+ kstat_t *ksp;
+ char buf[256];
+
+ len = prefix ? strlen(name) : 256;
+
+ /* 'for' loop 1: */
+ for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
+
+ if (strcmp(ksp->ks_class, "kmem_cache") != 0)
+ continue; /* 'for' loop 1 */
+
+ /*
+ * Hack alert: because of the way streams messages are
+ * allocated, every constructed free dblk has an associated
+ * mblk. From the allocator's viewpoint those mblks are
+ * allocated (because they haven't been freed), but from
+ * our viewpoint they're actually free (because they're
+ * not currently in use). To account for this caching
+ * effect we subtract the total constructed free dblks
+ * from the total allocated mblks to derive mblks in use.
+ */
+ if (strcmp(name, "streams_mblk") == 0 &&
+ strncmp(ksp->ks_name, "streams_dblk", 12) == 0) {
+ (void) safe_kstat_read(kc, ksp, NULL);
+ total_buf_inuse -=
+ kstat_named_value(ksp, "buf_constructed");
+ continue; /* 'for' loop 1 */
+ }
+
+ if (strncmp(ksp->ks_name, name, len) != 0)
+ continue; /* 'for' loop 1 */
+
+ (void) safe_kstat_read(kc, ksp, NULL);
+
+ alloc = kstat_named_value(ksp, "alloc");
+ alloc_fail = kstat_named_value(ksp, "alloc_fail");
+ buf_size = kstat_named_value(ksp, "buf_size");
+ buf_avail = kstat_named_value(ksp, "buf_avail");
+ buf_total = kstat_named_value(ksp, "buf_total");
+ buf_max = kstat_named_value(ksp, "buf_max");
+ buf_inuse = buf_total - buf_avail;
+
+ if (Vflag && prefix) {
+ (void) snprintf(buf, sizeof (buf), "%s%s", title,
+ ksp->ks_name + len);
+ (void) printf(" %-18s %6u %9u %11u %11u\n",
+ buf, buf_inuse, buf_max, alloc, alloc_fail);
+ }
+
+ total_alloc += alloc;
+ total_alloc_fail += alloc_fail;
+ total_buf_max += buf_max;
+ total_buf_inuse += buf_inuse;
+ *total_bytes += (int64_t)buf_inuse * buf_size;
+ } /* 'for' loop 1 ends */
+
+ if (buf_size == 0) {
+ (void) printf("%-22s [couldn't find statistics for %s]\n",
+ title, name);
+ return;
+ }
+
+ if (Vflag && prefix)
+ (void) snprintf(buf, sizeof (buf), "%s_total", title);
+ else
+ (void) snprintf(buf, sizeof (buf), "%s", title);
+
+ (void) printf("%-22s %6d %9d %11lld %11d\n", buf,
+ total_buf_inuse, total_buf_max, total_alloc, total_alloc_fail);
+}
+
+static void
+m_report(void)
+{
+ int64_t total_bytes = 0;
+
+ (void) puts("streams allocation:");
+ (void) printf("%63s\n", "cumulative allocation");
+ (void) printf("%63s\n",
+ "current maximum total failures");
+
+ kmem_cache_stats("streams",
+ "stream_head_cache", 0, &total_bytes);
+ kmem_cache_stats("queues", "queue_cache", 0, &total_bytes);
+ kmem_cache_stats("mblk", "streams_mblk", 0, &total_bytes);
+ kmem_cache_stats("dblk", "streams_dblk", 1, &total_bytes);
+ kmem_cache_stats("linkblk", "linkinfo_cache", 0, &total_bytes);
+ kmem_cache_stats("syncq", "syncq_cache", 0, &total_bytes);
+ kmem_cache_stats("qband", "qband_cache", 0, &total_bytes);
+
+ (void) printf("\n%lld Kbytes allocated for streams data\n",
+ total_bytes / 1024);
+
+ (void) putchar('\n');
+ (void) fflush(stdout);
+}
+
+/* --------------------------------- */
+
+/*
+ * Print an IPv4 address. Remove the matching part of the domain name
+ * from the returned name.
+ */
+static char *
+pr_addr(uint_t addr, char *dst, uint_t dstlen)
+{
+ char *cp;
+ struct hostent *hp = NULL;
+ static char domain[MAXHOSTNAMELEN + 1];
+ static boolean_t first = B_TRUE;
+ int error_num;
+
+ if (first) {
+ first = B_FALSE;
+ if (sysinfo(SI_HOSTNAME, domain, MAXHOSTNAMELEN) != -1 &&
+ (cp = strchr(domain, '.'))) {
+ (void) strncpy(domain, cp + 1, sizeof (domain));
+ } else
+ domain[0] = 0;
+ }
+ cp = NULL;
+ if (!Nflag) {
+ hp = getipnodebyaddr((char *)&addr, sizeof (uint_t), AF_INET,
+ &error_num);
+ if (hp) {
+ if ((cp = strchr(hp->h_name, '.')) != NULL &&
+ strcasecmp(cp + 1, domain) == 0)
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (cp != NULL) {
+ (void) strncpy(dst, cp, dstlen);
+ dst[dstlen - 1] = 0;
+ } else {
+ (void) inet_ntop(AF_INET, (char *)&addr, dst, dstlen);
+ }
+ if (hp != NULL)
+ freehostent(hp);
+ return (dst);
+}
+
+/*
+ * Print a non-zero IPv4 address. Print " --" if the address is zero.
+ */
+static char *
+pr_addrnz(ipaddr_t addr, char *dst, uint_t dstlen)
+{
+ if (addr == INADDR_ANY) {
+ (void) strlcpy(dst, " --", dstlen);
+ return (dst);
+ }
+ return (pr_addr(addr, dst, dstlen));
+}
+
+/*
+ * Print an IPv6 address. Remove the matching part of the domain name
+ * from the returned name.
+ */
+static char *
+pr_addr6(const struct in6_addr *addr, char *dst, uint_t dstlen)
+{
+ char *cp;
+ struct hostent *hp = NULL;
+ static char domain[MAXHOSTNAMELEN + 1];
+ static boolean_t first = B_TRUE;
+ int error_num;
+
+ if (first) {
+ first = B_FALSE;
+ if (sysinfo(SI_HOSTNAME, domain, MAXHOSTNAMELEN) != -1 &&
+ (cp = strchr(domain, '.'))) {
+ (void) strncpy(domain, cp + 1, sizeof (domain));
+ } else
+ domain[0] = 0;
+ }
+ cp = NULL;
+ if (!Nflag) {
+ hp = getipnodebyaddr((char *)addr,
+ sizeof (struct in6_addr), AF_INET6, &error_num);
+ if (hp) {
+ if ((cp = strchr(hp->h_name, '.')) != NULL &&
+ strcasecmp(cp + 1, domain) == 0)
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (cp != NULL) {
+ (void) strncpy(dst, cp, dstlen);
+ dst[dstlen - 1] = 0;
+ } else {
+ (void) inet_ntop(AF_INET6, (void *)addr, dst, dstlen);
+ }
+ if (hp != NULL)
+ freehostent(hp);
+ return (dst);
+}
+
+/* For IPv4 masks */
+static char *
+pr_mask(uint_t addr, char *dst, uint_t dstlen)
+{
+ uint8_t *ip_addr = (uint8_t *)&addr;
+
+ (void) snprintf(dst, dstlen, "%d.%d.%d.%d",
+ ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3]);
+ return (dst);
+}
+
+/*
+ * For ipv6 masks format is : dest/mask
+ * Does not print /128 to save space in printout. H flag carries this notion.
+ */
+static char *
+pr_prefix6(struct in6_addr *addr, uint_t prefixlen, char *dst, uint_t dstlen)
+{
+ char *cp;
+
+ if (IN6_IS_ADDR_UNSPECIFIED(addr) && prefixlen == 0) {
+ (void) strncpy(dst, "default", dstlen);
+ dst[dstlen - 1] = 0;
+ return (dst);
+ }
+
+ (void) pr_addr6(addr, dst, dstlen);
+ if (prefixlen != IPV6_ABITS) {
+ /* How much room is left? */
+ cp = strchr(dst, '\0');
+ if (dst + dstlen > cp) {
+ dstlen -= (cp - dst);
+ (void) snprintf(cp, dstlen, "/%d", prefixlen);
+ }
+ }
+ return (dst);
+}
+
+/* Print IPv4 address and port */
+static char *
+pr_ap(uint_t addr, uint_t port, char *proto,
+ char *dst, uint_t dstlen)
+{
+ char *cp;
+
+ if (addr == INADDR_ANY) {
+ (void) strncpy(dst, " *", dstlen);
+ dst[dstlen - 1] = 0;
+ } else {
+ (void) pr_addr(addr, dst, dstlen);
+ }
+ /* How much room is left? */
+ cp = strchr(dst, '\0');
+ if (dst + dstlen > cp + 1) {
+ *cp++ = '.';
+ dstlen -= (cp - dst);
+ dstlen--;
+ (void) portname(port, proto, cp, dstlen);
+ }
+ return (dst);
+}
+
+/* Print IPv6 address and port */
+static char *
+pr_ap6(const in6_addr_t *addr, uint_t port, char *proto,
+ char *dst, uint_t dstlen)
+{
+ char *cp;
+
+ if (IN6_IS_ADDR_UNSPECIFIED(addr)) {
+ (void) strncpy(dst, " *", dstlen);
+ dst[dstlen - 1] = 0;
+ } else {
+ (void) pr_addr6(addr, dst, dstlen);
+ }
+ /* How much room is left? */
+ cp = strchr(dst, '\0');
+ if (dst + dstlen + 1 > cp) {
+ *cp++ = '.';
+ dstlen -= (cp - dst);
+ dstlen--;
+ (void) portname(port, proto, cp, dstlen);
+ }
+ return (dst);
+}
+
+/*
+ * Return the name of the network whose address is given. The address is
+ * assumed to be that of a net or subnet, not a host.
+ */
+static char *
+pr_net(uint_t addr, uint_t mask, char *dst, uint_t dstlen)
+{
+ char *cp = NULL;
+ struct netent *np = NULL;
+ struct hostent *hp = NULL;
+ uint_t net;
+ int subnetshift;
+ int error_num;
+
+ if (addr == INADDR_ANY && mask == INADDR_ANY) {
+ (void) strncpy(dst, "default", dstlen);
+ dst[dstlen - 1] = 0;
+ return (dst);
+ }
+
+ if (!Nflag && addr) {
+ if (mask == 0) {
+ if (IN_CLASSA(addr)) {
+ mask = (uint_t)IN_CLASSA_NET;
+ subnetshift = 8;
+ } else if (IN_CLASSB(addr)) {
+ mask = (uint_t)IN_CLASSB_NET;
+ subnetshift = 8;
+ } else {
+ mask = (uint_t)IN_CLASSC_NET;
+ subnetshift = 4;
+ }
+ /*
+ * If there are more bits than the standard mask
+ * would suggest, subnets must be in use. Guess at
+ * the subnet mask, assuming reasonable width subnet
+ * fields.
+ */
+ while (addr & ~mask)
+ /* compiler doesn't sign extend! */
+ mask = (mask | ((int)mask >> subnetshift));
+ }
+ net = addr & mask;
+ while ((mask & 1) == 0)
+ mask >>= 1, net >>= 1;
+ np = getnetbyaddr(net, AF_INET);
+ if (np && np->n_net == net)
+ cp = np->n_name;
+ else {
+ /*
+ * Look for subnets in hosts map.
+ */
+ hp = getipnodebyaddr((char *)&addr, sizeof (uint_t),
+ AF_INET, &error_num);
+ if (hp)
+ cp = hp->h_name;
+ }
+ }
+ if (cp != NULL) {
+ (void) strncpy(dst, cp, dstlen);
+ dst[dstlen - 1] = 0;
+ } else {
+ (void) inet_ntop(AF_INET, (char *)&addr, dst, dstlen);
+ }
+ if (hp != NULL)
+ freehostent(hp);
+ return (dst);
+}
+
+/*
+ * Return the name of the network whose address is given.
+ * The address is assumed to be a host address.
+ */
+static char *
+pr_netaddr(uint_t addr, uint_t mask, char *dst, uint_t dstlen)
+{
+ char *cp = NULL;
+ struct netent *np = NULL;
+ struct hostent *hp = NULL;
+ uint_t net;
+ uint_t netshifted;
+ int subnetshift;
+ struct in_addr in;
+ int error_num;
+ uint_t nbo_addr = addr; /* network byte order */
+
+ addr = ntohl(addr);
+ mask = ntohl(mask);
+ if (addr == INADDR_ANY && mask == INADDR_ANY) {
+ (void) strncpy(dst, "default", dstlen);
+ dst[dstlen - 1] = 0;
+ return (dst);
+ }
+
+ /* Figure out network portion of address (with host portion = 0) */
+ if (addr) {
+ /* Try figuring out mask if unknown (all 0s). */
+ if (mask == 0) {
+ if (IN_CLASSA(addr)) {
+ mask = (uint_t)IN_CLASSA_NET;
+ subnetshift = 8;
+ } else if (IN_CLASSB(addr)) {
+ mask = (uint_t)IN_CLASSB_NET;
+ subnetshift = 8;
+ } else {
+ mask = (uint_t)IN_CLASSC_NET;
+ subnetshift = 4;
+ }
+ /*
+ * If there are more bits than the standard mask
+ * would suggest, subnets must be in use. Guess at
+ * the subnet mask, assuming reasonable width subnet
+ * fields.
+ */
+ while (addr & ~mask)
+ /* compiler doesn't sign extend! */
+ mask = (mask | ((int)mask >> subnetshift));
+ }
+ net = netshifted = addr & mask;
+ while ((mask & 1) == 0)
+ mask >>= 1, netshifted >>= 1;
+ }
+ else
+ net = netshifted = 0;
+
+ /* Try looking up name unless -n was specified. */
+ if (!Nflag) {
+ np = getnetbyaddr(netshifted, AF_INET);
+ if (np && np->n_net == netshifted)
+ cp = np->n_name;
+ else {
+ /*
+ * Look for subnets in hosts map.
+ */
+ hp = getipnodebyaddr((char *)&nbo_addr, sizeof (uint_t),
+ AF_INET, &error_num);
+ if (hp)
+ cp = hp->h_name;
+ }
+
+ if (cp != NULL) {
+ (void) strncpy(dst, cp, dstlen);
+ dst[dstlen - 1] = 0;
+ if (hp != NULL)
+ freehostent(hp);
+ return (dst);
+ }
+ /*
+ * No name found for net: fallthru and return in decimal
+ * dot notation.
+ */
+ }
+
+ in.s_addr = htonl(net);
+ (void) inet_ntop(AF_INET, (char *)&in, dst, dstlen);
+ if (hp != NULL)
+ freehostent(hp);
+ return (dst);
+}
+
+
+/*
+ * Return the standard IPv4 classess host or network identifier.
+ *
+ * Returns "default" for the default route.
+ * Returns "x.x.x.x" or host name if mask is 255.255.255.255.
+ * Returns "x.x.x.x/y" (y is bit count) if mask is contiguous.
+ * Otherwise, returns "x.x.x.x/m.m.m.m" (undesirable mask).
+ *
+ * Can also return "****" if inet_ntop fails -- insufficient dst space
+ * available. (Shouldn't happen otherwise.)
+ */
+static char *
+pr_netclassless(ipaddr_t addr, ipaddr_t mask, char *dst, size_t dstlen)
+{
+ struct hostent *hp;
+ int error_num;
+ struct in_addr in;
+ char *cp;
+ int slen;
+
+ if (addr == INADDR_ANY && mask == INADDR_ANY) {
+ (void) strlcpy(dst, "default", dstlen);
+ return (dst);
+ }
+ if (mask == IP_HOST_MASK && !Nflag &&
+ (hp = getipnodebyaddr(&addr, sizeof (addr), AF_INET,
+ &error_num)) != NULL) {
+ (void) strlcpy(dst, hp->h_name, dstlen);
+ freehostent(hp);
+ return (dst);
+ }
+ in.s_addr = addr;
+ if (inet_ntop(AF_INET, &in, dst, dstlen) == NULL) {
+ (void) strlcpy(dst, "****", dstlen);
+ return (dst);
+ }
+ if (mask != IP_HOST_MASK) {
+ slen = strlen(dst);
+ cp = dst + slen;
+ dstlen -= slen;
+ if (mask == 0) {
+ /* Illegal on non-zero addresses */
+ (void) strlcpy(cp, "/0", dstlen);
+ } else if ((mask | (mask - 1)) == IP_HOST_MASK) {
+ (void) snprintf(cp, dstlen, "/%d",
+ IP_ABITS - ffs(mask) + 1);
+ } else {
+ /* Ungood; non-contiguous mask */
+ (void) pr_mask(mask, cp, dstlen);
+ }
+ }
+ return (dst);
+}
+
+/*
+ * Return the filter mode as a string:
+ * 1 => "INCLUDE"
+ * 2 => "EXCLUDE"
+ * otherwise "<unknown>"
+ */
+static char *
+fmodestr(uint_t fmode)
+{
+ switch (fmode) {
+ case 1:
+ return ("INCLUDE");
+ case 2:
+ return ("EXCLUDE");
+ default:
+ return ("<unknown>");
+ }
+}
+
+/*
+ * Pretty print a port number. If the Nflag was
+ * specified, use numbers instead of names.
+ */
+static char *
+portname(uint_t port, char *proto, char *dst, uint_t dstlen)
+{
+ struct servent *sp = NULL;
+
+ if (!Nflag && port)
+ sp = getservbyport(htons(port), proto);
+ if (sp || port == 0)
+ (void) snprintf(dst, dstlen, "%.*s", MAXHOSTNAMELEN,
+ sp ? sp->s_name : "*");
+ else
+ (void) snprintf(dst, dstlen, "%d", port);
+ dst[dstlen - 1] = 0;
+ return (dst);
+}
+
+/*PRINTFLIKE2*/
+void
+fail(int do_perror, char *message, ...)
+{
+ va_list args;
+
+ va_start(args, message);
+ (void) fputs("netstat: ", stderr);
+ (void) vfprintf(stderr, message, args);
+ va_end(args);
+ if (do_perror)
+ (void) fprintf(stderr, ": %s", strerror(errno));
+ (void) fputc('\n', stderr);
+ exit(2);
+}
+
+/*
+ * Return value of named statistic for given kstat_named kstat;
+ * return 0LL if named statistic is not in list (use "ll" as a
+ * type qualifier when printing 64-bit int's with printf() )
+ */
+static uint64_t
+kstat_named_value(kstat_t *ksp, char *name)
+{
+ kstat_named_t *knp;
+ uint64_t value;
+
+ if (ksp == NULL)
+ return (0LL);
+
+ knp = kstat_data_lookup(ksp, name);
+ if (knp == NULL)
+ return (0LL);
+
+ switch (knp->data_type) {
+ case KSTAT_DATA_INT32:
+ case KSTAT_DATA_UINT32:
+ value = (uint64_t)(knp->value.ui32);
+ break;
+ case KSTAT_DATA_INT64:
+ case KSTAT_DATA_UINT64:
+ value = knp->value.ui64;
+ break;
+ default:
+ value = 0LL;
+ break;
+ }
+
+ return (value);
+}
+
+kid_t
+safe_kstat_read(kstat_ctl_t *kc, kstat_t *ksp, void *data)
+{
+ kid_t kstat_chain_id = kstat_read(kc, ksp, data);
+
+ if (kstat_chain_id == -1)
+ fail(1, "kstat_read(%p, '%s') failed", (void *)kc,
+ ksp->ks_name);
+ return (kstat_chain_id);
+}
+
+/*
+ * Parse a list of IRE flag characters into a bit field.
+ */
+static uint_t
+flag_bits(const char *arg)
+{
+ const char *cp;
+ uint_t val;
+
+ if (*arg == '\0')
+ fatal(1, "missing flag list\n");
+
+ val = 0;
+ while (*arg != '\0') {
+ if ((cp = strchr(flag_list, *arg)) == NULL)
+ fatal(1, "%c: illegal flag\n", *arg);
+ val |= 1 << (cp - flag_list);
+ arg++;
+ }
+ return (val);
+}
+
+/*
+ * Handle -f argument. Validate input format, sort by keyword, and
+ * save off digested results.
+ */
+static void
+process_filter(char *arg)
+{
+ int idx;
+ int klen = 0;
+ char *cp, *cp2;
+ int val;
+ filter_t *newf;
+ struct hostent *hp;
+ int error_num;
+ uint8_t *ucp;
+ int maxv;
+
+ /* Look up the keyword first */
+ if (strchr(arg, ':') == NULL) {
+ idx = FK_AF;
+ } else {
+ for (idx = 0; idx < NFILTERKEYS; idx++) {
+ klen = strlen(filter_keys[idx]);
+ if (strncmp(filter_keys[idx], arg, klen) == 0 &&
+ arg[klen] == ':')
+ break;
+ }
+ if (idx >= NFILTERKEYS)
+ fatal(1, "%s: unknown filter keyword\n", arg);
+
+ /* Advance past keyword and separator. */
+ arg += klen + 1;
+ }
+
+ if ((newf = malloc(sizeof (*newf))) == NULL) {
+ perror("filter");
+ exit(1);
+ }
+ switch (idx) {
+ case FK_AF:
+ if (strcmp(arg, "inet") == 0) {
+ newf->u.f_family = AF_INET;
+ } else if (strcmp(arg, "inet6") == 0) {
+ newf->u.f_family = AF_INET6;
+ } else if (strcmp(arg, "unix") == 0) {
+ newf->u.f_family = AF_UNIX;
+ } else {
+ newf->u.f_family = strtol(arg, &cp, 0);
+ if (arg == cp || *cp != '\0')
+ fatal(1, "%s: unknown address family.\n", arg);
+ }
+ break;
+
+ case FK_INIF:
+ case FK_OUTIF:
+ if (strcmp(arg, "none") == 0) {
+ newf->u.f_ifname = NULL;
+ break;
+ }
+ if (strcmp(arg, "any") == 0) {
+ newf->u.f_ifname = "";
+ break;
+ }
+ val = strtol(arg, &cp, 0);
+ if (val <= 0 || arg == cp || cp[0] != '\0') {
+ if ((val = if_nametoindex(arg)) == 0) {
+ perror(arg);
+ exit(1);
+ }
+ }
+ newf->u.f_ifname = arg;
+ break;
+
+ case FK_SRC:
+ case FK_DST:
+ V4MASK_TO_V6(IP_HOST_MASK, newf->u.a.f_mask);
+ if (strcmp(arg, "any") == 0) {
+ /* Special semantics; any address *but* zero */
+ newf->u.a.f_address = NULL;
+ (void) memset(&newf->u.a.f_mask, 0,
+ sizeof (newf->u.a.f_mask));
+ break;
+ }
+ if (strcmp(arg, "none") == 0) {
+ newf->u.a.f_address = NULL;
+ break;
+ }
+ if ((cp = strrchr(arg, '/')) != NULL)
+ *cp++ = '\0';
+ hp = getipnodebyname(arg, AF_INET6, AI_V4MAPPED|AI_ALL,
+ &error_num);
+ if (hp == NULL)
+ fatal(1, "%s: invalid or unknown host address\n", arg);
+ newf->u.a.f_address = hp;
+ if (cp == NULL) {
+ V4MASK_TO_V6(IP_HOST_MASK, newf->u.a.f_mask);
+ } else {
+ val = strtol(cp, &cp2, 0);
+ if (cp != cp2 && cp2[0] == '\0') {
+ /*
+ * If decode as "/n" works, then translate
+ * into a mask.
+ */
+ if (hp->h_addr_list[0] != NULL &&
+ /* LINTED: (note 1) */
+ IN6_IS_ADDR_V4MAPPED((in6_addr_t
+ *)hp->h_addr_list[0])) {
+ maxv = IP_ABITS;
+ } else {
+ maxv = IPV6_ABITS;
+ }
+ if (val < 0 || val >= maxv)
+ fatal(1, "%d: not in range 0 to %d\n",
+ val, maxv - 1);
+ if (maxv == IP_ABITS)
+ val += IPV6_ABITS - IP_ABITS;
+ ucp = newf->u.a.f_mask.s6_addr;
+ while (val >= 8)
+ *ucp++ = 0xff, val -= 8;
+ *ucp++ = (0xff << (8 - val)) & 0xff;
+ while (ucp < newf->u.a.f_mask.s6_addr +
+ sizeof (newf->u.a.f_mask.s6_addr))
+ *ucp++ = 0;
+ /* Otherwise, try as numeric address */
+ } else if (inet_pton(AF_INET6,
+ cp, &newf->u.a.f_mask) <= 0) {
+ fatal(1, "%s: illegal mask format\n", cp);
+ }
+ }
+ break;
+
+ case FK_FLAGS:
+ if (*arg == '+') {
+ newf->u.f.f_flagset = flag_bits(arg + 1);
+ newf->u.f.f_flagclear = 0;
+ } else if (*arg == '-') {
+ newf->u.f.f_flagset = 0;
+ newf->u.f.f_flagclear = flag_bits(arg + 1);
+ } else {
+ newf->u.f.f_flagset = flag_bits(arg);
+ newf->u.f.f_flagclear = ~newf->u.f.f_flagset;
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+ newf->f_next = filters[idx];
+ filters[idx] = newf;
+}
+
+/* Determine if user wants this address family printed. */
+static boolean_t
+family_selected(int family)
+{
+ const filter_t *fp;
+
+ if (v4compat && family == AF_INET6)
+ return (B_FALSE);
+ if ((fp = filters[FK_AF]) == NULL)
+ return (B_TRUE);
+ while (fp != NULL) {
+ if (fp->u.f_family == family)
+ return (B_TRUE);
+ fp = fp->f_next;
+ }
+ return (B_FALSE);
+}
+
+/*
+ * print the usage line
+ */
+static void
+usage(char *cmdname)
+{
+ (void) fprintf(stderr, "usage: %s [-anv] [-f address_family]\n",
+ cmdname);
+ (void) fprintf(stderr, " %s [-n] [-f address_family] "
+ "[-P protocol] [-g | -p | -s [interval [count]]]\n", cmdname);
+ (void) fprintf(stderr, " %s -m [-v] "
+ "[interval [count]]\n", cmdname);
+ (void) fprintf(stderr, " %s -i [-I interface] [-an] "
+ "[-f address_family] [interval [count]]\n", cmdname);
+ (void) fprintf(stderr, " %s -r [-anv] "
+ "[-f address_family|filter]\n", cmdname);
+ (void) fprintf(stderr, " %s -M [-ns] [-f address_family]\n",
+ cmdname);
+ (void) fprintf(stderr, " %s -D [-I interface] "
+ "[-f address_family]\n", cmdname);
+ exit(EXIT_FAILURE);
+}
+
+/*
+ * fatal: print error message to stderr and
+ * call exit(errcode)
+ */
+/*PRINTFLIKE2*/
+static void
+fatal(int errcode, char *format, ...) {
+ va_list argp;
+
+ if (format == NULL)
+ return;
+
+ va_start(argp, format);
+ (void) vfprintf(stderr, format, argp);
+ va_end(argp);
+
+ exit(errcode);
+}