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