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