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(uint32_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_node_list_hdr_t *, boolean_t first,
4799     const mib2_transportMLPEntry_t *);
4800 static boolean_t tcp_report_item_v6(const mib2_tcp6ConnEntry_t *,
4801     conn_pid_node_list_hdr_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_node_list_hdr_t        *cph;
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 *)cph +
4889                             cph->cph_tot_size)) {
4890                                 aptr = v4a == NULL ? NULL : *v4a++;
4891                                 /* LINTED: (note 1) */
4892                                 cph = (conn_pid_node_list_hdr_t *)
4893                                         ((char *)tp + tcpConnEntrySize);
4894                                 print_hdr_once_v4 = tcp_report_item_v4(tp,
4895                                     cph, 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 *)cph +
4903                             cph->cph_tot_size)) {
4904                                 aptr = v6a == NULL ? NULL : *v6a++;
4905                                 /* LINTED: (note 1) */
4906                                 cph = (conn_pid_node_list_hdr_t *)
4907                                         ((char *)tp6 + tcp6ConnEntrySize);
4908                                 print_hdr_once_v6 = tcp_report_item_v6(tp6,
4909                                     cph, 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,
4924     conn_pid_node_list_hdr_t * cph, boolean_t first,
4925     const mib2_transportMLPEntry_t *attr)
4926 {
4927         /*
4928          * lname and fname below are for the hostname as well as the portname
4929          * There is no limit on portname length so we assume MAXHOSTNAMELEN
4930          * as the limit
4931          */
4932         char    lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4933         char    fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
4934 
4935 
4936         if (!(Aflag || tp->tcpConnEntryInfo.ce_state >= TCPS_ESTABLISHED))
4937                 return (first); /* Nothing to print */
4938 
4939         if (first) {
4940                 (void) printf(v4compat ? tcp_hdr_v4_compat : tcp_hdr_v4);
4941                 if (Uflag)
4942                         (void) printf(Vflag ? tcp_hdr_v4_pid_verbose :
4943                                 tcp_hdr_v4_pid);
4944                 else
4945                         (void) printf(Vflag ? tcp_hdr_v4_verbose :
4946                                 tcp_hdr_v4_normal);
4947         }
4948 
4949         if ((!Uflag) && Vflag) {
4950                 (void) printf("%-20s\n%-20s %5u %08x %08x %5u %08x %08x "
4951                     "%5u %5u %s\n",
4952                     pr_ap(tp->tcpConnLocalAddress,
4953                     tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
4954                     pr_ap(tp->tcpConnRemAddress,
4955                     tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
4956                     tp->tcpConnEntryInfo.ce_swnd,
4957                     tp->tcpConnEntryInfo.ce_snxt,
4958                     tp->tcpConnEntryInfo.ce_suna,
4959                     tp->tcpConnEntryInfo.ce_rwnd,
4960                     tp->tcpConnEntryInfo.ce_rnxt,
4961                     tp->tcpConnEntryInfo.ce_rack,
4962                     tp->tcpConnEntryInfo.ce_rto,
4963                     tp->tcpConnEntryInfo.ce_mss,
4964                     mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
4965         } else if ((!Uflag) && (!Vflag)) {
4966                 int sq = (int)tp->tcpConnEntryInfo.ce_snxt -
4967                     (int)tp->tcpConnEntryInfo.ce_suna - 1;
4968                 int rq = (int)tp->tcpConnEntryInfo.ce_rnxt -
4969                     (int)tp->tcpConnEntryInfo.ce_rack;
4970 
4971                 (void) printf("%-20s %-20s %5u %6d %5u %6d %s\n",
4972                     pr_ap(tp->tcpConnLocalAddress,
4973                     tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
4974                     pr_ap(tp->tcpConnRemAddress,
4975                     tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
4976                     tp->tcpConnEntryInfo.ce_swnd,
4977                     (sq >= 0) ? sq : 0,
4978                     tp->tcpConnEntryInfo.ce_rwnd,
4979                     (rq >= 0) ? rq : 0,
4980                     mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
4981         } else if (Uflag && Vflag) {
4982                 int i = 0;
4983                 conn_pid_node_t *cpn = cph->cph_cpns;
4984                 proc_info_t *pinfo;
4985 
4986                 do {
4987                         int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
4988                         pinfo = get_proc_info(cpn->cpn_pid);
4989 
4990                         (void) printf("%-20s\n%-20s %7u %08x %08x %7u %08x %08x "
4991                             "%5u %5u %-11s %-8.8s %6u %s\n",
4992                             pr_ap(tp->tcpConnLocalAddress,
4993                             tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
4994                             pr_ap(tp->tcpConnRemAddress,
4995                             tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
4996                             tp->tcpConnEntryInfo.ce_swnd,
4997                             tp->tcpConnEntryInfo.ce_snxt,
4998                             tp->tcpConnEntryInfo.ce_suna,
4999                             tp->tcpConnEntryInfo.ce_rwnd,
5000                             tp->tcpConnEntryInfo.ce_rnxt,
5001                             tp->tcpConnEntryInfo.ce_rack,
5002                             tp->tcpConnEntryInfo.ce_rto,
5003                             tp->tcpConnEntryInfo.ce_mss,
5004                             mitcp_state(tp->tcpConnEntryInfo.ce_state, attr),
5005                             pinfo->pr_user, pid, pinfo->pr_psargs);
5006                         i++; cpn++;
5007                 } while (i < cph->cph_pn_cnt);
5008         } else if (Uflag && (!Vflag)) {
5009                 int sq = (int)tp->tcpConnEntryInfo.ce_snxt -
5010                     (int)tp->tcpConnEntryInfo.ce_suna - 1;
5011                 int rq = (int)tp->tcpConnEntryInfo.ce_rnxt -
5012                    (int)tp->tcpConnEntryInfo.ce_rack;
5013                 int i = 0;
5014                 conn_pid_node_t *cpn = cph->cph_cpns;
5015                 proc_info_t *pinfo;
5016 
5017                 do {
5018                         int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
5019                         pinfo = get_proc_info(cpn->cpn_pid);
5020 
5021                         (void) printf("%-20s %-20s %-8.8s %6u %-13.13s %7u %6d %7u %6d %s\n",
5022                             pr_ap(tp->tcpConnLocalAddress,
5023                             tp->tcpConnLocalPort, "tcp", lname, sizeof (lname)),
5024                             pr_ap(tp->tcpConnRemAddress,
5025                             tp->tcpConnRemPort, "tcp", fname, sizeof (fname)),
5026                             pinfo->pr_user, pid, pinfo->pr_fname,
5027                             tp->tcpConnEntryInfo.ce_swnd,
5028                             (sq >= 0) ? sq : 0,
5029                             tp->tcpConnEntryInfo.ce_rwnd,
5030                             (rq >= 0) ? rq : 0,
5031                             mitcp_state(tp->tcpConnEntryInfo.ce_state, attr));
5032 
5033                         i++; cpn++;
5034                 } while (i < cph->cph_pn_cnt);
5035         }
5036 
5037         print_transport_label(attr);
5038 
5039         return (B_FALSE);
5040 }
5041 
5042 static boolean_t
5043 tcp_report_item_v6(const mib2_tcp6ConnEntry_t *tp6,
5044     conn_pid_node_list_hdr_t *cph, boolean_t first,
5045     const mib2_transportMLPEntry_t *attr)
5046 {
5047         /*
5048          * lname and fname below are for the hostname as well as the portname
5049          * There is no limit on portname length so we assume MAXHOSTNAMELEN
5050          * as the limit
5051          */
5052         char    lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5053         char    fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5054         char    ifname[LIFNAMSIZ + 1];
5055         char    *ifnamep;
5056 
5057         if (!(Aflag || tp6->tcp6ConnEntryInfo.ce_state >= TCPS_ESTABLISHED))
5058                 return (first); /* Nothing to print */
5059 
5060         if (first) {
5061                 (void) printf(tcp_hdr_v6);
5062                 if (Uflag)
5063                         (void) printf(Vflag ? tcp_hdr_v6_pid_verbose :
5064                                 tcp_hdr_v6_pid);
5065                 else
5066                         (void) printf(Vflag ? tcp_hdr_v6_verbose :
5067                                 tcp_hdr_v6_normal);
5068         }
5069 
5070         ifnamep = (tp6->tcp6ConnIfIndex != 0) ?
5071             if_indextoname(tp6->tcp6ConnIfIndex, ifname) : NULL;
5072         if (ifnamep == NULL)
5073                 ifnamep = "";
5074 
5075         if ((!Uflag) && Vflag) {
5076                 (void) printf("%-33s\n%-33s %5u %08x %08x %5u %08x %08x "
5077                     "%5u %5u %-11s %s\n",
5078                     pr_ap6(&tp6->tcp6ConnLocalAddress,
5079                     tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5080                     pr_ap6(&tp6->tcp6ConnRemAddress,
5081                     tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5082                     tp6->tcp6ConnEntryInfo.ce_swnd,
5083                     tp6->tcp6ConnEntryInfo.ce_snxt,
5084                     tp6->tcp6ConnEntryInfo.ce_suna,
5085                     tp6->tcp6ConnEntryInfo.ce_rwnd,
5086                     tp6->tcp6ConnEntryInfo.ce_rnxt,
5087                     tp6->tcp6ConnEntryInfo.ce_rack,
5088                     tp6->tcp6ConnEntryInfo.ce_rto,
5089                     tp6->tcp6ConnEntryInfo.ce_mss,
5090                     mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5091                     ifnamep);
5092         } else if ((!Uflag) && (!Vflag)) {
5093                 int sq = (int)tp6->tcp6ConnEntryInfo.ce_snxt -
5094                     (int)tp6->tcp6ConnEntryInfo.ce_suna - 1;
5095                 int rq = (int)tp6->tcp6ConnEntryInfo.ce_rnxt -
5096                     (int)tp6->tcp6ConnEntryInfo.ce_rack;
5097 
5098                 (void) printf("%-33s %-33s %5u %6d %5u %6d %-11s %s\n",
5099                     pr_ap6(&tp6->tcp6ConnLocalAddress,
5100                     tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5101                     pr_ap6(&tp6->tcp6ConnRemAddress,
5102                     tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5103                     tp6->tcp6ConnEntryInfo.ce_swnd,
5104                     (sq >= 0) ? sq : 0,
5105                     tp6->tcp6ConnEntryInfo.ce_rwnd,
5106                     (rq >= 0) ? rq : 0,
5107                     mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5108                     ifnamep);
5109         } else if (Uflag && Vflag) {
5110                 int i = 0;
5111                 conn_pid_node_t *cpn = cph->cph_cpns;
5112                 proc_info_t *pinfo;
5113 
5114                 do {
5115                         int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
5116                         pinfo = get_proc_info(cpn->cpn_pid);
5117 
5118                         (void) printf("%-33s\n%-33s %7u %08x %08x %7u %08x %08x "
5119                             "%5u %5u %-11s %-5.5s %-8.8s %6u %s\n",
5120                             pr_ap6(&tp6->tcp6ConnLocalAddress,
5121                             tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5122                             pr_ap6(&tp6->tcp6ConnRemAddress,
5123                             tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5124                             tp6->tcp6ConnEntryInfo.ce_swnd,
5125                             tp6->tcp6ConnEntryInfo.ce_snxt,
5126                             tp6->tcp6ConnEntryInfo.ce_suna,
5127                             tp6->tcp6ConnEntryInfo.ce_rwnd,
5128                             tp6->tcp6ConnEntryInfo.ce_rnxt,
5129                             tp6->tcp6ConnEntryInfo.ce_rack,
5130                             tp6->tcp6ConnEntryInfo.ce_rto,
5131                             tp6->tcp6ConnEntryInfo.ce_mss,
5132                             mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5133                             ifnamep, pinfo->pr_user, pid, pinfo->pr_psargs);
5134                         i++; cpn++;
5135                 } while (i < cph->cph_pn_cnt);
5136         } else if (Uflag && (!Vflag)) {
5137                 int sq = (int)tp6->tcp6ConnEntryInfo.ce_snxt -
5138                     (int)tp6->tcp6ConnEntryInfo.ce_suna - 1;
5139                 int rq = (int)tp6->tcp6ConnEntryInfo.ce_rnxt -
5140                     (int)tp6->tcp6ConnEntryInfo.ce_rack;
5141                 int i = 0;
5142                 conn_pid_node_t *cpn = cph->cph_cpns;
5143                 proc_info_t *pinfo;
5144 
5145                 do {
5146                         int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
5147                         pinfo = get_proc_info(cpn->cpn_pid);
5148 
5149                         (void) printf("%-33s %-33s %-8.8s %6u %-14.14s %7d %6u %7d %6d %-11s %s\n",
5150                             pr_ap6(&tp6->tcp6ConnLocalAddress,
5151                             tp6->tcp6ConnLocalPort, "tcp", lname, sizeof (lname)),
5152                             pr_ap6(&tp6->tcp6ConnRemAddress,
5153                             tp6->tcp6ConnRemPort, "tcp", fname, sizeof (fname)),
5154                             pinfo->pr_user, pid, pinfo->pr_fname,
5155                             tp6->tcp6ConnEntryInfo.ce_swnd,
5156                             (sq >= 0) ? sq : 0,
5157                             tp6->tcp6ConnEntryInfo.ce_rwnd,
5158                             (rq >= 0) ? rq : 0,
5159                             mitcp_state(tp6->tcp6ConnEntryInfo.ce_state, attr),
5160                             ifnamep);
5161 
5162                         i++; cpn++;
5163                 } while (i < cph->cph_pn_cnt);
5164         }
5165 
5166         print_transport_label(attr);
5167 
5168         return (B_FALSE);
5169 }
5170 
5171 /* ------------------------------- UDP_REPORT------------------------------- */
5172 
5173 static boolean_t udp_report_item_v4(const mib2_udpEntry_t *ude,
5174     conn_pid_node_list_hdr_t *cph, boolean_t first,
5175     const mib2_transportMLPEntry_t *attr);
5176 static boolean_t udp_report_item_v6(const mib2_udp6Entry_t *ude6,
5177     conn_pid_node_list_hdr_t *cph, boolean_t first,
5178     const mib2_transportMLPEntry_t *attr);
5179 
5180 static const char udp_hdr_v4[] =
5181 "   Local Address        Remote Address      State\n"
5182 "-------------------- -------------------- ----------\n";
5183 static const char udp_hdr_v4_pid[] =
5184 "   Local Address        Remote Address      User    Pid   "
5185 "   Command       State\n"
5186 "-------------------- -------------------- -------- ------ "
5187 "-------------- ----------\n";
5188 static const char udp_hdr_v4_pid_verbose[] =
5189 "   Local Address        Remote Address      User    Pid     State    "
5190 "   Command\n"
5191 "-------------------- -------------------- -------- ------ ---------- "
5192 "----------------\n";
5193 
5194 static const char udp_hdr_v6[] =
5195 "   Local Address                     Remote Address                 "
5196 "  State      If\n"
5197 "--------------------------------- --------------------------------- "
5198 "---------- -----\n";
5199 static const char udp_hdr_v6_pid[] =
5200 "   Local Address                     Remote Address                 "
5201 "  User    Pid      Command       State      If\n"
5202 "--------------------------------- --------------------------------- "
5203 "-------- ------ -------------- ---------- -----\n";
5204 static const char udp_hdr_v6_pid_verbose[] =
5205 "   Local Address                     Remote Address                 "
5206 "  User    Pid     State      If     Command\n"
5207 "--------------------------------- --------------------------------- "
5208 "-------- ------ ---------- ----- ----------------\n";
5209 
5210 
5211 static void
5212 udp_report(const mib_item_t *item)
5213 {
5214         int                             jtemp = 0;
5215         boolean_t                       print_hdr_once_v4 = B_TRUE;
5216         boolean_t                       print_hdr_once_v6 = B_TRUE;
5217         mib2_udpEntry_t                 *ude;
5218         mib2_udp6Entry_t                *ude6;
5219         mib2_transportMLPEntry_t        **v4_attrs, **v6_attrs;
5220         mib2_transportMLPEntry_t        **v4a, **v6a;
5221         mib2_transportMLPEntry_t        *aptr;
5222         conn_pid_node_list_hdr_t        *cph;
5223 
5224         if (!protocol_selected(IPPROTO_UDP))
5225                 return;
5226 
5227         /*
5228          * Preparation pass: the kernel returns separate entries for UDP
5229          * connection table entries and Multilevel Port attributes.  We loop
5230          * through the attributes first and set up an array for each address
5231          * family.
5232          */
5233         v4_attrs = family_selected(AF_INET) && RSECflag ?
5234             gather_attrs(item, MIB2_UDP, MIB2_UDP_ENTRY, udpEntrySize) : NULL;
5235         v6_attrs = family_selected(AF_INET6) && RSECflag ?
5236             gather_attrs(item, MIB2_UDP6, MIB2_UDP6_ENTRY, udp6EntrySize) :
5237             NULL;
5238 
5239         v4a = v4_attrs;
5240         v6a = v6_attrs;
5241         /* 'for' loop 1: */
5242         for (; item; item = item->next_item) {
5243                 if (Xflag) {
5244                         (void) printf("\n--- Entry %d ---\n", ++jtemp);
5245                         (void) printf("Group = %d, mib_id = %d, "
5246                             "length = %d, valp = 0x%p\n",
5247                             item->group, item->mib_id,
5248                             item->length, item->valp);
5249                 }
5250                 if (!((item->group == MIB2_UDP &&
5251                     item->mib_id == MIB2_UDP_ENTRY) ||
5252                     (item->group == MIB2_UDP6 &&
5253                     item->mib_id == MIB2_UDP6_ENTRY) ||
5254                     (item->group == MIB2_UDP &&
5255                     item->mib_id == EXPER_XPORT_PROC_INFO) ||
5256                     (item->group == MIB2_UDP6 &&
5257                     item->mib_id == EXPER_XPORT_PROC_INFO)))
5258                         continue; /* 'for' loop 1 */
5259 
5260                 if (item->group == MIB2_UDP && !family_selected(AF_INET))
5261                         continue; /* 'for' loop 1 */
5262                 else if (item->group == MIB2_UDP6 && !family_selected(AF_INET6))
5263                         continue; /* 'for' loop 1 */
5264 
5265                 /*      xxx.xxx.xxx.xxx,pppp  sss... */
5266                 if ((!Uflag) && item->group == MIB2_UDP &&
5267                     item->mib_id == MIB2_UDP_ENTRY) {
5268                         for (ude = (mib2_udpEntry_t *)item->valp;
5269                             (char *)ude < (char *)item->valp + item->length;
5270                             /* LINTED: (note 1) */
5271                             ude = (mib2_udpEntry_t *)((char *)ude +
5272                             udpEntrySize)) {
5273                                 aptr = v4a == NULL ? NULL : *v4a++;
5274                                 print_hdr_once_v4 = udp_report_item_v4(ude,
5275                                     NULL, print_hdr_once_v4, aptr);
5276                         }
5277                 } else if ((!Uflag) && item->group == MIB2_UDP6 &&
5278                      item->mib_id == MIB2_UDP6_ENTRY) {
5279                         for (ude6 = (mib2_udp6Entry_t *)item->valp;
5280                             (char *)ude6 < (char *)item->valp + item->length;
5281                             /* LINTED: (note 1) */
5282                             ude6 = (mib2_udp6Entry_t *)((char *)ude6 +
5283                             udp6EntrySize)) {
5284                                 aptr = v6a == NULL ? NULL : *v6a++;
5285                                 print_hdr_once_v6 = udp_report_item_v6(ude6,
5286                                     NULL, print_hdr_once_v6, aptr);
5287                         }
5288                 } else if ((Uflag) && item->group == MIB2_UDP &&
5289                     item->mib_id == EXPER_XPORT_PROC_INFO) {
5290                         for (ude = (mib2_udpEntry_t *)item->valp;
5291                             (char *)ude < (char *)item->valp + item->length;
5292                             /* LINTED: (note 1) */
5293                             ude = (mib2_udpEntry_t *)((char *)cph +
5294                             cph->cph_tot_size)) {
5295                                 aptr = v4a == NULL ? NULL : *v4a++;
5296                                 /* LINTED: (note 1) */
5297                                 cph = (conn_pid_node_list_hdr_t *)
5298                                         ((char *)ude + udpEntrySize);
5299                                 print_hdr_once_v4 = udp_report_item_v4(ude,
5300                                     cph, print_hdr_once_v4, aptr);
5301                         }
5302                 } else if ((Uflag) && item->group == MIB2_UDP6 &&
5303                     item->mib_id == EXPER_XPORT_PROC_INFO) {
5304                         for (ude6 = (mib2_udp6Entry_t *)item->valp;
5305                             (char *)ude6 < (char *)item->valp + item->length;
5306                             /* LINTED: (note 1) */
5307                             ude6 = (mib2_udp6Entry_t *)((char *)cph +
5308                             cph->cph_tot_size)) {
5309                                 aptr = v6a == NULL ? NULL : *v6a++;
5310                                 /* LINTED: (note 1) */
5311                                 cph = (conn_pid_node_list_hdr_t *)
5312                                         ((char *)ude6 + udp6EntrySize);
5313                                 print_hdr_once_v6 = udp_report_item_v6(ude6,
5314                                     cph, print_hdr_once_v6, aptr);
5315                         }
5316                 }
5317         } /* 'for' loop 1 ends */
5318         (void) fflush(stdout);
5319 
5320         if (v4_attrs != NULL)
5321                 free(v4_attrs);
5322         if (v6_attrs != NULL)
5323                 free(v6_attrs);
5324 }
5325 
5326 static boolean_t
5327 udp_report_item_v4(const mib2_udpEntry_t *ude, conn_pid_node_list_hdr_t *cph,
5328     boolean_t first, const mib2_transportMLPEntry_t *attr)
5329 {
5330         char    lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5331                         /* hostname + portname */
5332 
5333         if (!(Aflag || ude->udpEntryInfo.ue_state >= MIB2_UDP_connected))
5334                 return (first); /* Nothing to print */
5335 
5336         if (first) {
5337                 (void) printf(v4compat ? "\nUDP\n" : "\nUDP: IPv4\n");
5338 
5339                 if (Uflag)
5340                         (void) printf(Vflag ? udp_hdr_v4_pid_verbose :
5341                                 udp_hdr_v4_pid);
5342                 else
5343                         (void) printf(udp_hdr_v4);
5344 
5345                 first = B_FALSE;
5346         }
5347 
5348         (void) printf("%-20s %-20s ",
5349             pr_ap(ude->udpLocalAddress, ude->udpLocalPort, "udp",
5350             lname, sizeof (lname)),
5351             ude->udpEntryInfo.ue_state == MIB2_UDP_connected ?
5352             pr_ap(ude->udpEntryInfo.ue_RemoteAddress,
5353             ude->udpEntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
5354             "");
5355         if (!Uflag) {
5356                 (void) printf("%s\n",
5357                     miudp_state(ude->udpEntryInfo.ue_state, attr));
5358         } else {
5359                 int i = 0;
5360                 conn_pid_node_t *cpn = cph->cph_cpns;
5361                 proc_info_t *pinfo;
5362 
5363                 do {
5364                         int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
5365                         pinfo = get_proc_info(cpn->cpn_pid);
5366                         (void) printf("%-8.8s %6u ", pinfo->pr_user, pid);
5367 
5368                         if (Vflag) {
5369                                 (void) printf("%-10.10s %s\n",
5370                                     miudp_state(ude->udpEntryInfo.ue_state,
5371                                     attr),
5372                                     pinfo->pr_psargs);
5373                         } else {
5374                                 (void) printf("%-14.14s %s\n", pinfo->pr_fname,
5375                                   miudp_state(ude->udpEntryInfo.ue_state,
5376                                   attr));
5377                         }
5378                         i++; cpn++;
5379                 } while (i < cph->cph_pn_cnt);
5380         }
5381 
5382         print_transport_label(attr);
5383 
5384         return (first);
5385 }
5386 
5387 static boolean_t
5388 udp_report_item_v6(const mib2_udp6Entry_t *ude6, conn_pid_node_list_hdr_t *cph,
5389     boolean_t first, const mib2_transportMLPEntry_t *attr)
5390 {
5391         char    lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5392                         /* hostname + portname */
5393         char    ifname[LIFNAMSIZ + 1];
5394         const char *ifnamep;
5395 
5396         if (!(Aflag || ude6->udp6EntryInfo.ue_state >= MIB2_UDP_connected))
5397                 return (first); /* Nothing to print */
5398 
5399         if (first) {
5400                 (void) printf("\nUDP: IPv6\n");
5401 
5402                 if (Uflag)
5403                         (void) printf(Vflag ? udp_hdr_v6_pid_verbose :
5404                                 udp_hdr_v6_pid);
5405                 else
5406                         (void) printf(udp_hdr_v6);
5407 
5408                 first = B_FALSE;
5409         }
5410 
5411         ifnamep = (ude6->udp6IfIndex != 0) ?
5412             if_indextoname(ude6->udp6IfIndex, ifname) : NULL;
5413 
5414         (void) printf("%-33s %-33s ",
5415             pr_ap6(&ude6->udp6LocalAddress,
5416             ude6->udp6LocalPort, "udp", lname, sizeof (lname)),
5417             ude6->udp6EntryInfo.ue_state == MIB2_UDP_connected ?
5418             pr_ap6(&ude6->udp6EntryInfo.ue_RemoteAddress,
5419             ude6->udp6EntryInfo.ue_RemotePort, "udp", lname, sizeof (lname)) :
5420             "");
5421         if (!Uflag) {
5422                 (void) printf("%-10s %s\n",
5423                     miudp_state(ude6->udp6EntryInfo.ue_state, attr),
5424                     ifnamep == NULL ? "" : ifnamep);
5425         } else {
5426                 int i = 0;
5427                 conn_pid_node_t *cpn = cph->cph_cpns;
5428                 proc_info_t *pinfo;
5429 
5430                 do {
5431                         int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
5432                         pinfo = get_proc_info(cpn->cpn_pid);
5433                         (void) printf("%-8.8s %6u ", pinfo->pr_user, pid);
5434 
5435                         if (Vflag) {
5436                                 (void) printf("%-10.10s %-5.5s %s\n",
5437                                     miudp_state(ude6->udp6EntryInfo.ue_state,
5438                                     attr),
5439                                     ifnamep == NULL ? "" : ifnamep,
5440                                     pinfo->pr_psargs);
5441                         } else {
5442                                 (void) printf("%-14.14s %-10.10s %s\n",
5443                                     pinfo->pr_fname,
5444                                     miudp_state(ude6->udp6EntryInfo.ue_state,
5445                                     attr),
5446                                     ifnamep == NULL ? "" : ifnamep);
5447                         }
5448                         i++; cpn++;
5449                 } while (i < cph->cph_pn_cnt);
5450         }
5451 
5452         print_transport_label(attr);
5453 
5454         return (first);
5455 }
5456 
5457 /* ------------------------------ SCTP_REPORT------------------------------- */
5458 
5459 static const char sctp_hdr[] =
5460 "\nSCTP:";
5461 static const char sctp_hdr_normal[] =
5462 "        Local Address                   Remote Address          "
5463 "Swind  Send-Q Rwind  Recv-Q StrsI/O  State\n"
5464 "------------------------------- ------------------------------- "
5465 "------ ------ ------ ------ ------- -----------";
5466 static const char sctp_hdr_pid[] =
5467 "        Local Address                   Remote Address          "
5468 "Swind  Send-Q Rwind  Recv-Q StrsI/O   User    Pid      Command      State\n"
5469 "------------------------------- ------------------------------- ------ "
5470 "------ ------ ------ ------- -------- ------ -------------- -----------";
5471 static const char sctp_hdr_pid_verbose[] =
5472 "        Local Address                   Remote Address          "
5473 "Swind  Send-Q Rwind  Recv-Q StrsI/O   User    Pid    State         Command\n"
5474 "------------------------------- ------------------------------- ------ "
5475 "------ ------ ------ ------- -------- ------ ----------- --------------";
5476 
5477 static const char *
5478 nssctp_state(int state, const mib2_transportMLPEntry_t *attr)
5479 {
5480         static char sctpsbuf[50];
5481         const char *cp;
5482 
5483         switch (state) {
5484         case MIB2_SCTP_closed:
5485                 cp = "CLOSED";
5486                 break;
5487         case MIB2_SCTP_cookieWait:
5488                 cp = "COOKIE_WAIT";
5489                 break;
5490         case MIB2_SCTP_cookieEchoed:
5491                 cp = "COOKIE_ECHOED";
5492                 break;
5493         case MIB2_SCTP_established:
5494                 cp = "ESTABLISHED";
5495                 break;
5496         case MIB2_SCTP_shutdownPending:
5497                 cp = "SHUTDOWN_PENDING";
5498                 break;
5499         case MIB2_SCTP_shutdownSent:
5500                 cp = "SHUTDOWN_SENT";
5501                 break;
5502         case MIB2_SCTP_shutdownReceived:
5503                 cp = "SHUTDOWN_RECEIVED";
5504                 break;
5505         case MIB2_SCTP_shutdownAckSent:
5506                 cp = "SHUTDOWN_ACK_SENT";
5507                 break;
5508         case MIB2_SCTP_listen:
5509                 cp = "LISTEN";
5510                 break;
5511         default:
5512                 (void) snprintf(sctpsbuf, sizeof (sctpsbuf),
5513                     "UNKNOWN STATE(%d)", state);
5514                 cp = sctpsbuf;
5515                 break;
5516         }
5517 
5518         if (RSECflag && attr != NULL && attr->tme_flags != 0) {
5519                 if (cp != sctpsbuf) {
5520                         (void) strlcpy(sctpsbuf, cp, sizeof (sctpsbuf));
5521                         cp = sctpsbuf;
5522                 }
5523                 if (attr->tme_flags & MIB2_TMEF_PRIVATE)
5524                         (void) strlcat(sctpsbuf, " P", sizeof (sctpsbuf));
5525                 if (attr->tme_flags & MIB2_TMEF_SHARED)
5526                         (void) strlcat(sctpsbuf, " S", sizeof (sctpsbuf));
5527         }
5528 
5529         return (cp);
5530 }
5531 
5532 static const mib2_sctpConnRemoteEntry_t *
5533 sctp_getnext_rem(const mib_item_t **itemp,
5534     const mib2_sctpConnRemoteEntry_t *current, uint32_t associd)
5535 {
5536         const mib_item_t *item = *itemp;
5537         const mib2_sctpConnRemoteEntry_t        *sre;
5538 
5539         for (; item != NULL; item = item->next_item, current = NULL) {
5540                 if (!(item->group == MIB2_SCTP &&
5541                     item->mib_id == MIB2_SCTP_CONN_REMOTE)) {
5542                         continue;
5543                 }
5544 
5545                 if (current != NULL) {
5546                         /* LINTED: (note 1) */
5547                         sre = (const mib2_sctpConnRemoteEntry_t *)
5548                             ((const char *)current + sctpRemoteEntrySize);
5549                 } else {
5550                         sre = item->valp;
5551                 }
5552                 for (; (char *)sre < (char *)item->valp + item->length;
5553                     /* LINTED: (note 1) */
5554                     sre = (const mib2_sctpConnRemoteEntry_t *)
5555                     ((const char *)sre + sctpRemoteEntrySize)) {
5556                         if (sre->sctpAssocId != associd) {
5557                                 continue;
5558                         }
5559                         *itemp = item;
5560                         return (sre);
5561                 }
5562         }
5563         *itemp = NULL;
5564         return (NULL);
5565 }
5566 
5567 static const mib2_sctpConnLocalEntry_t *
5568 sctp_getnext_local(const mib_item_t **itemp,
5569     const mib2_sctpConnLocalEntry_t *current, uint32_t associd)
5570 {
5571         const mib_item_t *item = *itemp;
5572         const mib2_sctpConnLocalEntry_t *sle;
5573 
5574         for (; item != NULL; item = item->next_item, current = NULL) {
5575                 if (!(item->group == MIB2_SCTP &&
5576                     item->mib_id == MIB2_SCTP_CONN_LOCAL)) {
5577                         continue;
5578                 }
5579 
5580                 if (current != NULL) {
5581                         /* LINTED: (note 1) */
5582                         sle = (const mib2_sctpConnLocalEntry_t *)
5583                             ((const char *)current + sctpLocalEntrySize);
5584                 } else {
5585                         sle = item->valp;
5586                 }
5587                 for (; (char *)sle < (char *)item->valp + item->length;
5588                     /* LINTED: (note 1) */
5589                     sle = (const mib2_sctpConnLocalEntry_t *)
5590                     ((const char *)sle + sctpLocalEntrySize)) {
5591                         if (sle->sctpAssocId != associd) {
5592                                 continue;
5593                         }
5594                         *itemp = item;
5595                         return (sle);
5596                 }
5597         }
5598         *itemp = NULL;
5599         return (NULL);
5600 }
5601 
5602 static void
5603 sctp_pr_addr(int type, char *name, int namelen, const in6_addr_t *addr,
5604     int port)
5605 {
5606         ipaddr_t        v4addr;
5607         in6_addr_t      v6addr;
5608 
5609         /*
5610          * Address is either a v4 mapped or v6 addr. If
5611          * it's a v4 mapped, convert to v4 before
5612          * displaying.
5613          */
5614         switch (type) {
5615         case MIB2_SCTP_ADDR_V4:
5616                 /* v4 */
5617                 v6addr = *addr;
5618 
5619                 IN6_V4MAPPED_TO_IPADDR(&v6addr, v4addr);
5620                 if (port > 0) {
5621                         (void) pr_ap(v4addr, port, "sctp", name, namelen);
5622                 } else {
5623                         (void) pr_addr(v4addr, name, namelen);
5624                 }
5625                 break;
5626 
5627         case MIB2_SCTP_ADDR_V6:
5628                 /* v6 */
5629                 if (port > 0) {
5630                         (void) pr_ap6(addr, port, "sctp", name, namelen);
5631                 } else {
5632                         (void) pr_addr6(addr, name, namelen);
5633                 }
5634                 break;
5635 
5636         default:
5637                 (void) snprintf(name, namelen, "<unknown addr type>");
5638                 break;
5639         }
5640 }
5641 
5642 static boolean_t
5643 sctp_conn_report_item(const mib_item_t *head, conn_pid_node_list_hdr_t * cph,
5644     boolean_t print_sctp_hdr, const mib2_sctpConnEntry_t *sp,
5645     const mib2_transportMLPEntry_t *attr)
5646 {
5647         char            lname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5648         char            fname[MAXHOSTNAMELEN + MAXHOSTNAMELEN + 1];
5649         const mib2_sctpConnRemoteEntry_t        *sre = NULL;
5650         const mib2_sctpConnLocalEntry_t *sle = NULL;
5651         const mib_item_t *local = head;
5652         const mib_item_t *remote = head;
5653         uint32_t        id = sp->sctpAssocId;
5654         boolean_t       printfirst = B_TRUE;
5655 
5656         if (print_sctp_hdr == B_TRUE) {
5657                 (void) puts(sctp_hdr);
5658                 if (Uflag)
5659                         (void) puts(Vflag? sctp_hdr_pid_verbose: sctp_hdr_pid);
5660                 else
5661                         (void) puts(sctp_hdr_normal);
5662 
5663                 print_sctp_hdr = B_FALSE;
5664         }
5665 
5666         sctp_pr_addr(sp->sctpAssocRemPrimAddrType, fname, sizeof (fname),
5667             &sp->sctpAssocRemPrimAddr, sp->sctpAssocRemPort);
5668         sctp_pr_addr(sp->sctpAssocRemPrimAddrType, lname, sizeof (lname),
5669             &sp->sctpAssocLocPrimAddr, sp->sctpAssocLocalPort);
5670 
5671         if (Uflag) {
5672                 int i = 0;
5673                 conn_pid_node_t *cpn = cph->cph_cpns;
5674                 proc_info_t *pinfo;
5675 
5676                 do {
5677                         int pid = (cph->cph_pn_cnt)?cpn->cpn_pid:0;
5678                         pinfo = get_proc_info(cpn->cpn_pid);
5679                         (void) printf("%-31s %-31s %6u %6d %6u %6d %3d/%-3d %-8.8s %6u ",
5680                             lname, fname,
5681                             sp->sctpConnEntryInfo.ce_swnd,
5682                             sp->sctpConnEntryInfo.ce_sendq,
5683                             sp->sctpConnEntryInfo.ce_rwnd,
5684                             sp->sctpConnEntryInfo.ce_recvq,
5685                             sp->sctpAssocInStreams,
5686                             sp->sctpAssocOutStreams,
5687                             pinfo->pr_user, pid);
5688 
5689                         if (Vflag) {
5690                                 (void) printf("%-11.11s %s\n",
5691                                     nssctp_state(sp->sctpAssocState, attr),
5692                                     pinfo->pr_psargs);
5693                         } else {
5694                                 (void) printf("%-14.14s %s\n",
5695                                     pinfo->pr_fname,
5696                                     nssctp_state(sp->sctpAssocState, attr));
5697                         }
5698 
5699                         i++; cpn++;
5700                 } while (i < cph->cph_pn_cnt);
5701 
5702         } else {
5703 
5704                 (void) printf("%-31s %-31s %6u %6d %6u %6d %3d/%-3d %s\n",
5705                     lname, fname,
5706                     sp->sctpConnEntryInfo.ce_swnd,
5707                     sp->sctpConnEntryInfo.ce_sendq,
5708                     sp->sctpConnEntryInfo.ce_rwnd,
5709                     sp->sctpConnEntryInfo.ce_recvq,
5710                     sp->sctpAssocInStreams, sp->sctpAssocOutStreams,
5711                     nssctp_state(sp->sctpAssocState, attr));
5712         }
5713 
5714         print_transport_label(attr);
5715 
5716         if (!Vflag) {
5717                 return (print_sctp_hdr);
5718         }
5719 
5720         /* Print remote addresses/local addresses on following lines */
5721         while ((sre = sctp_getnext_rem(&remote, sre, id)) != NULL) {
5722                 if (!IN6_ARE_ADDR_EQUAL(&sre->sctpAssocRemAddr,
5723                     &sp->sctpAssocRemPrimAddr)) {
5724                         if (printfirst == B_TRUE) {
5725                                 (void) fputs("\t<Remote: ", stdout);
5726                                 printfirst = B_FALSE;
5727                         } else {
5728                                 (void) fputs(", ", stdout);
5729                         }
5730                         sctp_pr_addr(sre->sctpAssocRemAddrType, fname,
5731                             sizeof (fname), &sre->sctpAssocRemAddr, -1);
5732                         if (sre->sctpAssocRemAddrActive == MIB2_SCTP_ACTIVE) {
5733                                 (void) fputs(fname, stdout);
5734                         } else {
5735                                 (void) printf("(%s)", fname);
5736                         }
5737                 }
5738         }
5739         if (printfirst == B_FALSE) {
5740                 (void) puts(">");
5741                 printfirst = B_TRUE;
5742         }
5743         while ((sle = sctp_getnext_local(&local, sle, id)) != NULL) {
5744                 if (!IN6_ARE_ADDR_EQUAL(&sle->sctpAssocLocalAddr,
5745                     &sp->sctpAssocLocPrimAddr)) {
5746                         if (printfirst == B_TRUE) {
5747                                 (void) fputs("\t<Local: ", stdout);
5748                                 printfirst = B_FALSE;
5749                         } else {
5750                                 (void) fputs(", ", stdout);
5751                         }
5752                         sctp_pr_addr(sle->sctpAssocLocalAddrType, lname,
5753                             sizeof (lname), &sle->sctpAssocLocalAddr, -1);
5754                         (void) fputs(lname, stdout);
5755                 }
5756         }
5757         if (printfirst == B_FALSE) {
5758                 (void) puts(">");
5759         }
5760 
5761         return (print_sctp_hdr);
5762 }
5763 
5764 static void
5765 sctp_report(const mib_item_t *item)
5766 {
5767         const mib_item_t                *head;
5768         const mib2_sctpConnEntry_t      *sp;
5769         boolean_t                       print_sctp_hdr_once = B_TRUE;
5770         mib2_transportMLPEntry_t        **attrs, **aptr;
5771         mib2_transportMLPEntry_t        *attr;
5772         conn_pid_node_list_hdr_t        *cph;
5773 
5774         /*
5775          * Preparation pass: the kernel returns separate entries for SCTP
5776          * connection table entries and Multilevel Port attributes.  We loop
5777          * through the attributes first and set up an array for each address
5778          * family.
5779          */
5780         attrs = RSECflag ?
5781             gather_attrs(item, MIB2_SCTP, MIB2_SCTP_CONN, sctpEntrySize) :
5782             NULL;
5783 
5784         aptr = attrs;
5785         head = item;
5786         for (; item != NULL; item = item->next_item) {
5787 
5788                 if (!((item->group == MIB2_SCTP &&
5789                     item->mib_id == MIB2_SCTP_CONN) ||
5790                     (item->group == MIB2_SCTP &&
5791                     item->mib_id == EXPER_XPORT_PROC_INFO)))
5792                         continue;
5793 
5794                 if ((!Uflag) && item->group == MIB2_SCTP
5795                     && item->mib_id == MIB2_SCTP_CONN) {
5796                         for (sp = item->valp;
5797                             (char *)sp < (char *)item->valp + item->length;
5798                             /* LINTED: (note 1) */
5799                             sp = (mib2_sctpConnEntry_t *)((char *)sp + sctpEntrySize)) {
5800                                 if (!(Aflag ||
5801                                   sp->sctpAssocState >= MIB2_SCTP_established))
5802                                         continue;
5803                                 attr = aptr == NULL ? NULL : *aptr++;
5804                                 print_sctp_hdr_once = sctp_conn_report_item(head, NULL,
5805                                                         print_sctp_hdr_once, sp,
5806                                                         attr);
5807                         }
5808                 } else if ((Uflag) && item->group == MIB2_SCTP &&
5809                     item->mib_id == EXPER_XPORT_PROC_INFO) {
5810                         for (sp = (mib2_sctpConnEntry_t *)item->valp;
5811                             (char *)sp < (char *)item->valp + item->length;
5812                             /* LINTED: (note 1) */
5813                             sp = (mib2_sctpConnEntry_t *)((char *)cph +
5814                             cph->cph_tot_size)) {
5815                                 /* LINTED: (note 1) */
5816                                 cph = (conn_pid_node_list_hdr_t *)
5817                                         ((char *)sp + sctpEntrySize);
5818                                 if (!(Aflag ||
5819                                   sp->sctpAssocState >= MIB2_SCTP_established))
5820                                         continue;
5821                                 attr = aptr == NULL ? NULL : *aptr++;
5822                                 print_sctp_hdr_once =
5823                                     sctp_conn_report_item(head, cph,
5824                                         print_sctp_hdr_once, sp, attr);
5825                         }
5826                 }
5827         }
5828         if (attrs != NULL)
5829                 free(attrs);
5830 }
5831 
5832 static char *
5833 plural(int n)
5834 {
5835         return (n != 1 ? "s" : "");
5836 }
5837 
5838 static char *
5839 pluraly(int n)
5840 {
5841         return (n != 1 ? "ies" : "y");
5842 }
5843 
5844 static char *
5845 plurales(int n)
5846 {
5847         return (n != 1 ? "es" : "");
5848 }
5849 
5850 static char *
5851 pktscale(n)
5852         int n;
5853 {
5854         static char buf[6];
5855         char t;
5856 
5857         if (n < 1024) {
5858                 t = ' ';
5859         } else if (n < 1024 * 1024) {
5860                 t = 'k';
5861                 n /= 1024;
5862         } else if (n < 1024 * 1024 * 1024) {
5863                 t = 'm';
5864                 n /= 1024 * 1024;
5865         } else {
5866                 t = 'g';
5867                 n /= 1024 * 1024 * 1024;
5868         }
5869 
5870         (void) snprintf(buf, sizeof (buf), "%4u%c", n, t);
5871         return (buf);
5872 }
5873 
5874 /* --------------------- mrt_report (netstat -m) -------------------------- */
5875 
5876 static void
5877 mrt_report(mib_item_t *item)
5878 {
5879         int             jtemp = 0;
5880         struct vifctl   *vip;
5881         vifi_t          vifi;
5882         struct mfcctl   *mfccp;
5883         int             numvifs = 0;
5884         int             nmfc = 0;
5885         char            abuf[MAXHOSTNAMELEN + 1];
5886 
5887         if (!(family_selected(AF_INET)))
5888                 return;
5889 
5890         /* 'for' loop 1: */
5891         for (; item; item = item->next_item) {
5892                 if (Xflag) {
5893                         (void) printf("\n--- Entry %d ---\n", ++jtemp);
5894                         (void) printf("Group = %d, mib_id = %d, "
5895                             "length = %d, valp = 0x%p\n",
5896                             item->group, item->mib_id, item->length,
5897                             item->valp);
5898                 }
5899                 if (item->group != EXPER_DVMRP)
5900                         continue; /* 'for' loop 1 */
5901 
5902                 switch (item->mib_id) {
5903 
5904                 case EXPER_DVMRP_VIF:
5905                         if (Xflag)
5906                                 (void) printf("%u records for ipVifTable:\n",
5907                                     item->length/sizeof (struct vifctl));
5908                         if (item->length/sizeof (struct vifctl) == 0) {
5909                                 (void) puts("\nVirtual Interface Table is "
5910                                     "empty");
5911                                 break;
5912                         }
5913 
5914                         (void) puts("\nVirtual Interface Table\n"
5915                             " Vif Threshold Rate_Limit Local-Address"
5916                             "   Remote-Address     Pkt_in   Pkt_out");
5917 
5918                         /* 'for' loop 2: */
5919                         for (vip = (struct vifctl *)item->valp;
5920                             (char *)vip < (char *)item->valp + item->length;
5921                             /* LINTED: (note 1) */
5922                             vip = (struct vifctl *)((char *)vip +
5923                             vifctlSize)) {
5924                                 if (vip->vifc_lcl_addr.s_addr == 0)
5925                                         continue; /* 'for' loop 2 */
5926                                 /* numvifs = vip->vifc_vifi; */
5927 
5928                                 numvifs++;
5929                                 (void) printf("  %2u       %3u       "
5930                                     "%4u %-15.15s",
5931                                     vip->vifc_vifi,
5932                                     vip->vifc_threshold,
5933                                     vip->vifc_rate_limit,
5934                                     pr_addr(vip->vifc_lcl_addr.s_addr,
5935                                     abuf, sizeof (abuf)));
5936                                 (void) printf(" %-15.15s  %8u  %8u\n",
5937                                     (vip->vifc_flags & VIFF_TUNNEL) ?
5938                                     pr_addr(vip->vifc_rmt_addr.s_addr,
5939                                     abuf, sizeof (abuf)) : "",
5940                                     vip->vifc_pkt_in,
5941                                     vip->vifc_pkt_out);
5942                         } /* 'for' loop 2 ends */
5943 
5944                         (void) printf("Numvifs: %d\n", numvifs);
5945                         break;
5946 
5947                 case EXPER_DVMRP_MRT:
5948                         if (Xflag)
5949                                 (void) printf("%u records for ipMfcTable:\n",
5950                                     item->length/sizeof (struct vifctl));
5951                         if (item->length/sizeof (struct vifctl) == 0) {
5952                                 (void) puts("\nMulticast Forwarding Cache is "
5953                                     "empty");
5954                                 break;
5955                         }
5956 
5957                         (void) puts("\nMulticast Forwarding Cache\n"
5958                             "  Origin-Subnet                 Mcastgroup      "
5959                             "# Pkts  In-Vif  Out-vifs/Forw-ttl");
5960 
5961                         for (mfccp = (struct mfcctl *)item->valp;
5962                             (char *)mfccp < (char *)item->valp + item->length;
5963                             /* LINTED: (note 1) */
5964                             mfccp = (struct mfcctl *)((char *)mfccp +
5965                             mfcctlSize)) {
5966 
5967                                 nmfc++;
5968                                 (void) printf("  %-30.15s",
5969                                     pr_addr(mfccp->mfcc_origin.s_addr,
5970                                     abuf, sizeof (abuf)));
5971                                 (void) printf("%-15.15s  %6s  %3u    ",
5972                                     pr_net(mfccp->mfcc_mcastgrp.s_addr,
5973                                     mfccp->mfcc_mcastgrp.s_addr,
5974                                     abuf, sizeof (abuf)),
5975                                     pktscale((int)mfccp->mfcc_pkt_cnt),
5976                                     mfccp->mfcc_parent);
5977 
5978                                 for (vifi = 0; vifi < MAXVIFS; ++vifi) {
5979                                         if (mfccp->mfcc_ttls[vifi]) {
5980                                                 (void) printf("      %u (%u)",
5981                                                     vifi,
5982                                                     mfccp->mfcc_ttls[vifi]);
5983                                         }
5984 
5985                                 }
5986                                 (void) putchar('\n');
5987                         }
5988                         (void) printf("\nTotal no. of entries in cache: %d\n",
5989                             nmfc);
5990                         break;
5991                 }
5992         } /* 'for' loop 1 ends */
5993         (void) putchar('\n');
5994         (void) fflush(stdout);
5995 }
5996 
5997 /*
5998  * Get the stats for the cache named 'name'.  If prefix != 0, then
5999  * interpret the name as a prefix, and sum up stats for all caches
6000  * named 'name*'.
6001  */
6002 static void
6003 kmem_cache_stats(char *title, char *name, int prefix, int64_t *total_bytes)
6004 {
6005         int len;
6006         int alloc;
6007         int64_t total_alloc = 0;
6008         int alloc_fail, total_alloc_fail = 0;
6009         int buf_size = 0;
6010         int buf_avail;
6011         int buf_total;
6012         int buf_max, total_buf_max = 0;
6013         int buf_inuse, total_buf_inuse = 0;
6014         kstat_t *ksp;
6015         char buf[256];
6016 
6017         len = prefix ? strlen(name) : 256;
6018 
6019         /* 'for' loop 1: */
6020         for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
6021 
6022                 if (strcmp(ksp->ks_class, "kmem_cache") != 0)
6023                         continue; /* 'for' loop 1 */
6024 
6025                 /*
6026                  * Hack alert: because of the way streams messages are
6027                  * allocated, every constructed free dblk has an associated
6028                  * mblk.  From the allocator's viewpoint those mblks are
6029                  * allocated (because they haven't been freed), but from
6030                  * our viewpoint they're actually free (because they're
6031                  * not currently in use).  To account for this caching
6032                  * effect we subtract the total constructed free dblks
6033                  * from the total allocated mblks to derive mblks in use.
6034                  */
6035                 if (strcmp(name, "streams_mblk") == 0 &&
6036                     strncmp(ksp->ks_name, "streams_dblk", 12) == 0) {
6037                         (void) safe_kstat_read(kc, ksp, NULL);
6038                         total_buf_inuse -=
6039                             kstat_named_value(ksp, "buf_constructed");
6040                         continue; /* 'for' loop 1 */
6041                 }
6042 
6043                 if (strncmp(ksp->ks_name, name, len) != 0)
6044                         continue; /* 'for' loop 1 */
6045 
6046                 (void) safe_kstat_read(kc, ksp, NULL);
6047 
6048                 alloc           = kstat_named_value(ksp, "alloc");
6049                 alloc_fail      = kstat_named_value(ksp, "alloc_fail");
6050                 buf_size        = kstat_named_value(ksp, "buf_size");
6051                 buf_avail       = kstat_named_value(ksp, "buf_avail");
6052                 buf_total       = kstat_named_value(ksp, "buf_total");
6053                 buf_max         = kstat_named_value(ksp, "buf_max");
6054                 buf_inuse       = buf_total - buf_avail;
6055 
6056                 if (Vflag && prefix) {
6057                         (void) snprintf(buf, sizeof (buf), "%s%s", title,
6058                             ksp->ks_name + len);
6059                         (void) printf("    %-18s %6u %9u %11u %11u\n",
6060                             buf, buf_inuse, buf_max, alloc, alloc_fail);
6061                 }
6062 
6063                 total_alloc             += alloc;
6064                 total_alloc_fail        += alloc_fail;
6065                 total_buf_max           += buf_max;
6066                 total_buf_inuse         += buf_inuse;
6067                 *total_bytes            += (int64_t)buf_inuse * buf_size;
6068         } /* 'for' loop 1 ends */
6069 
6070         if (buf_size == 0) {
6071                 (void) printf("%-22s [couldn't find statistics for %s]\n",
6072                     title, name);
6073                 return;
6074         }
6075 
6076         if (Vflag && prefix)
6077                 (void) snprintf(buf, sizeof (buf), "%s_total", title);
6078         else
6079                 (void) snprintf(buf, sizeof (buf), "%s", title);
6080 
6081         (void) printf("%-22s %6d %9d %11lld %11d\n", buf,
6082             total_buf_inuse, total_buf_max, total_alloc, total_alloc_fail);
6083 }
6084 
6085 static void
6086 m_report(void)
6087 {
6088         int64_t total_bytes = 0;
6089 
6090         (void) puts("streams allocation:");
6091         (void) printf("%63s\n", "cumulative  allocation");
6092         (void) printf("%63s\n",
6093             "current   maximum       total    failures");
6094 
6095         kmem_cache_stats("streams",
6096             "stream_head_cache", 0, &total_bytes);
6097         kmem_cache_stats("queues", "queue_cache", 0, &total_bytes);
6098         kmem_cache_stats("mblk", "streams_mblk", 0, &total_bytes);
6099         kmem_cache_stats("dblk", "streams_dblk", 1, &total_bytes);
6100         kmem_cache_stats("linkblk", "linkinfo_cache", 0, &total_bytes);
6101         kmem_cache_stats("syncq", "syncq_cache", 0, &total_bytes);
6102         kmem_cache_stats("qband", "qband_cache", 0, &total_bytes);
6103 
6104         (void) printf("\n%lld Kbytes allocated for streams data\n",
6105             total_bytes / 1024);
6106 
6107         (void) putchar('\n');
6108         (void) fflush(stdout);
6109 }
6110 
6111 /* --------------------------------- */
6112 
6113 /*
6114  * Print an IPv4 address. Remove the matching part of the domain name
6115  * from the returned name.
6116  */
6117 static char *
6118 pr_addr(uint_t addr, char *dst, uint_t dstlen)
6119 {
6120         char                    *cp;
6121         struct hostent          *hp = NULL;
6122         static char             domain[MAXHOSTNAMELEN + 1];
6123         static boolean_t        first = B_TRUE;
6124         int                     error_num;
6125 
6126         if (first) {
6127                 first = B_FALSE;
6128                 if (sysinfo(SI_HOSTNAME, domain, MAXHOSTNAMELEN) != -1 &&
6129                     (cp = strchr(domain, '.'))) {
6130                         (void) strncpy(domain, cp + 1, sizeof (domain));
6131                 } else
6132                         domain[0] = 0;
6133         }
6134         cp = NULL;
6135         if (!Nflag) {
6136                 hp = getipnodebyaddr((char *)&addr, sizeof (uint_t), AF_INET,
6137                     &error_num);
6138                 if (hp) {
6139                         if ((cp = strchr(hp->h_name, '.')) != NULL &&
6140                             strcasecmp(cp + 1, domain) == 0)
6141                                 *cp = 0;
6142                         cp = hp->h_name;
6143                 }
6144         }
6145         if (cp != NULL) {
6146                 (void) strncpy(dst, cp, dstlen);
6147                 dst[dstlen - 1] = 0;
6148         } else {
6149                 (void) inet_ntop(AF_INET, (char *)&addr, dst, dstlen);
6150         }
6151         if (hp != NULL)
6152                 freehostent(hp);
6153         return (dst);
6154 }
6155 
6156 /*
6157  * Print a non-zero IPv4 address.  Print "    --" if the address is zero.
6158  */
6159 static char *
6160 pr_addrnz(ipaddr_t addr, char *dst, uint_t dstlen)
6161 {
6162         if (addr == INADDR_ANY) {
6163                 (void) strlcpy(dst, "    --", dstlen);
6164                 return (dst);
6165         }
6166         return (pr_addr(addr, dst, dstlen));
6167 }
6168 
6169 /*
6170  * Print an IPv6 address. Remove the matching part of the domain name
6171  * from the returned name.
6172  */
6173 static char *
6174 pr_addr6(const struct in6_addr *addr, char *dst, uint_t dstlen)
6175 {
6176         char                    *cp;
6177         struct hostent          *hp = NULL;
6178         static char             domain[MAXHOSTNAMELEN + 1];
6179         static boolean_t        first = B_TRUE;
6180         int                     error_num;
6181 
6182         if (first) {
6183                 first = B_FALSE;
6184                 if (sysinfo(SI_HOSTNAME, domain, MAXHOSTNAMELEN) != -1 &&
6185                     (cp = strchr(domain, '.'))) {
6186                         (void) strncpy(domain, cp + 1, sizeof (domain));
6187                 } else
6188                         domain[0] = 0;
6189         }
6190         cp = NULL;
6191         if (!Nflag) {
6192                 hp = getipnodebyaddr((char *)addr,
6193                     sizeof (struct in6_addr), AF_INET6, &error_num);
6194                 if (hp) {
6195                         if ((cp = strchr(hp->h_name, '.')) != NULL &&
6196                             strcasecmp(cp + 1, domain) == 0)
6197                                 *cp = 0;
6198                         cp = hp->h_name;
6199                 }
6200         }
6201         if (cp != NULL) {
6202                 (void) strncpy(dst, cp, dstlen);
6203                 dst[dstlen - 1] = 0;
6204         } else {
6205                 (void) inet_ntop(AF_INET6, (void *)addr, dst, dstlen);
6206         }
6207         if (hp != NULL)
6208                 freehostent(hp);
6209         return (dst);
6210 }
6211 
6212 /* For IPv4 masks */
6213 static char *
6214 pr_mask(uint_t addr, char *dst, uint_t dstlen)
6215 {
6216         uint8_t *ip_addr = (uint8_t *)&addr;
6217 
6218         (void) snprintf(dst, dstlen, "%d.%d.%d.%d",
6219             ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3]);
6220         return (dst);
6221 }
6222 
6223 /*
6224  * For ipv6 masks format is : dest/mask
6225  * Does not print /128 to save space in printout. H flag carries this notion.
6226  */
6227 static char *
6228 pr_prefix6(const struct in6_addr *addr, uint_t prefixlen, char *dst,
6229     uint_t dstlen)
6230 {
6231         char *cp;
6232 
6233         if (IN6_IS_ADDR_UNSPECIFIED(addr) && prefixlen == 0) {
6234                 (void) strncpy(dst, "default", dstlen);
6235                 dst[dstlen - 1] = 0;
6236                 return (dst);
6237         }
6238 
6239         (void) pr_addr6(addr, dst, dstlen);
6240         if (prefixlen != IPV6_ABITS) {
6241                 /* How much room is left? */
6242                 cp = strchr(dst, '\0');
6243                 if (dst + dstlen > cp) {
6244                         dstlen -= (cp - dst);
6245                         (void) snprintf(cp, dstlen, "/%d", prefixlen);
6246                 }
6247         }
6248         return (dst);
6249 }
6250 
6251 /* Print IPv4 address and port */
6252 static char *
6253 pr_ap(uint_t addr, uint_t port, char *proto,
6254     char *dst, uint_t dstlen)
6255 {
6256         char *cp;
6257 
6258         if (addr == INADDR_ANY) {
6259                 (void) strncpy(dst, "      *", dstlen);
6260                 dst[dstlen - 1] = 0;
6261         } else {
6262                 (void) pr_addr(addr, dst, dstlen);
6263         }
6264         /* How much room is left? */
6265         cp = strchr(dst, '\0');
6266         if (dst + dstlen > cp + 1) {
6267                 *cp++ = '.';
6268                 dstlen -= (cp - dst);
6269                 dstlen--;
6270                 (void) portname(port, proto, cp, dstlen);
6271         }
6272         return (dst);
6273 }
6274 
6275 /* Print IPv6 address and port */
6276 static char *
6277 pr_ap6(const in6_addr_t *addr, uint_t port, char *proto,
6278     char *dst, uint_t dstlen)
6279 {
6280         char *cp;
6281 
6282         if (IN6_IS_ADDR_UNSPECIFIED(addr)) {
6283                 (void) strncpy(dst, "      *", dstlen);
6284                 dst[dstlen - 1] = 0;
6285         } else {
6286                 (void) pr_addr6(addr, dst, dstlen);
6287         }
6288         /* How much room is left? */
6289         cp = strchr(dst, '\0');
6290         if (dst + dstlen + 1 > cp) {
6291                 *cp++ = '.';
6292                 dstlen -= (cp - dst);
6293                 dstlen--;
6294                 (void) portname(port, proto, cp, dstlen);
6295         }
6296         return (dst);
6297 }
6298 
6299 /*
6300  * Return the name of the network whose address is given. The address is
6301  * assumed to be that of a net or subnet, not a host.
6302  */
6303 static char *
6304 pr_net(uint_t addr, uint_t mask, char *dst, uint_t dstlen)
6305 {
6306         char            *cp = NULL;
6307         struct netent   *np = NULL;
6308         struct hostent  *hp = NULL;
6309         uint_t          net;
6310         int             subnetshift;
6311         int             error_num;
6312 
6313         if (addr == INADDR_ANY && mask == INADDR_ANY) {
6314                 (void) strncpy(dst, "default", dstlen);
6315                 dst[dstlen - 1] = 0;
6316                 return (dst);
6317         }
6318 
6319         if (!Nflag && addr) {
6320                 if (mask == 0) {
6321                         if (IN_CLASSA(addr)) {
6322                                 mask = (uint_t)IN_CLASSA_NET;
6323                                 subnetshift = 8;
6324                         } else if (IN_CLASSB(addr)) {
6325                                 mask = (uint_t)IN_CLASSB_NET;
6326                                 subnetshift = 8;
6327                         } else {
6328                                 mask = (uint_t)IN_CLASSC_NET;
6329                                 subnetshift = 4;
6330                         }
6331                         /*
6332                          * If there are more bits than the standard mask
6333                          * would suggest, subnets must be in use. Guess at
6334                          * the subnet mask, assuming reasonable width subnet
6335                          * fields.
6336                          */
6337                         while (addr & ~mask)
6338                                 /* compiler doesn't sign extend! */
6339                                 mask = (mask | ((int)mask >> subnetshift));
6340                 }
6341                 net = addr & mask;
6342                 while ((mask & 1) == 0)
6343                         mask >>= 1, net >>= 1;
6344                 np = getnetbyaddr(net, AF_INET);
6345                 if (np && np->n_net == net)
6346                         cp = np->n_name;
6347                 else {
6348                         /*
6349                          * Look for subnets in hosts map.
6350                          */
6351                         hp = getipnodebyaddr((char *)&addr, sizeof (uint_t),
6352                             AF_INET, &error_num);
6353                         if (hp)
6354                                 cp = hp->h_name;
6355                 }
6356         }
6357         if (cp != NULL) {
6358                 (void) strncpy(dst, cp, dstlen);
6359                 dst[dstlen - 1] = 0;
6360         } else {
6361                 (void) inet_ntop(AF_INET, (char *)&addr, dst, dstlen);
6362         }
6363         if (hp != NULL)
6364                 freehostent(hp);
6365         return (dst);
6366 }
6367 
6368 /*
6369  * Return the name of the network whose address is given.
6370  * The address is assumed to be a host address.
6371  */
6372 static char *
6373 pr_netaddr(uint_t addr, uint_t mask, char *dst, uint_t dstlen)
6374 {
6375         char            *cp = NULL;
6376         struct netent   *np = NULL;
6377         struct hostent  *hp = NULL;
6378         uint_t          net;
6379         uint_t          netshifted;
6380         int             subnetshift;
6381         struct in_addr in;
6382         int             error_num;
6383         uint_t          nbo_addr = addr;        /* network byte order */
6384 
6385         addr = ntohl(addr);
6386         mask = ntohl(mask);
6387         if (addr == INADDR_ANY && mask == INADDR_ANY) {
6388                 (void) strncpy(dst, "default", dstlen);
6389                 dst[dstlen - 1] = 0;
6390                 return (dst);
6391         }
6392 
6393         /* Figure out network portion of address (with host portion = 0) */
6394         if (addr) {
6395                 /* Try figuring out mask if unknown (all 0s). */
6396                 if (mask == 0) {
6397                         if (IN_CLASSA(addr)) {
6398                                 mask = (uint_t)IN_CLASSA_NET;
6399                                 subnetshift = 8;
6400                         } else if (IN_CLASSB(addr)) {
6401                                 mask = (uint_t)IN_CLASSB_NET;
6402                                 subnetshift = 8;
6403                         } else {
6404                                 mask = (uint_t)IN_CLASSC_NET;
6405                                 subnetshift = 4;
6406                         }
6407                         /*
6408                          * If there are more bits than the standard mask
6409                          * would suggest, subnets must be in use. Guess at
6410                          * the subnet mask, assuming reasonable width subnet
6411                          * fields.
6412                          */
6413                         while (addr & ~mask)
6414                                 /* compiler doesn't sign extend! */
6415                                 mask = (mask | ((int)mask >> subnetshift));
6416                 }
6417                 net = netshifted = addr & mask;
6418                 while ((mask & 1) == 0)
6419                         mask >>= 1, netshifted >>= 1;
6420         }
6421         else
6422                 net = netshifted = 0;
6423 
6424         /* Try looking up name unless -n was specified. */
6425         if (!Nflag) {
6426                 np = getnetbyaddr(netshifted, AF_INET);
6427                 if (np && np->n_net == netshifted)
6428                         cp = np->n_name;
6429                 else {
6430                         /*
6431                          * Look for subnets in hosts map.
6432                          */
6433                         hp = getipnodebyaddr((char *)&nbo_addr, sizeof (uint_t),
6434                             AF_INET, &error_num);
6435                         if (hp)
6436                                 cp = hp->h_name;
6437                 }
6438 
6439                 if (cp != NULL) {
6440                         (void) strncpy(dst, cp, dstlen);
6441                         dst[dstlen - 1] = 0;
6442                         if (hp != NULL)
6443                                 freehostent(hp);
6444                         return (dst);
6445                 }
6446                 /*
6447                  * No name found for net: fallthru and return in decimal
6448                  * dot notation.
6449                  */
6450         }
6451 
6452         in.s_addr = htonl(net);
6453         (void) inet_ntop(AF_INET, (char *)&in, dst, dstlen);
6454         if (hp != NULL)
6455                 freehostent(hp);
6456         return (dst);
6457 }
6458 
6459 /*
6460  * Return the filter mode as a string:
6461  *      1 => "INCLUDE"
6462  *      2 => "EXCLUDE"
6463  *      otherwise "<unknown>"
6464  */
6465 static char *
6466 fmodestr(uint_t fmode)
6467 {
6468         switch (fmode) {
6469         case 1:
6470                 return ("INCLUDE");
6471         case 2:
6472                 return ("EXCLUDE");
6473         default:
6474                 return ("<unknown>");
6475         }
6476 }
6477 
6478 #define MAX_STRING_SIZE 256
6479 
6480 static const char *
6481 pr_secattr(const sec_attr_list_t *attrs)
6482 {
6483         int i;
6484         char buf[MAX_STRING_SIZE + 1], *cp;
6485         static char *sbuf;
6486         static size_t sbuf_len;
6487         struct rtsa_s rtsa;
6488         const sec_attr_list_t *aptr;
6489 
6490         if (!RSECflag || attrs == NULL)
6491                 return ("");
6492 
6493         for (aptr = attrs, i = 1; aptr != NULL; aptr = aptr->sal_next)
6494                 i += MAX_STRING_SIZE;
6495         if (i > sbuf_len) {
6496                 cp = realloc(sbuf, i);
6497                 if (cp == NULL) {
6498                         perror("realloc security attribute buffer");
6499                         return ("");
6500                 }
6501                 sbuf_len = i;
6502                 sbuf = cp;
6503         }
6504 
6505         cp = sbuf;
6506         while (attrs != NULL) {
6507                 const mib2_ipAttributeEntry_t *iae = attrs->sal_attr;
6508 
6509                 /* note: effectively hard-coded in rtsa_keyword */
6510                 rtsa.rtsa_mask = RTSA_CIPSO | RTSA_SLRANGE | RTSA_DOI;
6511                 rtsa.rtsa_slrange = iae->iae_slrange;
6512                 rtsa.rtsa_doi = iae->iae_doi;
6513 
6514                 (void) snprintf(cp, MAX_STRING_SIZE,
6515                     "<%s>%s ", rtsa_to_str(&rtsa, buf, sizeof (buf)),
6516                     attrs->sal_next == NULL ? "" : ",");
6517                 cp += strlen(cp);
6518                 attrs = attrs->sal_next;
6519         }
6520         *cp = '\0';
6521 
6522         return (sbuf);
6523 }
6524 
6525 /*
6526  * Pretty print a port number. If the Nflag was
6527  * specified, use numbers instead of names.
6528  */
6529 static char *
6530 portname(uint_t port, char *proto, char *dst, uint_t dstlen)
6531 {
6532         struct servent *sp = NULL;
6533 
6534         if (!Nflag && port)
6535                 sp = getservbyport(htons(port), proto);
6536         if (sp || port == 0)
6537                 (void) snprintf(dst, dstlen, "%.*s", MAXHOSTNAMELEN,
6538                     sp ? sp->s_name : "*");
6539         else
6540                 (void) snprintf(dst, dstlen, "%d", port);
6541         dst[dstlen - 1] = 0;
6542         return (dst);
6543 }
6544 
6545 /*PRINTFLIKE2*/
6546 void
6547 fail(int do_perror, char *message, ...)
6548 {
6549         va_list args;
6550 
6551         va_start(args, message);
6552         (void) fputs("netstat: ", stderr);
6553         (void) vfprintf(stderr, message, args);
6554         va_end(args);
6555         if (do_perror)
6556                 (void) fprintf(stderr, ": %s", strerror(errno));
6557         (void) fputc('\n', stderr);
6558         exit(2);
6559 }
6560 
6561 /*
6562  * Return value of named statistic for given kstat_named kstat;
6563  * return 0LL if named statistic is not in list (use "ll" as a
6564  * type qualifier when printing 64-bit int's with printf() )
6565  */
6566 static uint64_t
6567 kstat_named_value(kstat_t *ksp, char *name)
6568 {
6569         kstat_named_t *knp;
6570         uint64_t value;
6571 
6572         if (ksp == NULL)
6573                 return (0LL);
6574 
6575         knp = kstat_data_lookup(ksp, name);
6576         if (knp == NULL)
6577                 return (0LL);
6578 
6579         switch (knp->data_type) {
6580         case KSTAT_DATA_INT32:
6581         case KSTAT_DATA_UINT32:
6582                 value = (uint64_t)(knp->value.ui32);
6583                 break;
6584         case KSTAT_DATA_INT64:
6585         case KSTAT_DATA_UINT64:
6586                 value = knp->value.ui64;
6587                 break;
6588         default:
6589                 value = 0LL;
6590                 break;
6591         }
6592 
6593         return (value);
6594 }
6595 
6596 kid_t
6597 safe_kstat_read(kstat_ctl_t *kc, kstat_t *ksp, void *data)
6598 {
6599         kid_t kstat_chain_id = kstat_read(kc, ksp, data);
6600 
6601         if (kstat_chain_id == -1)
6602                 fail(1, "kstat_read(%p, '%s') failed", (void *)kc,
6603                     ksp->ks_name);
6604         return (kstat_chain_id);
6605 }
6606 
6607 /*
6608  * Parse a list of IRE flag characters into a bit field.
6609  */
6610 static uint_t
6611 flag_bits(const char *arg)
6612 {
6613         const char *cp;
6614         uint_t val;
6615 
6616         if (*arg == '\0')
6617                 fatal(1, "missing flag list\n");
6618 
6619         val = 0;
6620         while (*arg != '\0') {
6621                 if ((cp = strchr(flag_list, *arg)) == NULL)
6622                         fatal(1, "%c: illegal flag\n", *arg);
6623                 val |= 1 << (cp - flag_list);
6624                 arg++;
6625         }
6626         return (val);
6627 }
6628 
6629 /*
6630  * Handle -f argument.  Validate input format, sort by keyword, and
6631  * save off digested results.
6632  */
6633 static void
6634 process_filter(char *arg)
6635 {
6636         int idx;
6637         int klen = 0;
6638         char *cp, *cp2;
6639         int val;
6640         filter_t *newf;
6641         struct hostent *hp;
6642         int error_num;
6643         uint8_t *ucp;
6644         int maxv;
6645 
6646         /* Look up the keyword first */
6647         if (strchr(arg, ':') == NULL) {
6648                 idx = FK_AF;
6649         } else {
6650                 for (idx = 0; idx < NFILTERKEYS; idx++) {
6651                         klen = strlen(filter_keys[idx]);
6652                         if (strncmp(filter_keys[idx], arg, klen) == 0 &&
6653                             arg[klen] == ':')
6654                                 break;
6655                 }
6656                 if (idx >= NFILTERKEYS)
6657                         fatal(1, "%s: unknown filter keyword\n", arg);
6658 
6659                 /* Advance past keyword and separator. */
6660                 arg += klen + 1;
6661         }
6662 
6663         if ((newf = malloc(sizeof (*newf))) == NULL) {
6664                 perror("filter");
6665                 exit(1);
6666         }
6667         switch (idx) {
6668         case FK_AF:
6669                 if (strcmp(arg, "inet") == 0) {
6670                         newf->u.f_family = AF_INET;
6671                 } else if (strcmp(arg, "inet6") == 0) {
6672                         newf->u.f_family = AF_INET6;
6673                 } else if (strcmp(arg, "unix") == 0) {
6674                         newf->u.f_family = AF_UNIX;
6675                 } else {
6676                         newf->u.f_family = strtol(arg, &cp, 0);
6677                         if (arg == cp || *cp != '\0')
6678                                 fatal(1, "%s: unknown address family.\n", arg);
6679                 }
6680                 break;
6681 
6682         case FK_OUTIF:
6683                 if (strcmp(arg, "none") == 0) {
6684                         newf->u.f_ifname = NULL;
6685                         break;
6686                 }
6687                 if (strcmp(arg, "any") == 0) {
6688                         newf->u.f_ifname = "";
6689                         break;
6690                 }
6691                 val = strtol(arg, &cp, 0);
6692                 if (val <= 0 || arg == cp || cp[0] != '\0') {
6693                         if ((val = if_nametoindex(arg)) == 0) {
6694                                 perror(arg);
6695                                 exit(1);
6696                         }
6697                 }
6698                 newf->u.f_ifname = arg;
6699                 break;
6700 
6701         case FK_DST:
6702                 V4MASK_TO_V6(IP_HOST_MASK, newf->u.a.f_mask);
6703                 if (strcmp(arg, "any") == 0) {
6704                         /* Special semantics; any address *but* zero */
6705                         newf->u.a.f_address = NULL;
6706                         (void) memset(&newf->u.a.f_mask, 0,
6707                             sizeof (newf->u.a.f_mask));
6708                         break;
6709                 }
6710                 if (strcmp(arg, "none") == 0) {
6711                         newf->u.a.f_address = NULL;
6712                         break;
6713                 }
6714                 if ((cp = strrchr(arg, '/')) != NULL)
6715                         *cp++ = '\0';
6716                 hp = getipnodebyname(arg, AF_INET6, AI_V4MAPPED|AI_ALL,
6717                     &error_num);
6718                 if (hp == NULL)
6719                         fatal(1, "%s: invalid or unknown host address\n", arg);
6720                 newf->u.a.f_address = hp;
6721                 if (cp == NULL) {
6722                         V4MASK_TO_V6(IP_HOST_MASK, newf->u.a.f_mask);
6723                 } else {
6724                         val = strtol(cp, &cp2, 0);
6725                         if (cp != cp2 && cp2[0] == '\0') {
6726                                 /*
6727                                  * If decode as "/n" works, then translate
6728                                  * into a mask.
6729                                  */
6730                                 if (hp->h_addr_list[0] != NULL &&
6731                                     /* LINTED: (note 1) */
6732                                     IN6_IS_ADDR_V4MAPPED((in6_addr_t *)
6733                                     hp->h_addr_list[0])) {
6734                                         maxv = IP_ABITS;
6735                                 } else {
6736                                         maxv = IPV6_ABITS;
6737                                 }
6738                                 if (val < 0 || val >= maxv)
6739                                         fatal(1, "%d: not in range 0 to %d\n",
6740                                             val, maxv - 1);
6741                                 if (maxv == IP_ABITS)
6742                                         val += IPV6_ABITS - IP_ABITS;
6743                                 ucp = newf->u.a.f_mask.s6_addr;
6744                                 while (val >= 8)
6745                                         *ucp++ = 0xff, val -= 8;
6746                                 *ucp++ = (0xff << (8 - val)) & 0xff;
6747                                 while (ucp < newf->u.a.f_mask.s6_addr +
6748                                     sizeof (newf->u.a.f_mask.s6_addr))
6749                                         *ucp++ = 0;
6750                                 /* Otherwise, try as numeric address */
6751                         } else if (inet_pton(AF_INET6,
6752                             cp, &newf->u.a.f_mask) <= 0) {
6753                                 fatal(1, "%s: illegal mask format\n", cp);
6754                         }
6755                 }
6756                 break;
6757 
6758         case FK_FLAGS:
6759                 if (*arg == '+') {
6760                         newf->u.f.f_flagset = flag_bits(arg + 1);
6761                         newf->u.f.f_flagclear = 0;
6762                 } else if (*arg == '-') {
6763                         newf->u.f.f_flagset = 0;
6764                         newf->u.f.f_flagclear = flag_bits(arg + 1);
6765                 } else {
6766                         newf->u.f.f_flagset = flag_bits(arg);
6767                         newf->u.f.f_flagclear = ~newf->u.f.f_flagset;
6768                 }
6769                 break;
6770 
6771         default:
6772                 assert(0);
6773         }
6774         newf->f_next = filters[idx];
6775         filters[idx] = newf;
6776 }
6777 
6778 /* Determine if user wants this address family printed. */
6779 static boolean_t
6780 family_selected(int family)
6781 {
6782         const filter_t *fp;
6783 
6784         if (v4compat && family == AF_INET6)
6785                 return (B_FALSE);
6786         if ((fp = filters[FK_AF]) == NULL)
6787                 return (B_TRUE);
6788         while (fp != NULL) {
6789                 if (fp->u.f_family == family)
6790                         return (B_TRUE);
6791                 fp = fp->f_next;
6792         }
6793         return (B_FALSE);
6794 }
6795 
6796 /*
6797  * Convert the interface index to a string using the buffer `ifname', which
6798  * must be at least LIFNAMSIZ bytes.  We first try to map it to name.  If that
6799  * fails (e.g., because we're inside a zone and it does not have access to
6800  * interface for the index in question), just return "if#<num>".
6801  */
6802 static char *
6803 ifindex2str(uint_t ifindex, char *ifname)
6804 {
6805         if (if_indextoname(ifindex, ifname) == NULL)
6806                 (void) snprintf(ifname, LIFNAMSIZ, "if#%d", ifindex);
6807 
6808         return (ifname);
6809 }
6810 
6811 /*
6812  * get proc info (psinfo_t) given pid. It doesn't return NULL.
6813  */
6814 
6815 proc_info_t *
6816 get_proc_info(uint32_t pid)
6817 {
6818         static uint32_t saved_pid = 0;
6819         static proc_info_t saved_proc_info;
6820         static proc_info_t unknown_proc_info = {"<unknown>","",""};
6821         static psinfo_t pinfo;
6822         char path[128];
6823         int fd;
6824 
6825         /* hardcode pid = 0 */
6826         if (pid == 0) {
6827                 saved_proc_info.pr_user = "root";
6828                 saved_proc_info.pr_fname = "sched";
6829                 saved_proc_info.pr_psargs = "sched";
6830                 saved_pid = 0;
6831                 return &saved_proc_info;
6832         }
6833 
6834         if (pid == saved_pid)
6835                 return &saved_proc_info;
6836         if ((snprintf(path, 128, "/proc/%u/psinfo",pid) > 0) &&
6837             ((fd = open(path, O_RDONLY)) != -1)) {
6838                 if (read(fd, &pinfo, sizeof(pinfo)) == sizeof(pinfo)){
6839                         saved_proc_info.pr_user = get_username(pinfo.pr_uid);
6840                         saved_proc_info.pr_fname = pinfo.pr_fname;
6841                         saved_proc_info.pr_psargs = pinfo.pr_psargs;
6842                         saved_pid = pid;
6843                         (void) close(fd);
6844                         return &saved_proc_info;
6845                 } else {
6846                         (void) close(fd);
6847                 }
6848         }
6849 
6850         return (&unknown_proc_info);
6851 }
6852 
6853 /*
6854  * get username given uid. It doesn't return NULL.
6855  */
6856 
6857 static char *
6858 get_username(uid_t u)
6859 {
6860         static uid_t saved_uid = UINT_MAX;
6861         static char  saved_username[128];
6862         struct passwd *pw = NULL;
6863         if (u == UINT_MAX)
6864                 return "<unknown>";
6865         if (u == saved_uid && saved_username[0] != '\0')
6866                 return  (saved_username);
6867         setpwent();
6868         if ((pw = getpwuid(u)) != NULL)
6869                 (void) strlcpy(saved_username, pw->pw_name, 128);
6870         else
6871                 (void) snprintf(saved_username, 128, "%u", u);
6872         saved_uid = u;
6873         return saved_username;
6874 }
6875 
6876 /*
6877  * print the usage line
6878  */
6879 static void
6880 usage(char *cmdname)
6881 {
6882         (void) fprintf(stderr, "usage: %s [-anuv] [-f address_family] "
6883             "[-T d|u]\n", cmdname);
6884         (void) fprintf(stderr, "       %s [-n] [-f address_family] "
6885             "[-P protocol] [-T d|u] [-g | -p | -s [interval [count]]]\n",
6886             cmdname);
6887         (void) fprintf(stderr, "       %s -m [-v] [-T d|u] "
6888             "[interval [count]]\n", cmdname);
6889         (void) fprintf(stderr, "       %s -i [-I interface] [-an] "
6890             "[-f address_family] [-T d|u] [interval [count]]\n", cmdname);
6891         (void) fprintf(stderr, "       %s -r [-anv] "
6892             "[-f address_family|filter] [-T d|u]\n", cmdname);
6893         (void) fprintf(stderr, "       %s -M [-ns] [-f address_family] "
6894             "[-T d|u]\n", cmdname);
6895         (void) fprintf(stderr, "       %s -D [-I interface] "
6896             "[-f address_family] [-T d|u]\n", cmdname);
6897         exit(EXIT_FAILURE);
6898 }
6899 
6900 /*
6901  * fatal: print error message to stderr and
6902  * call exit(errcode)
6903  */
6904 /*PRINTFLIKE2*/
6905 static void
6906 fatal(int errcode, char *format, ...)
6907 {
6908         va_list argp;
6909 
6910         if (format == NULL)
6911                 return;
6912 
6913         va_start(argp, format);
6914         (void) vfprintf(stderr, format, argp);
6915         va_end(argp);
6916 
6917         exit(errcode);
6918 }
6919 
6920 
6921 /* -------------------UNIX Domain Sockets Report---------------------------- */
6922 
6923 
6924 #define NO_ADDR         "                                       "
6925 #define SO_PAIR         " (socketpair)                          "
6926 
6927 static char             *typetoname(t_scalar_t);
6928 static boolean_t        uds_report_item(struct sockinfo *, boolean_t);
6929 
6930 
6931 static char uds_hdr[] = "\nActive UNIX domain sockets\n";
6932 
6933 static char uds_hdr_normal[] =
6934 " Type       Local Adress                           "
6935 " Remote Address\n"
6936 "---------- --------------------------------------- "
6937 "---------------------------------------\n";
6938 
6939 static char uds_hdr_pid[] =
6940 " Type       User     Pid     Command       "
6941 " Local Address                         "
6942 " Remote Address\n"
6943 "---------- -------- ------ -------------- "
6944 "--------------------------------------- "
6945 "---------------------------------------\n";
6946 static char uds_hdr_pid_verbose[] =
6947 " Type       User     Pid    Local Address                          "
6948 " Remote Address                          Command\n"
6949 "---------- -------- ------ --------------------------------------- "
6950 "--------------------------------------- --------------\n";
6951 
6952 /*
6953  * Print a summary of connections related to a unix protocol.
6954  */
6955 static void
6956 uds_report(kstat_ctl_t  *kc)
6957 {
6958         int             i;
6959         kstat_t         *ksp;
6960         struct sockinfo *psi;           /* ptr to current sockinfo      */
6961         boolean_t       print_uds_hdr_once = B_TRUE;
6962 
6963         if (kc == NULL) {       /* sanity check.                        */
6964                 fail(0, "uds_report: No kstat");
6965                 exit(3);
6966         }
6967 
6968         /* find the sockfs kstat:                                       */
6969         if ((ksp = kstat_lookup(kc, "sockfs", 0, "sock_unix_list")) ==
6970             (kstat_t *)NULL) {
6971                 fail(0, "kstat_data_lookup failed\n");
6972         }
6973 
6974         if (kstat_read(kc, ksp, NULL) == -1) {
6975                 fail(0, "kstat_read failed for sock_unix_list\n");
6976         }
6977 
6978         if (ksp->ks_ndata == 0) {
6979                 return;                 /* no AF_UNIX sockets found     */
6980         }
6981 
6982         /*
6983          * Having ks_data set with ks_data == NULL shouldn't happen;
6984          * If it does, the sockfs kstat is seriously broken.
6985          */
6986         if ((psi = ksp->ks_data) == NULL) {
6987                 fail(0, "uds_report: no kstat data\n");
6988         }
6989 
6990         /* for each sockinfo structure, display what we need:           */
6991         for (i = 0; i < ksp->ks_ndata; i++) {
6992 
6993                 /* process this entry */
6994                 print_uds_hdr_once = uds_report_item(psi, print_uds_hdr_once);
6995 
6996                 /* if si_size didn't get filled in, then we're done     */
6997                 if (psi->si_size == 0 ||
6998                     !IS_P2ALIGNED(psi->si_size, sizeof (psi))) {
6999                         break;
7000                 }
7001 
7002                 /* point to the next sockinfo in the array */
7003                 /* LINTED: (note 1) */
7004                 psi = (struct sockinfo *)(((char *)psi) + psi->si_size);
7005         }
7006 }
7007 
7008 static boolean_t
7009 uds_report_item(struct sockinfo *psi, boolean_t first)
7010 {
7011         int             i = 0;
7012         conn_pid_node_t *cpn;
7013         proc_info_t     *pinfo;
7014         char            *laddr, *raddr;
7015 
7016         if(first) {
7017                 (void) printf("%s", uds_hdr);
7018                 if (Uflag)
7019                         (void) printf("%s", Vflag?uds_hdr_pid_verbose:
7020                             uds_hdr_pid);
7021                 else
7022                         (void) printf("%s", uds_hdr_normal);
7023 
7024                 first = B_FALSE;
7025         }
7026 
7027         cpn = psi->si_pns;
7028 
7029         do {
7030                 int pid = (psi->si_pn_cnt)?cpn->cpn_pid:0;
7031                 pinfo = get_proc_info(cpn->cpn_pid);
7032                 raddr = laddr = NO_ADDR;
7033 
7034                 /* laddr.soa_sa:                                        */
7035                 if ((psi->si_state & SS_ISBOUND) &&
7036                     strlen(psi->si_laddr_sun_path) != 0 &&
7037                     psi->si_laddr_soa_len != 0) {
7038                         if (psi->si_faddr_noxlate) {
7039                                 laddr = SO_PAIR;
7040                         } else {
7041                                 if (psi->si_laddr_soa_len >
7042                                     sizeof (psi->si_laddr_family))
7043                                         laddr = psi->si_laddr_sun_path;
7044                         }
7045                 }
7046 
7047                 /* faddr.soa_sa:                                        */
7048                 if ((psi->si_state & SS_ISCONNECTED) &&
7049                     strlen(psi->si_faddr_sun_path) != 0 &&
7050                     psi->si_faddr_soa_len != 0) {
7051 
7052                         if (psi->si_faddr_noxlate) {
7053                                 raddr = SO_PAIR;
7054                         } else {
7055                                 if (psi->si_faddr_soa_len >
7056                                     sizeof (psi->si_faddr_family))
7057                                         raddr = psi->si_faddr_sun_path;
7058                         }
7059                 }
7060 
7061                 if (Uflag && Vflag) {
7062                         (void) printf("%-10.10s %-8.8s %6u "
7063                                 "%-39.39s %-39.39s %s\n",
7064                                 typetoname(psi->si_serv_type), pinfo->pr_user,
7065                                 pid, laddr, raddr, pinfo->pr_psargs);
7066                 } else if (Uflag && (!Vflag)) {
7067                         (void) printf("%-10.10s %-8.8s %6u %-14.14s"
7068                                 "%-39.39s %-39.39s\n",
7069                                 typetoname(psi->si_serv_type), pinfo->pr_user,
7070                                 pid, pinfo->pr_fname, laddr, raddr);
7071                 } else {
7072                         (void) printf("%-10.10s %s %s\n",
7073                                 typetoname(psi->si_serv_type), laddr, raddr);
7074                 }
7075 
7076                 i++; cpn++;
7077         } while (i < psi->si_pn_cnt);
7078 
7079         return (first);
7080 }
7081 
7082 static char *
7083 typetoname(t_scalar_t type)
7084 {
7085         switch (type) {
7086         case T_CLTS:
7087                 return ("dgram");
7088 
7089         case T_COTS:
7090                 return ("stream");
7091 
7092         case T_COTS_ORD:
7093                 return ("stream-ord");
7094 
7095         default:
7096                 return ("");
7097         }
7098 }