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