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