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