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