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