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