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