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