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