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