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