Home | History | Annotate | Line # | Download | only in netstat
inet6.c revision 1.72.2.2
      1 /*	$NetBSD: inet6.c,v 1.72.2.2 2022/09/12 14:23:41 martin Exp $	*/
      2 /*	BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp	*/
      3 
      4 /*
      5  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. Neither the name of the project nor the names of its contributors
     17  *    may be used to endorse or promote products derived from this software
     18  *    without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     30  * SUCH DAMAGE.
     31  */
     32 
     33 /*
     34  * Copyright (c) 1983, 1988, 1993
     35  *	The Regents of the University of California.  All rights reserved.
     36  *
     37  * Redistribution and use in source and binary forms, with or without
     38  * modification, are permitted provided that the following conditions
     39  * are met:
     40  * 1. Redistributions of source code must retain the above copyright
     41  *    notice, this list of conditions and the following disclaimer.
     42  * 2. Redistributions in binary form must reproduce the above copyright
     43  *    notice, this list of conditions and the following disclaimer in the
     44  *    documentation and/or other materials provided with the distribution.
     45  * 3. Neither the name of the University nor the names of its contributors
     46  *    may be used to endorse or promote products derived from this software
     47  *    without specific prior written permission.
     48  *
     49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     59  * SUCH DAMAGE.
     60  */
     61 
     62 #include <sys/cdefs.h>
     63 #ifndef lint
     64 #if 0
     65 static char sccsid[] = "@(#)inet.c	8.4 (Berkeley) 4/20/94";
     66 #else
     67 __RCSID("$NetBSD: inet6.c,v 1.72.2.2 2022/09/12 14:23:41 martin Exp $");
     68 #endif
     69 #endif /* not lint */
     70 
     71 #define _CALLOUT_PRIVATE
     72 
     73 #include <sys/param.h>
     74 #include <sys/socket.h>
     75 #include <sys/socketvar.h>
     76 #include <sys/ioctl.h>
     77 #include <sys/mbuf.h>
     78 #include <sys/protosw.h>
     79 #include <sys/sysctl.h>
     80 
     81 #include <net/route.h>
     82 #include <net/if.h>
     83 #include <netinet/in.h>
     84 #include <netinet/ip6.h>
     85 #include <netinet/icmp6.h>
     86 #include <netinet/in_systm.h>
     87 #ifndef TCP6
     88 #include <netinet/ip.h>
     89 #include <netinet/ip_var.h>
     90 #endif
     91 #include <netinet6/ip6_var.h>
     92 #include <netinet6/in6_pcb.h>
     93 #include <netinet6/in6_var.h>
     94 #ifdef TCP6
     95 #include <netinet/tcp6.h>
     96 #include <netinet/tcp6_seq.h>
     97 #define TCP6STATES
     98 #include <netinet/tcp6_fsm.h>
     99 #define TCP6TIMERS
    100 #include <netinet/tcp6_timer.h>
    101 #include <netinet/tcp6_var.h>
    102 #include <netinet/tcp6_debug.h>
    103 #else
    104 #define TCP6T_NTIMERS	TCPT_NTIMERS
    105 #define tcp6timers tcptimers
    106 #define tcp6states tcpstates
    107 #define TCP6_NSTATES	TCP_NSTATES
    108 #define tcp6cb tcpcb
    109 #include <netinet/tcp.h>
    110 #include <netinet/tcp_seq.h>
    111 #include <netinet/tcp_fsm.h>
    112 extern const char * const tcpstates[];
    113 extern const char * const tcptimers[];
    114 #include <netinet/tcp_timer.h>
    115 #include <netinet/tcp_var.h>
    116 #include <netinet/tcp_debug.h>
    117 #endif /*TCP6*/
    118 #include <netinet6/udp6.h>
    119 #include <netinet6/udp6_var.h>
    120 #include <netinet6/pim6_var.h>
    121 #include <netinet6/raw_ip6.h>
    122 #include <netinet/tcp_vtw.h>
    123 
    124 #include <arpa/inet.h>
    125 #if 0
    126 #include "gethostbyname2.h"
    127 #endif
    128 #include <netdb.h>
    129 
    130 #include <err.h>
    131 #include <errno.h>
    132 #include <kvm.h>
    133 #include <stdio.h>
    134 #include <stdlib.h>
    135 #include <string.h>
    136 #include <unistd.h>
    137 #include <util.h>
    138 #include "netstat.h"
    139 #include "vtw.h"
    140 #include "prog_ops.h"
    141 
    142 #ifdef INET6
    143 
    144 struct	in6pcb in6pcb;
    145 #ifdef TCP6
    146 struct	tcp6cb tcp6cb;
    147 #else
    148 struct	tcpcb tcpcb;
    149 #endif
    150 
    151 char	*inet6name(const struct in6_addr *);
    152 void	inet6print(const struct in6_addr *, int, const char *);
    153 void	print_vtw_v6(const vtw_t *);
    154 
    155 /*
    156  * Print a summary of connections related to an Internet
    157  * protocol.  For TCP, also give state of connection.
    158  * Listening processes (aflag) are suppressed unless the
    159  * -a (all) flag is specified.
    160  */
    161 static int width;
    162 static int compact;
    163 
    164 /* VTW-related variables. */
    165 static struct timeval now;
    166 
    167 static void
    168 ip6protoprhdr(void)
    169 {
    170 
    171 	printf("Active Internet6 connections");
    172 
    173 	if (aflag)
    174 		printf(" (including servers)");
    175 	putchar('\n');
    176 
    177 	if (Aflag) {
    178 		printf("%-8.8s ", "PCB");
    179 		width = 18;
    180 	}
    181 	printf(
    182 	    Vflag ? "%-5.5s %-6.6s %-6.6s  %*.*s %*.*s %-13.13s Expires\n"
    183 		  : "%-5.5s %-6.6s %-6.6s  %*.*s %*.*s %s\n",
    184 	    "Proto", "Recv-Q", "Send-Q",
    185 	    -width, width, "Local Address",
    186 	    -width, width, "Foreign Address", "(state)");
    187 }
    188 
    189 static void
    190 ip6protopr0(intptr_t ppcb, u_long rcv_sb_cc, u_long snd_sb_cc,
    191 	const struct in6_addr *laddr, uint16_t lport,
    192 	const struct in6_addr *faddr, uint16_t fport,
    193 	short t_state, const char *name, const struct timeval *expires)
    194 {
    195 	static const char *shorttcpstates[] = {
    196 		"CLOSED",       "LISTEN",       "SYNSEN",       "SYSRCV",
    197 		"ESTABL",       "CLWAIT",       "FWAIT1",       "CLOSNG",
    198 		"LASTAK",       "FWAIT2",       "TMWAIT"
    199 	};
    200 	int istcp;
    201 
    202 	istcp = strcmp(name, "tcp6") == 0;
    203 	if (Aflag)
    204 		printf("%8" PRIxPTR " ", ppcb);
    205 
    206 	printf("%-5.5s %6ld %6ld%s", name, rcv_sb_cc, snd_sb_cc,
    207 	    compact ? "" : " ");
    208 
    209 	inet6print(laddr, (int)lport, name);
    210 	inet6print(faddr, (int)fport, name);
    211 	if (istcp) {
    212 #ifdef TCP6
    213 		if (t_state < 0 || t_state >= TCP6_NSTATES)
    214 			printf(" %d", t_state);
    215 		else
    216 			printf(" %s", tcp6states[t_state]);
    217 #else
    218 		if (t_state < 0 || t_state >= TCP_NSTATES)
    219 			printf(" %d", t_state);
    220 		else
    221 			printf(" %s", compact ? shorttcpstates[t_state] :
    222 			    tcpstates[t_state]);
    223 #endif
    224 	}
    225 	if (Vflag && expires != NULL) {
    226 		if (expires->tv_sec == 0 && expires->tv_usec == -1)
    227 			printf(" reclaimed");
    228 		else {
    229 			struct timeval delta;
    230 
    231 			timersub(expires, &now, &delta);
    232 			printf(" %.3fms",
    233 			    delta.tv_sec * 1000.0 + delta.tv_usec / 1000.0);
    234 		}
    235 	}
    236 	putchar('\n');
    237 }
    238 
    239 static void
    240 dbg_printf(const char *fmt, ...)
    241 {
    242 
    243 	return;
    244 }
    245 
    246 void
    247 print_vtw_v6(const vtw_t *vtw)
    248 {
    249 	const vtw_v6_t *v6 = (const vtw_v6_t *)vtw;
    250 	struct timeval delta;
    251 	char buf[2][128];
    252 	static const struct timeval zero = {.tv_sec = 0, .tv_usec = 0};
    253 
    254 	inet_ntop(AF_INET6, &v6->laddr, buf[0], sizeof(buf[0]));
    255 	inet_ntop(AF_INET6, &v6->faddr, buf[1], sizeof(buf[1]));
    256 
    257 	timersub(&vtw->expire, &now, &delta);
    258 
    259 	if (vtw->expire.tv_sec == 0 && vtw->expire.tv_usec == -1) {
    260 		dbg_printf("%15.15s:%d %15.15s:%d reclaimed\n",
    261 		    buf[0], ntohs(v6->lport),
    262 		    buf[1], ntohs(v6->fport));
    263 		if (!(Vflag && vflag))
    264 			return;
    265 	} else if (vtw->expire.tv_sec == 0)
    266 		return;
    267 	else if (timercmp(&delta, &zero, <) && !(Vflag && vflag)) {
    268 		dbg_printf("%15.15s:%d %15.15s:%d expired\n",
    269 		    buf[0], ntohs(v6->lport),
    270 		    buf[1], ntohs(v6->fport));
    271 		return;
    272 	} else {
    273 		dbg_printf("%15.15s:%d %15.15s:%d expires in %.3fms\n",
    274 		    buf[0], ntohs(v6->lport),
    275 		    buf[1], ntohs(v6->fport),
    276 		    delta.tv_sec * 1000.0 + delta.tv_usec / 1000.0);
    277 	}
    278 	ip6protopr0(0, 0, 0,
    279 		 &v6->laddr, v6->lport,
    280 		 &v6->faddr, v6->fport,
    281 		 TCPS_TIME_WAIT, "tcp6", &vtw->expire);
    282 }
    283 
    284 
    285 static struct kinfo_pcb *
    286 getpcblist_kmem(u_long off, const char *name, size_t *len)
    287 {
    288 	struct socket sockb;
    289 	struct inpcbtable table;
    290 	struct inpcb_hdr *next, *prev;
    291 	int istcp = strcmp(name, "tcp6") == 0;
    292 	struct kinfo_pcb *pcblist;
    293 	size_t size = 100, i;
    294 	struct sockaddr_in6 sin6;
    295 	struct inpcbqueue *head;
    296 
    297 	if (off == 0) {
    298 		*len = 0;
    299 		return NULL;
    300 	}
    301 	kread(off, (char *)&table, sizeof (table));
    302 	head = &table.inpt_queue;
    303 	next = TAILQ_FIRST(head);
    304 	prev = TAILQ_END(head);
    305 
    306 	if ((pcblist = malloc(size * sizeof(*pcblist))) == NULL)
    307 		err(1, "malloc");
    308 
    309 	i = 0;
    310 	while (next != TAILQ_END(head)) {
    311 		kread((u_long)next, (char *)&in6pcb, sizeof in6pcb);
    312 		next = TAILQ_NEXT(&in6pcb, in6p_queue);
    313 		prev = next;
    314 
    315 		if (in6pcb.in6p_af != AF_INET6)
    316 			continue;
    317 
    318 		kread((u_long)in6pcb.in6p_socket, (char *)&sockb,
    319 		    sizeof (sockb));
    320 		if (istcp) {
    321 #ifdef TCP6
    322 			kread((u_long)in6pcb.in6p_ppcb,
    323 			    (char *)&tcp6cb, sizeof (tcp6cb));
    324 #else
    325 			kread((u_long)in6pcb.in6p_ppcb,
    326 			    (char *)&tcpcb, sizeof (tcpcb));
    327 #endif
    328 		}
    329 		pcblist[i].ki_ppcbaddr =
    330 		    istcp ? (uintptr_t) in6pcb.in6p_ppcb : (uintptr_t) prev;
    331 		pcblist[i].ki_rcvq = (uint64_t)sockb.so_rcv.sb_cc;
    332 		pcblist[i].ki_sndq = (uint64_t)sockb.so_snd.sb_cc;
    333 		sin6.sin6_addr = in6pcb.in6p_laddr;
    334 		sin6.sin6_port = in6pcb.in6p_lport;
    335 		memcpy(&pcblist[i].ki_s, &sin6, sizeof(sin6));
    336 		sin6.sin6_addr = in6pcb.in6p_faddr;
    337 		sin6.sin6_port = in6pcb.in6p_fport;
    338 		memcpy(&pcblist[i].ki_d, &sin6, sizeof(sin6));
    339 		pcblist[i].ki_tstate = tcpcb.t_state;
    340 		if (i++ == size) {
    341 			size += 100;
    342 			struct kinfo_pcb *n = realloc(pcblist,
    343 			    size * sizeof(*pcblist));
    344 			if (n == NULL)
    345 				err(1, "realloc");
    346 			pcblist = n;
    347 		}
    348 	}
    349 	*len = i;
    350 	return pcblist;
    351 }
    352 
    353 void
    354 ip6protopr(u_long off, const char *name)
    355 {
    356 	struct kinfo_pcb *pcblist;
    357 	size_t i, len;
    358 	static int first = 1;
    359 
    360 	compact = 0;
    361 	if (Aflag) {
    362 		if (!numeric_addr)
    363 			width = 18;
    364 		else {
    365 			width = 21;
    366 			compact = 1;
    367 		}
    368 	} else
    369 		width = 22;
    370 
    371 	if (use_sysctl)
    372 		pcblist = getpcblist_sysctl(name, &len);
    373 	else
    374 		pcblist = getpcblist_kmem(off, name, &len);
    375 
    376 	for (i = 0; i < len; i++) {
    377 		struct sockaddr_in6 src, dst;
    378 
    379 		memcpy(&src, &pcblist[i].ki_s, sizeof(src));
    380 		memcpy(&dst, &pcblist[i].ki_d, sizeof(dst));
    381 
    382 		if (!aflag && IN6_IS_ADDR_UNSPECIFIED(&dst.sin6_addr))
    383 			continue;
    384 
    385 		if (first) {
    386 			ip6protoprhdr();
    387 			first = 0;
    388 		}
    389 
    390 		ip6protopr0((intptr_t) pcblist[i].ki_ppcbaddr,
    391 		    pcblist[i].ki_rcvq, pcblist[i].ki_sndq,
    392 		    &src.sin6_addr, src.sin6_port,
    393 		    &dst.sin6_addr, dst.sin6_port,
    394 		    pcblist[i].ki_tstate, name, NULL);
    395 	}
    396 
    397 	free(pcblist);
    398 
    399 	if (strcmp(name, "tcp6") == 0) {
    400 		struct timeval t;
    401 		timebase(&t);
    402 		gettimeofday(&now, NULL);
    403 		timersub(&now, &t, &now);
    404 		show_vtw_v6(print_vtw_v6);
    405 	}
    406 }
    407 
    408 #ifdef TCP6
    409 /*
    410  * Dump TCP6 statistics structure.
    411  */
    412 void
    413 tcp6_stats(u_long off, const char *name)
    414 {
    415 	struct tcp6stat tcp6stat;
    416 
    417 	if (use_sysctl) {
    418 		size_t size = sizeof(tcp6stat);
    419 
    420 		if (prog_sysctlbyname("net.inet6.tcp6.stats", &tcp6stat, &size,
    421 		    NULL, 0) == -1)
    422 			return;
    423 	} else {
    424 		warnx("%s stats not available via KVM.", name);
    425 		return;
    426 	}
    427 
    428 	printf ("%s:\n", name);
    429 
    430 #define	p(f, m) if (tcp6stat.f || sflag <= 1)			\
    431 		printf(m, tcp6stat.f, plural(tcp6stat.f))
    432 #define	p2(f1, f2, m) if (tcp6stat.f1 || tcp6stat.f2 || sflag <= 1)	 \
    433 		printf(m, tcp6stat.f1, plural(tcp6stat.f1), tcp6stat.f2, \
    434 		    plural(tcp6stat.f2))
    435 #define	p3(f, m) if (tcp6stat.f || sflag <= 1)			\
    436 		printf(m, tcp6stat.f, plurales(tcp6stat.f))
    437 
    438 	p(tcp6s_sndtotal, "\t%ld packet%s sent\n");
    439 	p2(tcp6s_sndpack,tcp6s_sndbyte,
    440 	    "\t\t%ld data packet%s (%ld byte%s)\n");
    441 	p2(tcp6s_sndrexmitpack, tcp6s_sndrexmitbyte,
    442 	    "\t\t%ld data packet%s (%ld byte%s) retransmitted\n");
    443 	p2(tcp6s_sndacks, tcp6s_delack,
    444 	    "\t\t%ld ack-only packet%s (%ld packet%s delayed)\n");
    445 	p(tcp6s_sndurg, "\t\t%ld URG only packet%s\n");
    446 	p(tcp6s_sndprobe, "\t\t%ld window probe packet%s\n");
    447 	p(tcp6s_sndwinup, "\t\t%ld window update packet%s\n");
    448 	p(tcp6s_sndctrl, "\t\t%ld control packet%s\n");
    449 	p(tcp6s_rcvtotal, "\t%ld packet%s received\n");
    450 	p2(tcp6s_rcvackpack, tcp6s_rcvackbyte,
    451 	    "\t\t%ld ack%s (for %ld byte%s)\n");
    452 	p(tcp6s_rcvdupack, "\t\t%ld duplicate ack%s\n");
    453 	p(tcp6s_rcvacktoomuch, "\t\t%ld ack%s for unsent data\n");
    454 	p2(tcp6s_rcvpack, tcp6s_rcvbyte,
    455 	    "\t\t%ld packet%s (%ld byte%s) received in-sequence\n");
    456 	p2(tcp6s_rcvduppack, tcp6s_rcvdupbyte,
    457 	    "\t\t%ld completely duplicate packet%s (%ld byte%s)\n");
    458 	p(tcp6s_pawsdrop, "\t\t%ld old duplicate packet%s\n");
    459 	p2(tcp6s_rcvpartduppack, tcp6s_rcvpartdupbyte,
    460 	    "\t\t%ld packet%s with some dup. data (%ld byte%s duped)\n");
    461 	p2(tcp6s_rcvoopack, tcp6s_rcvoobyte,
    462 	    "\t\t%ld out-of-order packet%s (%ld byte%s)\n");
    463 	p2(tcp6s_rcvpackafterwin, tcp6s_rcvbyteafterwin,
    464 	    "\t\t%ld packet%s (%ld byte%s) of data after window\n");
    465 	p(tcp6s_rcvwinprobe, "\t\t%ld window probe%s\n");
    466 	p(tcp6s_rcvwinupd, "\t\t%ld window update packet%s\n");
    467 	p(tcp6s_rcvafterclose, "\t\t%ld packet%s received after close\n");
    468 	p(tcp6s_rcvbadsum, "\t\t%ld discarded for bad checksum%s\n");
    469 	p(tcp6s_rcvbadoff,
    470 	    "\t\t%ld discarded for bad header offset field%s\n");
    471 	p(tcp6s_rcvshort, "\t\t%ld discarded because packet%s too short\n");
    472 	p(tcp6s_connattempt, "\t%ld connection request%s\n");
    473 	p(tcp6s_accepts, "\t%ld connection accept%s\n");
    474 	p(tcp6s_badsyn, "\t%ld bad connection attempt%s\n");
    475 	p(tcp6s_connects,
    476 	    "\t%ld connection%s established (including accepts)\n");
    477 	p2(tcp6s_closed, tcp6s_drops,
    478 	    "\t%ld connection%s closed (including %ld drop%s)\n");
    479 	p(tcp6s_conndrops, "\t%ld embryonic connection%s dropped\n");
    480 	p2(tcp6s_rttupdated, tcp6s_segstimed,
    481 	    "\t%ld segment%s updated rtt (of %ld attempt%s)\n");
    482 	p(tcp6s_rexmttimeo, "\t%ld retransmit timeout%s\n");
    483 	p(tcp6s_timeoutdrop,
    484 	    "\t\t%ld connection%s dropped by rexmit timeout\n");
    485 	p(tcp6s_persisttimeo, "\t%ld persist timeout%s\n");
    486 	p(tcp6s_persistdrop, "\t%ld connection%s timed out in persist\n");
    487 	p(tcp6s_keeptimeo, "\t%ld keepalive timeout%s\n");
    488 	p(tcp6s_keepprobe, "\t\t%ld keepalive probe%s sent\n");
    489 	p(tcp6s_keepdrops, "\t\t%ld connection%s dropped by keepalive\n");
    490 	p(tcp6s_predack, "\t%ld correct ACK header prediction%s\n");
    491 	p(tcp6s_preddat, "\t%ld correct data packet header prediction%s\n");
    492 	p3(tcp6s_pcbcachemiss, "\t%ld PCB cache miss%s\n");
    493 #undef p
    494 #undef p2
    495 #undef p3
    496 }
    497 #endif
    498 
    499 /*
    500  * Dump UDP6 statistics structure.
    501  */
    502 void
    503 udp6_stats(u_long off, const char *name)
    504 {
    505 	uint64_t udp6stat[UDP6_NSTATS];
    506 	u_quad_t delivered;
    507 
    508 	if (use_sysctl) {
    509 		size_t size = sizeof(udp6stat);
    510 
    511 		if (prog_sysctlbyname("net.inet6.udp6.stats", udp6stat, &size,
    512 		    NULL, 0) == -1)
    513 			return;
    514 	} else {
    515 		warnx("%s stats not available via KVM.", name);
    516 		return;
    517 	}
    518 	printf("%s:\n", name);
    519 #define	p(f, m) if (udp6stat[f] || sflag <= 1)				      \
    520 		printf(m, (unsigned long long)udp6stat[f], plural(udp6stat[f]))
    521 #define	p1(f, m) if (udp6stat[f] || sflag <= 1)			\
    522 		printf(m, (unsigned long long)udp6stat[f])
    523 	p(UDP6_STAT_IPACKETS, "\t%llu datagram%s received\n");
    524 	p1(UDP6_STAT_HDROPS, "\t%llu with incomplete header\n");
    525 	p1(UDP6_STAT_BADLEN, "\t%llu with bad data length field\n");
    526 	p1(UDP6_STAT_BADSUM, "\t%llu with bad checksum\n");
    527 	p1(UDP6_STAT_NOSUM, "\t%llu with no checksum\n");
    528 	p1(UDP6_STAT_NOPORT, "\t%llu dropped due to no socket\n");
    529 	p(UDP6_STAT_NOPORTMCAST,
    530 	    "\t%llu multicast datagram%s dropped due to no socket\n");
    531 	p1(UDP6_STAT_FULLSOCK, "\t%llu dropped due to full socket buffers\n");
    532 	delivered = udp6stat[UDP6_STAT_IPACKETS] -
    533 		    udp6stat[UDP6_STAT_HDROPS] -
    534 		    udp6stat[UDP6_STAT_BADLEN] -
    535 		    udp6stat[UDP6_STAT_BADSUM] -
    536 		    udp6stat[UDP6_STAT_NOPORT] -
    537 		    udp6stat[UDP6_STAT_NOPORTMCAST] -
    538 		    udp6stat[UDP6_STAT_FULLSOCK];
    539 	if (delivered || sflag <= 1)
    540 		printf("\t%llu delivered\n", (unsigned long long)delivered);
    541 	p(UDP6_STAT_OPACKETS, "\t%llu datagram%s output\n");
    542 #undef p
    543 #undef p1
    544 }
    545 
    546 static	const char *ip6nh[] = {
    547 /*0*/	"hop by hop",
    548 	"ICMP",
    549 	"IGMP",
    550 	NULL,
    551 	"IP",
    552 /*5*/	NULL,
    553 	"TCP",
    554 	NULL,
    555 	NULL,
    556 	NULL,
    557 /*10*/	NULL, NULL, NULL, NULL, NULL,
    558 /*15*/	NULL,
    559 	NULL,
    560 	"UDP",
    561 	NULL,
    562 	NULL,
    563 /*20*/	NULL,
    564 	NULL,
    565 	"IDP",
    566 	NULL,
    567 	NULL,
    568 /*25*/	NULL,
    569 	NULL,
    570 	NULL,
    571 	NULL,
    572 	NULL,
    573 /*30*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    574 /*40*/	NULL,
    575 	"IP6",
    576 	NULL,
    577 	"routing",
    578 	"fragment",
    579 /*45*/	NULL, NULL, NULL, NULL, NULL,
    580 /*50*/	"ESP",
    581 	"AH",
    582 	NULL,
    583 	NULL,
    584 	NULL,
    585 /*55*/	NULL,
    586 	NULL,
    587 	NULL,
    588 	"ICMP6",
    589 	"no next header",
    590 /*60*/	"destination option",
    591 	NULL,
    592 	NULL,
    593 	NULL,
    594 	NULL,
    595 /*65*/	NULL, NULL, NULL, NULL, NULL,
    596 /*70*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    597 /*80*/	NULL,
    598 	NULL,
    599 	NULL,
    600 	NULL,
    601 	NULL,
    602 	NULL,
    603 	NULL,
    604 	NULL,
    605 	NULL,
    606 	"OSPF",
    607 /*90*/	NULL, NULL, NULL, NULL, NULL,
    608 /*95*/	NULL,
    609 	NULL,
    610 	"Ethernet",
    611 	NULL,
    612 	NULL,
    613 /*100*/	NULL,
    614 	NULL,
    615 	NULL,
    616 	"PIM",
    617 	NULL,
    618 /*105*/	NULL, NULL, NULL, NULL, NULL,
    619 /*110*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    620 /*120*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    621 /*130*/	NULL,
    622 	NULL,
    623 	"SCTP",
    624 	NULL,
    625 	NULL,
    626 /*135*/	NULL, NULL, NULL, NULL, NULL,
    627 /*140*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    628 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    629 /*160*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    630 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    631 /*180*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    632 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    633 /*200*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    634 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    635 /*220*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    636 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    637 /*240*/	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    638 	NULL, NULL, NULL, NULL, NULL, NULL
    639 };
    640 
    641 /*
    642  * Dump IP6 statistics structure.
    643  */
    644 void
    645 ip6_stats(u_long off, const char *name)
    646 {
    647 	uint64_t ip6stat[IP6_NSTATS];
    648 	int first, i;
    649 	struct protoent *ep;
    650 	const char *n;
    651 
    652 	if (use_sysctl) {
    653 		size_t size = sizeof(ip6stat);
    654 
    655 		if (prog_sysctlbyname("net.inet6.ip6.stats", ip6stat, &size,
    656 		    NULL, 0) == -1)
    657 			return;
    658 	} else {
    659 		warnx("%s stats not available via KVM.", name);
    660 		return;
    661 	}
    662 	printf("%s:\n", name);
    663 
    664 #define	p(f, m) if (ip6stat[f] || sflag <= 1)				     \
    665 		printf(m, (unsigned long long)ip6stat[f], plural(ip6stat[f]))
    666 #define	p1(f, m) if (ip6stat[f] || sflag <= 1)			\
    667 		printf(m, (unsigned long long)ip6stat[f])
    668 
    669 	p(IP6_STAT_TOTAL, "\t%llu total packet%s received\n");
    670 	p1(IP6_STAT_TOOSMALL, "\t%llu with size smaller than minimum\n");
    671 	p1(IP6_STAT_TOOSHORT, "\t%llu with data size < data length\n");
    672 	p1(IP6_STAT_BADOPTIONS, "\t%llu with bad options\n");
    673 	p1(IP6_STAT_BADVERS, "\t%llu with incorrect version number\n");
    674 	p(IP6_STAT_FRAGMENTS, "\t%llu fragment%s received\n");
    675 	p(IP6_STAT_FRAGDROPPED,
    676 	    "\t%llu fragment%s dropped (dup or out of space)\n");
    677 	p(IP6_STAT_FRAGTIMEOUT, "\t%llu fragment%s dropped after timeout\n");
    678 	p(IP6_STAT_FRAGOVERFLOW, "\t%llu fragment%s that exceeded limit\n");
    679 	p(IP6_STAT_REASSEMBLED, "\t%llu packet%s reassembled ok\n");
    680 	p(IP6_STAT_DELIVERED, "\t%llu packet%s for this host\n");
    681 	p(IP6_STAT_FORWARD, "\t%llu packet%s forwarded\n");
    682 	p(IP6_STAT_FASTFORWARD, "\t%llu packet%s fast forwarded\n");
    683 	p1(IP6_STAT_FASTFORWARDFLOWS, "\t%llu fast forward flows\n");
    684 	p(IP6_STAT_CANTFORWARD, "\t%llu packet%s not forwardable\n");
    685 	p(IP6_STAT_REDIRECTSENT, "\t%llu redirect%s sent\n");
    686 	p(IP6_STAT_LOCALOUT, "\t%llu packet%s sent from this host\n");
    687 	p(IP6_STAT_RAWOUT, "\t%llu packet%s sent with fabricated ip header\n");
    688 	p(IP6_STAT_ODROPPED,
    689 	    "\t%llu output packet%s dropped due to no bufs, etc.\n");
    690 	p(IP6_STAT_NOROUTE,
    691 	    "\t%llu output packet%s discarded due to no route\n");
    692 	p(IP6_STAT_FRAGMENTED, "\t%llu output datagram%s fragmented\n");
    693 	p(IP6_STAT_OFRAGMENTS, "\t%llu fragment%s created\n");
    694 	p(IP6_STAT_CANTFRAG, "\t%llu datagram%s that can't be fragmented\n");
    695 	p(IP6_STAT_BADSCOPE, "\t%llu packet%s that violated scope rules\n");
    696 	p(IP6_STAT_NOTMEMBER, "\t%llu multicast packet%s which we don't join\n");
    697 	for (first = 1, i = 0; i < 256; i++)
    698 		if (ip6stat[IP6_STAT_NXTHIST + i] != 0) {
    699 			if (first) {
    700 				printf("\tInput packet histogram:\n");
    701 				first = 0;
    702 			}
    703 			n = NULL;
    704 			if (ip6nh[i])
    705 				n = ip6nh[i];
    706 			else if ((ep = getprotobynumber(i)) != NULL)
    707 				n = ep->p_name;
    708 			if (n)
    709 				printf("\t\t%s: %llu\n", n,
    710 				    (unsigned long long)ip6stat[IP6_STAT_NXTHIST + i]);
    711 			else
    712 				printf("\t\t#%d: %llu\n", i,
    713 				    (unsigned long long)ip6stat[IP6_STAT_NXTHIST + i]);
    714 		}
    715 	printf("\tMbuf statistics:\n");
    716 	p(IP6_STAT_M1, "\t\t%llu one mbuf%s\n");
    717 	for (first = 1, i = 0; i < 32; i++) {
    718 		char ifbuf[IFNAMSIZ];
    719 		if (ip6stat[IP6_STAT_M2M + i] != 0) {
    720 			if (first) {
    721 				printf("\t\ttwo or more mbuf:\n");
    722 				first = 0;
    723 			}
    724 			printf("\t\t\t%s = %llu\n",
    725 			    if_indextoname(i, ifbuf),
    726 			    (unsigned long long)ip6stat[IP6_STAT_M2M + i]);
    727 		}
    728 	}
    729 	p(IP6_STAT_MEXT1, "\t\t%llu one ext mbuf%s\n");
    730 	p(IP6_STAT_MEXT2M, "\t\t%llu two or more ext mbuf%s\n");
    731 	p(IP6_STAT_EXTHDRTOOLONG,
    732 	    "\t%llu packet%s whose headers are not continuous\n");
    733 	p(IP6_STAT_NOGIF, "\t%llu tunneling packet%s that can't find gif\n");
    734 	p(IP6_STAT_NOIPSEC,
    735 	    "\t%llu tunneling packet%s that can't find ipsecif\n");
    736 	p(IP6_STAT_TOOMANYHDR,
    737 	    "\t%llu packet%s discarded due to too many headers\n");
    738 
    739 	/* for debugging source address selection */
    740 #define PRINT_SCOPESTAT(s, i) do {				\
    741 		switch (i) { /* XXX hardcoding in each case */	\
    742 		case 1:						\
    743 			p(s, "\t\t%llu node-local%s\n");	\
    744 			break;					\
    745 		case 2:						\
    746 			p(s, "\t\t%llu link-local%s\n");	\
    747 			break;					\
    748 		case 5:						\
    749 			p(s, "\t\t%llu site-local%s\n");	\
    750 			break;					\
    751 		case 14:					\
    752 			p(s, "\t\t%llu global%s\n");		\
    753 			break;					\
    754 		default:					\
    755 			printf("\t\t%llu addresses scope=%x\n",	\
    756 			    (unsigned long long)ip6stat[s], i);	\
    757 		}						\
    758 	} while(/*CONSTCOND*/0);
    759 
    760 	p(IP6_STAT_SOURCES_NONE,
    761 	  "\t%llu failure%s of source address selection\n");
    762 	for (first = 1, i = 0; i < 16; i++) {
    763 		if (ip6stat[IP6_STAT_SOURCES_SAMEIF + i]) {
    764 			if (first) {
    765 				printf("\tsource addresses on an outgoing I/F\n");
    766 				first = 0;
    767 			}
    768 			PRINT_SCOPESTAT(IP6_STAT_SOURCES_SAMEIF + i, i);
    769 		}
    770 	}
    771 	for (first = 1, i = 0; i < 16; i++) {
    772 		if (ip6stat[IP6_STAT_SOURCES_OTHERIF + i]) {
    773 			if (first) {
    774 				printf("\tsource addresses on a non-outgoing I/F\n");
    775 				first = 0;
    776 			}
    777 			PRINT_SCOPESTAT(IP6_STAT_SOURCES_OTHERIF + i, i);
    778 		}
    779 	}
    780 	for (first = 1, i = 0; i < 16; i++) {
    781 		if (ip6stat[IP6_STAT_SOURCES_SAMESCOPE + i]) {
    782 			if (first) {
    783 				printf("\tsource addresses of same scope\n");
    784 				first = 0;
    785 			}
    786 			PRINT_SCOPESTAT(IP6_STAT_SOURCES_SAMESCOPE + i, i);
    787 		}
    788 	}
    789 	for (first = 1, i = 0; i < 16; i++) {
    790 		if (ip6stat[IP6_STAT_SOURCES_OTHERSCOPE + i]) {
    791 			if (first) {
    792 				printf("\tsource addresses of a different scope\n");
    793 				first = 0;
    794 			}
    795 			PRINT_SCOPESTAT(IP6_STAT_SOURCES_OTHERSCOPE + i, i);
    796 		}
    797 	}
    798 	for (first = 1, i = 0; i < 16; i++) {
    799 		if (ip6stat[IP6_STAT_SOURCES_DEPRECATED + i]) {
    800 			if (first) {
    801 				printf("\tdeprecated source addresses\n");
    802 				first = 0;
    803 			}
    804 			PRINT_SCOPESTAT(IP6_STAT_SOURCES_DEPRECATED + i, i);
    805 		}
    806 	}
    807 
    808 	p1(IP6_STAT_FORWARD_CACHEHIT, "\t%llu forward cache hit\n");
    809 	p1(IP6_STAT_FORWARD_CACHEMISS, "\t%llu forward cache miss\n");
    810 	p(IP6_STAT_PFILDROP_IN, "\t%llu input packet%s dropped by pfil\n");
    811 	p(IP6_STAT_PFILDROP_OUT, "\t%llu output packet%s dropped by pfil\n");
    812 #undef p
    813 #undef p1
    814 }
    815 
    816 /*
    817  * Dump IPv6 per-interface statistics based on RFC 2465.
    818  */
    819 void
    820 ip6_ifstats(const char *ifname)
    821 {
    822 	struct in6_ifreq ifr;
    823 	int s;
    824 #define	p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1)		\
    825 		printf(m, (unsigned long long)ifr.ifr_ifru.ifru_stat.f, \
    826 		    plural(ifr.ifr_ifru.ifru_stat.f))
    827 #define	p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1)	\
    828 		printf(m, (unsigned long long)ip6stat.f)
    829 
    830 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
    831 		perror("Warning: socket(AF_INET6)");
    832 		return;
    833 	}
    834 
    835 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    836 	printf("ip6 on %s:\n", ifname);
    837 
    838 	if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
    839 		perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
    840 		goto end;
    841 	}
    842 
    843 	p(ifs6_in_receive, "\t%llu total input datagram%s\n");
    844 	p(ifs6_in_hdrerr, "\t%llu datagram%s with invalid header received\n");
    845 	p(ifs6_in_toobig, "\t%llu datagram%s exceeded MTU received\n");
    846 	p(ifs6_in_noroute, "\t%llu datagram%s with no route received\n");
    847 	p(ifs6_in_addrerr, "\t%llu datagram%s with invalid dst received\n");
    848 	p(ifs6_in_truncated, "\t%llu truncated datagram%s received\n");
    849 	p(ifs6_in_protounknown,
    850 	    "\t%llu datagram%s with unknown proto received\n");
    851 	p(ifs6_in_discard, "\t%llu input datagram%s discarded\n");
    852 	p(ifs6_in_deliver,
    853 	    "\t%llu datagram%s delivered to an upper layer protocol\n");
    854 	p(ifs6_out_forward, "\t%llu datagram%s forwarded to this interface\n");
    855 	p(ifs6_out_request,
    856 	    "\t%llu datagram%s sent from an upper layer protocol\n");
    857 	p(ifs6_out_discard, "\t%llu total discarded output datagram%s\n");
    858 	p(ifs6_out_fragok, "\t%llu output datagram%s fragmented\n");
    859 	p(ifs6_out_fragfail, "\t%llu output datagram%s failed on fragment\n");
    860 	p(ifs6_out_fragcreat,
    861 	    "\t%llu output datagram%s succeeded on fragment\n");
    862 	p(ifs6_reass_reqd, "\t%llu incoming datagram%s fragmented\n");
    863 	p(ifs6_reass_ok, "\t%llu datagram%s reassembled\n");
    864 	p(ifs6_reass_fail, "\t%llu datagram%s failed on reassembling\n");
    865 	p(ifs6_in_mcast, "\t%llu multicast datagram%s received\n");
    866 	p(ifs6_out_mcast, "\t%llu multicast datagram%s sent\n");
    867 
    868   end:
    869 	close(s);
    870 
    871 #undef p
    872 #undef p_5
    873 }
    874 
    875 static	const char *icmp6names[256] = {
    876 	"#0",
    877 	"unreach",
    878 	"packet too big",
    879 	"time exceed",
    880 	"parameter problem",
    881 	"#5",
    882 	"#6",
    883 	"#7",
    884 	"#8",
    885 	"#9",
    886 	"#10",
    887 	"#11",
    888 	"#12",
    889 	"#13",
    890 	"#14",
    891 	"#15",
    892 	"#16",
    893 	"#17",
    894 	"#18",
    895 	"#19",
    896 	"#20",
    897 	"#21",
    898 	"#22",
    899 	"#23",
    900 	"#24",
    901 	"#25",
    902 	"#26",
    903 	"#27",
    904 	"#28",
    905 	"#29",
    906 	"#30",
    907 	"#31",
    908 	"#32",
    909 	"#33",
    910 	"#34",
    911 	"#35",
    912 	"#36",
    913 	"#37",
    914 	"#38",
    915 	"#39",
    916 	"#40",
    917 	"#41",
    918 	"#42",
    919 	"#43",
    920 	"#44",
    921 	"#45",
    922 	"#46",
    923 	"#47",
    924 	"#48",
    925 	"#49",
    926 	"#50",
    927 	"#51",
    928 	"#52",
    929 	"#53",
    930 	"#54",
    931 	"#55",
    932 	"#56",
    933 	"#57",
    934 	"#58",
    935 	"#59",
    936 	"#60",
    937 	"#61",
    938 	"#62",
    939 	"#63",
    940 	"#64",
    941 	"#65",
    942 	"#66",
    943 	"#67",
    944 	"#68",
    945 	"#69",
    946 	"#70",
    947 	"#71",
    948 	"#72",
    949 	"#73",
    950 	"#74",
    951 	"#75",
    952 	"#76",
    953 	"#77",
    954 	"#78",
    955 	"#79",
    956 	"#80",
    957 	"#81",
    958 	"#82",
    959 	"#83",
    960 	"#84",
    961 	"#85",
    962 	"#86",
    963 	"#87",
    964 	"#88",
    965 	"#89",
    966 	"#80",
    967 	"#91",
    968 	"#92",
    969 	"#93",
    970 	"#94",
    971 	"#95",
    972 	"#96",
    973 	"#97",
    974 	"#98",
    975 	"#99",
    976 	"#100",
    977 	"#101",
    978 	"#102",
    979 	"#103",
    980 	"#104",
    981 	"#105",
    982 	"#106",
    983 	"#107",
    984 	"#108",
    985 	"#109",
    986 	"#110",
    987 	"#111",
    988 	"#112",
    989 	"#113",
    990 	"#114",
    991 	"#115",
    992 	"#116",
    993 	"#117",
    994 	"#118",
    995 	"#119",
    996 	"#120",
    997 	"#121",
    998 	"#122",
    999 	"#123",
   1000 	"#124",
   1001 	"#125",
   1002 	"#126",
   1003 	"#127",
   1004 	"echo",
   1005 	"echo reply",
   1006 	"multicast listener query",
   1007 	"multicast listener report",
   1008 	"multicast listener done",
   1009 	"router solicitation",
   1010 	"router advertisement",
   1011 	"neighbor solicitation",
   1012 	"neighbor advertisement",
   1013 	"redirect",
   1014 	"router renumbering",
   1015 	"node information request",
   1016 	"node information reply",
   1017 	"#141",
   1018 	"#142",
   1019 	"multicast listener report (v2)",
   1020 	"home agent discovery request",
   1021 	"home agent discovery reply",
   1022 	"mobile prefix solicitation",
   1023 	"mobile prefix advertisement",
   1024 	"#148",
   1025 	"#149",
   1026 	"#150",
   1027 	"multicast router advertisement",
   1028 	"multicast router solicitation",
   1029 	"multicast router termination",
   1030 	"#154",
   1031 	"#155",
   1032 	"#156",
   1033 	"#157",
   1034 	"#158",
   1035 	"#159",
   1036 	"#160",
   1037 	"#161",
   1038 	"#162",
   1039 	"#163",
   1040 	"#164",
   1041 	"#165",
   1042 	"#166",
   1043 	"#167",
   1044 	"#168",
   1045 	"#169",
   1046 	"#170",
   1047 	"#171",
   1048 	"#172",
   1049 	"#173",
   1050 	"#174",
   1051 	"#175",
   1052 	"#176",
   1053 	"#177",
   1054 	"#178",
   1055 	"#179",
   1056 	"#180",
   1057 	"#181",
   1058 	"#182",
   1059 	"#183",
   1060 	"#184",
   1061 	"#185",
   1062 	"#186",
   1063 	"#187",
   1064 	"#188",
   1065 	"#189",
   1066 	"#180",
   1067 	"#191",
   1068 	"#192",
   1069 	"#193",
   1070 	"#194",
   1071 	"#195",
   1072 	"#196",
   1073 	"#197",
   1074 	"#198",
   1075 	"#199",
   1076 	"#200",
   1077 	"#201",
   1078 	"#202",
   1079 	"#203",
   1080 	"#204",
   1081 	"#205",
   1082 	"#206",
   1083 	"#207",
   1084 	"#208",
   1085 	"#209",
   1086 	"#210",
   1087 	"#211",
   1088 	"#212",
   1089 	"#213",
   1090 	"#214",
   1091 	"#215",
   1092 	"#216",
   1093 	"#217",
   1094 	"#218",
   1095 	"#219",
   1096 	"#220",
   1097 	"#221",
   1098 	"#222",
   1099 	"#223",
   1100 	"#224",
   1101 	"#225",
   1102 	"#226",
   1103 	"#227",
   1104 	"#228",
   1105 	"#229",
   1106 	"#230",
   1107 	"#231",
   1108 	"#232",
   1109 	"#233",
   1110 	"#234",
   1111 	"#235",
   1112 	"#236",
   1113 	"#237",
   1114 	"#238",
   1115 	"#239",
   1116 	"#240",
   1117 	"#241",
   1118 	"#242",
   1119 	"#243",
   1120 	"#244",
   1121 	"#245",
   1122 	"#246",
   1123 	"#247",
   1124 	"#248",
   1125 	"#249",
   1126 	"#250",
   1127 	"#251",
   1128 	"#252",
   1129 	"#253",
   1130 	"#254",
   1131 	"#255"
   1132 };
   1133 
   1134 /*
   1135  * Dump ICMPv6 statistics.
   1136  */
   1137 void
   1138 icmp6_stats(u_long off, const char *name)
   1139 {
   1140 	uint64_t icmp6stat[ICMP6_NSTATS];
   1141 	int i, first;
   1142 
   1143 	if (use_sysctl) {
   1144 		size_t size = sizeof(icmp6stat);
   1145 
   1146 		if (prog_sysctlbyname("net.inet6.icmp6.stats", icmp6stat,
   1147 		    &size, NULL, 0) == -1)
   1148 			return;
   1149 	} else {
   1150 		warnx("%s stats not available via KVM.", name);
   1151 		return;
   1152 	}
   1153 
   1154 	printf("%s:\n", name);
   1155 
   1156 #define	p(f, m) if (icmp6stat[f] || sflag <= 1)			\
   1157 		printf(m, (unsigned long long)icmp6stat[f],	\
   1158 		    plural(icmp6stat[f]))
   1159 #define p_oerr(f, m) if (icmp6stat[ICMP6_STAT_OUTERRHIST + f] || sflag <= 1) \
   1160 		printf(m,						     \
   1161 		    (unsigned long long)icmp6stat[ICMP6_STAT_OUTERRHIST + f])
   1162 
   1163 	p(ICMP6_STAT_ERROR, "\t%llu call%s to icmp6_error\n");
   1164 	p(ICMP6_STAT_CANTERROR,
   1165 	    "\t%llu error%s not generated because old message was icmp6 or so\n");
   1166 	p(ICMP6_STAT_TOOFREQ,
   1167 	    "\t%llu error%s not generated because of rate limitation\n");
   1168 	for (first = 1, i = 0; i < 256; i++)
   1169 		if (icmp6stat[ICMP6_STAT_OUTHIST + i] != 0) {
   1170 			if (first) {
   1171 				printf("\tOutput packet histogram:\n");
   1172 				first = 0;
   1173 			}
   1174 			printf("\t\t%s: %llu\n", icmp6names[i],
   1175 			 (unsigned long long)icmp6stat[ICMP6_STAT_OUTHIST + i]);
   1176 		}
   1177 	p(ICMP6_STAT_BADCODE, "\t%llu message%s with bad code fields\n");
   1178 	p(ICMP6_STAT_TOOSHORT, "\t%llu message%s < minimum length\n");
   1179 	p(ICMP6_STAT_CHECKSUM, "\t%llu bad checksum%s\n");
   1180 	p(ICMP6_STAT_BADLEN, "\t%llu message%s with bad length\n");
   1181 	for (first = 1, i = 0; i < ICMP6_MAXTYPE; i++)
   1182 		if (icmp6stat[ICMP6_STAT_INHIST + i] != 0) {
   1183 			if (first) {
   1184 				printf("\tInput packet histogram:\n");
   1185 				first = 0;
   1186 			}
   1187 			printf("\t\t%s: %llu\n", icmp6names[i],
   1188 			  (unsigned long long)icmp6stat[ICMP6_STAT_INHIST + i]);
   1189 		}
   1190 	printf("\tHistogram of error messages to be generated:\n");
   1191 	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_NOROUTE, "\t\t%llu no route\n");
   1192 	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_ADMIN,
   1193 	    "\t\t%llu administratively prohibited\n");
   1194 	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_BEYONDSCOPE,
   1195 	    "\t\t%llu beyond scope\n");
   1196 	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_ADDR,
   1197 	    "\t\t%llu address unreachable\n");
   1198 	p_oerr(ICMP6_ERRSTAT_DST_UNREACH_NOPORT,
   1199 	    "\t\t%llu port unreachable\n");
   1200 	p_oerr(ICMP6_ERRSTAT_PACKET_TOO_BIG, "\t\t%llu packet too big\n");
   1201 	p_oerr(ICMP6_ERRSTAT_TIME_EXCEED_TRANSIT,
   1202 	    "\t\t%llu time exceed transit\n");
   1203 	p_oerr(ICMP6_ERRSTAT_TIME_EXCEED_REASSEMBLY,
   1204 	    "\t\t%llu time exceed reassembly\n");
   1205 	p_oerr(ICMP6_ERRSTAT_PARAMPROB_HEADER,
   1206 	    "\t\t%llu erroneous header field\n");
   1207 	p_oerr(ICMP6_ERRSTAT_PARAMPROB_NEXTHEADER,
   1208 	    "\t\t%llu unrecognized next header\n");
   1209 	p_oerr(ICMP6_ERRSTAT_PARAMPROB_OPTION,
   1210 	    "\t\t%llu unrecognized option\n");
   1211 	p_oerr(ICMP6_ERRSTAT_REDIRECT, "\t\t%llu redirect\n");
   1212 	p_oerr(ICMP6_ERRSTAT_UNKNOWN, "\t\t%llu unknown\n");
   1213 
   1214 	p(ICMP6_STAT_REFLECT, "\t%llu message response%s generated\n");
   1215 	p(ICMP6_STAT_ND_TOOMANYOPT,
   1216 	    "\t%llu message%s with too many ND options\n");
   1217 	p(ICMP6_STAT_ND_BADOPT, "\t%llu message%s with bad ND options\n");
   1218 	p(ICMP6_STAT_BADNS, "\t%llu bad neighbor solicitation message%s\n");
   1219 	p(ICMP6_STAT_BADNA, "\t%llu bad neighbor advertisement message%s\n");
   1220 	p(ICMP6_STAT_BADRS, "\t%llu bad router solicitation message%s\n");
   1221 	p(ICMP6_STAT_BADRA, "\t%llu bad router advertisement message%s\n");
   1222 	p(ICMP6_STAT_DROPPED_RAROUTE,
   1223 	    "\t%llu router advertisement route%s dropped\n");
   1224 	p(ICMP6_STAT_BADREDIRECT, "\t%llu bad redirect message%s\n");
   1225 	p(ICMP6_STAT_PMTUCHG, "\t%llu path MTU change%s\n");
   1226 #undef p
   1227 #undef p_oerr
   1228 }
   1229 
   1230 /*
   1231  * Dump ICMPv6 per-interface statistics based on RFC 2466.
   1232  */
   1233 void
   1234 icmp6_ifstats(const char *ifname)
   1235 {
   1236 	struct in6_ifreq ifr;
   1237 	int s;
   1238 #define	p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1)	      \
   1239 		printf(m, (unsigned long long)ifr.ifr_ifru.ifru_icmp6stat.f,  \
   1240 		    plural(ifr.ifr_ifru.ifru_icmp6stat.f))
   1241 
   1242 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
   1243 		perror("Warning: socket(AF_INET6)");
   1244 		return;
   1245 	}
   1246 
   1247 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
   1248 	printf("icmp6 on %s:\n", ifname);
   1249 
   1250 	if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
   1251 		perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
   1252 		goto end;
   1253 	}
   1254 
   1255 	p(ifs6_in_msg, "\t%llu total input message%s\n");
   1256 	p(ifs6_in_error, "\t%llu total input error message%s\n");
   1257 	p(ifs6_in_dstunreach,
   1258 	    "\t%llu input destination unreachable error%s\n");
   1259 	p(ifs6_in_adminprohib,
   1260 	    "\t%llu input administratively prohibited error%s\n");
   1261 	p(ifs6_in_timeexceed, "\t%llu input time exceeded error%s\n");
   1262 	p(ifs6_in_paramprob, "\t%llu input parameter problem error%s\n");
   1263 	p(ifs6_in_pkttoobig, "\t%llu input packet too big error%s\n");
   1264 	p(ifs6_in_echo, "\t%llu input echo request%s\n");
   1265 	p(ifs6_in_echoreply, "\t%llu input echo reply%s\n");
   1266 	p(ifs6_in_routersolicit, "\t%llu input router solicitation%s\n");
   1267 	p(ifs6_in_routeradvert, "\t%llu input router advertisement%s\n");
   1268 	p(ifs6_in_neighborsolicit, "\t%llu input neighbor solicitation%s\n");
   1269 	p(ifs6_in_neighboradvert, "\t%llu input neighbor advertisement%s\n");
   1270 	p(ifs6_in_redirect, "\t%llu input redirect%s\n");
   1271 	p(ifs6_in_mldquery, "\t%llu input MLD query%s\n");
   1272 	p(ifs6_in_mldreport, "\t%llu input MLD report%s\n");
   1273 	p(ifs6_in_mlddone, "\t%llu input MLD done%s\n");
   1274 
   1275 	p(ifs6_out_msg, "\t%llu total output message%s\n");
   1276 	p(ifs6_out_error, "\t%llu total output error message%s\n");
   1277 	p(ifs6_out_dstunreach,
   1278 	    "\t%llu output destination unreachable error%s\n");
   1279 	p(ifs6_out_adminprohib,
   1280 	    "\t%llu output administratively prohibited error%s\n");
   1281 	p(ifs6_out_timeexceed, "\t%llu output time exceeded error%s\n");
   1282 	p(ifs6_out_paramprob, "\t%llu output parameter problem error%s\n");
   1283 	p(ifs6_out_pkttoobig, "\t%llu output packet too big error%s\n");
   1284 	p(ifs6_out_echo, "\t%llu output echo request%s\n");
   1285 	p(ifs6_out_echoreply, "\t%llu output echo reply%s\n");
   1286 	p(ifs6_out_routersolicit, "\t%llu output router solicitation%s\n");
   1287 	p(ifs6_out_routeradvert, "\t%llu output router advertisement%s\n");
   1288 	p(ifs6_out_neighborsolicit, "\t%llu output neighbor solicitation%s\n");
   1289 	p(ifs6_out_neighboradvert, "\t%llu output neighbor advertisement%s\n");
   1290 	p(ifs6_out_redirect, "\t%llu output redirect%s\n");
   1291 	p(ifs6_out_mldquery, "\t%llu output MLD query%s\n");
   1292 	p(ifs6_out_mldreport, "\t%llu output MLD report%s\n");
   1293 	p(ifs6_out_mlddone, "\t%llu output MLD done%s\n");
   1294 
   1295   end:
   1296 	close(s);
   1297 #undef p
   1298 }
   1299 
   1300 /*
   1301  * Dump PIM statistics structure.
   1302  */
   1303 void
   1304 pim6_stats(u_long off, const char *name)
   1305 {
   1306 	uint64_t pim6stat[PIM6_NSTATS];
   1307 
   1308 	if (use_sysctl) {
   1309 		size_t size = sizeof(pim6stat);
   1310 
   1311 		if (prog_sysctlbyname("net.inet6.pim6.stats", pim6stat, &size,
   1312 		    NULL, 0) == -1)
   1313 			return;
   1314 	} else {
   1315 		warnx("%s stats not available via KVM.", name);
   1316 		return;
   1317 	}
   1318 	printf("%s:\n", name);
   1319 
   1320 #define	p(f, m) if (pim6stat[f] || sflag <= 1)				      \
   1321 		printf(m, (unsigned long long)pim6stat[f], plural(pim6stat[f]))
   1322 
   1323 	p(PIM6_STAT_RCV_TOTAL, "\t%llu message%s received\n");
   1324 	p(PIM6_STAT_RCV_TOOSHORT,
   1325 	    "\t%llu message%s received with too few bytes\n");
   1326 	p(PIM6_STAT_RCV_BADSUM,
   1327 	    "\t%llu message%s received with bad checksum\n");
   1328 	p(PIM6_STAT_RCV_BADVERSION,
   1329 	    "\t%llu message%s received with bad version\n");
   1330 	p(PIM6_STAT_RCV_REGISTERS, "\t%llu register%s received\n");
   1331 	p(PIM6_STAT_RCV_BADREGISTERS, "\t%llu bad register%s received\n");
   1332 	p(PIM6_STAT_SND_REGISTERS, "\t%llu register%s sent\n");
   1333 #undef p
   1334 }
   1335 
   1336 /*
   1337  * Dump raw ip6 statistics structure.
   1338  */
   1339 void
   1340 rip6_stats(u_long off, const char *name)
   1341 {
   1342 	uint64_t rip6stat[RIP6_NSTATS];
   1343 	u_quad_t delivered;
   1344 
   1345 	if (use_sysctl) {
   1346 		size_t size = sizeof(rip6stat);
   1347 
   1348 		if (prog_sysctlbyname("net.inet6.raw6.stats", rip6stat, &size,
   1349 		    NULL, 0) == -1)
   1350 			return;
   1351 	} else {
   1352 		warnx("%s stats not available via KVM.", name);
   1353 		return;
   1354 	}
   1355 	printf("%s:\n", name);
   1356 
   1357 #define	p(f, m) if (rip6stat[f] || sflag <= 1) \
   1358     printf(m, (unsigned long long)rip6stat[f], plural(rip6stat[f]))
   1359 	p(RIP6_STAT_IPACKETS, "\t%llu message%s received\n");
   1360 	p(RIP6_STAT_ISUM, "\t%llu checksum calculation%s on inbound\n");
   1361 	p(RIP6_STAT_BADSUM, "\t%llu message%s with bad checksum\n");
   1362 	p(RIP6_STAT_NOSOCK, "\t%llu message%s dropped due to no socket\n");
   1363 	p(RIP6_STAT_NOSOCKMCAST,
   1364 	    "\t%llu multicast message%s dropped due to no socket\n");
   1365 	p(RIP6_STAT_FULLSOCK,
   1366 	    "\t%llu message%s dropped due to full socket buffers\n");
   1367 	delivered = rip6stat[RIP6_STAT_IPACKETS] -
   1368 		    rip6stat[RIP6_STAT_BADSUM] -
   1369 		    rip6stat[RIP6_STAT_NOSOCK] -
   1370 		    rip6stat[RIP6_STAT_NOSOCKMCAST] -
   1371 		    rip6stat[RIP6_STAT_FULLSOCK];
   1372 	if (delivered || sflag <= 1)
   1373 		printf("\t%llu delivered\n", (unsigned long long)delivered);
   1374 	p(RIP6_STAT_OPACKETS, "\t%llu datagram%s output\n");
   1375 #undef p
   1376 }
   1377 
   1378 /*
   1379  * Pretty print an Internet address (net address + port).
   1380  * Take numeric_addr and numeric_port into consideration.
   1381  */
   1382 void
   1383 inet6print(const struct in6_addr *in6, int port, const char *proto)
   1384 {
   1385 #define GETSERVBYPORT6(port, proto, ret)				\
   1386 	do {								\
   1387 		if (strcmp((proto), "tcp6") == 0)			\
   1388 			(ret) = getservbyport((int)(port), "tcp");	\
   1389 		else if (strcmp((proto), "udp6") == 0)			\
   1390 			(ret) = getservbyport((int)(port), "udp");	\
   1391 		else							\
   1392 			(ret) = getservbyport((int)(port), (proto));	\
   1393 	} while (0)
   1394 
   1395 	struct servent *sp = 0;
   1396 	char line[80], *cp;
   1397 	int lwidth;
   1398 
   1399 	lwidth = Aflag ? 12 : 16;
   1400 	if (vflag && lwidth < (int)strlen(inet6name(in6)))
   1401 		lwidth = strlen(inet6name(in6));
   1402 	snprintf(line, sizeof(line), "%.*s.", lwidth, inet6name(in6));
   1403 	cp = strchr(line, '\0');
   1404 	if (!numeric_port && port)
   1405 		GETSERVBYPORT6(port, proto, sp);
   1406 	if (sp || port == 0)
   1407 		snprintf(cp, sizeof(line) - (cp - line),
   1408 		    "%s", sp ? sp->s_name : "*");
   1409 	else
   1410 		snprintf(cp, sizeof(line) - (cp - line),
   1411 		    "%d", ntohs((u_short)port));
   1412 	lwidth = Aflag ? 18 : 22;
   1413 	if (vflag && lwidth < (int)strlen(line))
   1414 		lwidth = strlen(line);
   1415 	printf(" %-*.*s", lwidth, lwidth, line);
   1416 }
   1417 
   1418 /*
   1419  * Construct an Internet address representation.
   1420  * If the numeric_addr has been supplied, give
   1421  * numeric value, otherwise try for symbolic name.
   1422  */
   1423 
   1424 char *
   1425 inet6name(const struct in6_addr *in6p)
   1426 {
   1427 	char *cp;
   1428 	static char line[NI_MAXHOST];
   1429 	struct hostent *hp;
   1430 	static char domain[MAXHOSTNAMELEN + 1];
   1431 	static int first = 1;
   1432 	char hbuf[NI_MAXHOST];
   1433 	struct sockaddr_in6 sin6;
   1434 	const int niflag = NI_NUMERICHOST;
   1435 
   1436 	if (first && !numeric_addr) {
   1437 		first = 0;
   1438 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
   1439 		    (cp = strchr(domain, '.')))
   1440 			(void) strlcpy(domain, cp + 1, sizeof(domain));
   1441 		else
   1442 			domain[0] = 0;
   1443 	}
   1444 	cp = 0;
   1445 	if (!numeric_addr && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
   1446 		hp = gethostbyaddr((const char *)in6p, sizeof(*in6p), AF_INET6);
   1447 		if (hp) {
   1448 			if ((cp = strchr(hp->h_name, '.')) &&
   1449 			    !strcmp(cp + 1, domain))
   1450 				*cp = 0;
   1451 			cp = hp->h_name;
   1452 		}
   1453 	}
   1454 	if (IN6_IS_ADDR_UNSPECIFIED(in6p))
   1455 		strlcpy(line, "*", sizeof(line));
   1456 	else if (cp)
   1457 		strlcpy(line, cp, sizeof(line));
   1458 	else {
   1459 		memset(&sin6, 0, sizeof(sin6));
   1460 		sin6.sin6_len = sizeof(sin6);
   1461 		sin6.sin6_family = AF_INET6;
   1462 		sin6.sin6_addr = *in6p;
   1463 		inet6_getscopeid(&sin6,
   1464 		    INET6_IS_ADDR_LINKLOCAL | INET6_IS_ADDR_MC_LINKLOCAL);
   1465 		if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
   1466 				hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
   1467 			strlcpy(hbuf, "?", sizeof(hbuf));
   1468 		strlcpy(line, hbuf, sizeof(line));
   1469 	}
   1470 	return line;
   1471 }
   1472 
   1473 /*
   1474  * Dump the contents of a TCP6 PCB.
   1475  */
   1476 void
   1477 tcp6_dump(u_long off, const char *name, u_long pcbaddr)
   1478 {
   1479 	callout_impl_t *ci;
   1480 	int i, hardticks;
   1481 	struct kinfo_pcb *pcblist;
   1482 #ifdef TCP6
   1483 #define mypcb tcp6cb
   1484 #else
   1485 #define mypcb tcpcb
   1486 #endif
   1487 	size_t j, len;
   1488 
   1489 	if (use_sysctl)
   1490 		pcblist = getpcblist_sysctl(name, &len);
   1491 	else
   1492 		pcblist = getpcblist_kmem(off, name, &len);
   1493 
   1494 	for (j = 0; j < len; j++)
   1495 		if (pcblist[j].ki_ppcbaddr == pcbaddr)
   1496 			break;
   1497 	free(pcblist);
   1498 
   1499 	if (j == len)
   1500 		errx(1, "0x%lx is not a valid pcb address", pcbaddr);
   1501 
   1502 	kread(pcbaddr, (char *)&mypcb, sizeof(mypcb));
   1503 	hardticks = get_hardticks();
   1504 
   1505 	printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
   1506 	printf("Timers:\n");
   1507 	for (i = 0; i < TCP6T_NTIMERS; i++) {
   1508 		char buf[128];
   1509 		ci = (callout_impl_t *)&tcpcb.t_timer[i];
   1510 		snprintb(buf, sizeof(buf), CALLOUT_FMT, ci->c_flags);
   1511 		printf("\t%s\t%s", tcptimers[i], buf);
   1512 		if (ci->c_flags & CALLOUT_PENDING)
   1513 			printf("\t%d\n", ci->c_time - hardticks);
   1514 		else
   1515 			printf("\n");
   1516 	}
   1517 	printf("\n\n");
   1518 
   1519 	if (mypcb.t_state < 0 || mypcb.t_state >= TCP6_NSTATES)
   1520 		printf("State: %d", mypcb.t_state);
   1521 	else
   1522 		printf("State: %s", tcp6states[mypcb.t_state]);
   1523 	printf(", flags 0x%x, in6pcb 0x%lx\n\n", mypcb.t_flags,
   1524 	    (u_long)mypcb.t_in6pcb);
   1525 
   1526 	printf("rxtshift %d, rxtcur %d, dupacks %d\n", mypcb.t_rxtshift,
   1527 	    mypcb.t_rxtcur, mypcb.t_dupacks);
   1528 #ifdef TCP6
   1529 	printf("peermaxseg %u, maxseg %u, force %d\n\n", mypcb.t_peermaxseg,
   1530 	    mypcb.t_maxseg, mypcb.t_force);
   1531 #else
   1532 	printf("peermss %u, ourmss %u, segsz %u, segqlen %u\n\n",
   1533 	    tcpcb.t_peermss, tcpcb.t_ourmss, tcpcb.t_segsz, tcpcb.t_segqlen);
   1534 #endif
   1535 
   1536 	printf("snd_una %u, snd_nxt %u, snd_up %u\n",
   1537 	    mypcb.snd_una, mypcb.snd_nxt, mypcb.snd_up);
   1538 	printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %llu\n\n",
   1539 	    mypcb.snd_wl1, mypcb.snd_wl2, mypcb.iss,
   1540 	    (unsigned long long)mypcb.snd_wnd);
   1541 
   1542 	printf("rcv_wnd %llu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
   1543 	    (unsigned long long)mypcb.rcv_wnd, mypcb.rcv_nxt,
   1544 	    mypcb.rcv_up, mypcb.irs);
   1545 
   1546 	printf("rcv_adv %u, snd_max %u, snd_cwnd %llu, snd_ssthresh %llu\n",
   1547 	    mypcb.rcv_adv, mypcb.snd_max, (unsigned long long)mypcb.snd_cwnd,
   1548 	    (unsigned long long)mypcb.snd_ssthresh);
   1549 
   1550 #ifdef TCP6
   1551 	printf("idle %d, rtt %d, " mypcb.t_idle, mypcb.t_rtt);
   1552 #else
   1553 	printf("rcvtime %u, rtttime %u, ", tcpcb.t_rcvtime, tcpcb.t_rtttime);
   1554 #endif
   1555 
   1556 	printf("rtseq %u, srtt %d, rttvar %d, rttmin %d, "
   1557 	    "max_sndwnd %llu\n\n", mypcb.t_rtseq,
   1558 	    mypcb.t_srtt, mypcb.t_rttvar, mypcb.t_rttmin,
   1559 	    (unsigned long long)mypcb.max_sndwnd);
   1560 
   1561 	printf("oobflags %d, iobc %d, softerror %d\n\n", mypcb.t_oobflags,
   1562 	    mypcb.t_iobc, mypcb.t_softerror);
   1563 
   1564 	printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
   1565 	    mypcb.snd_scale, mypcb.rcv_scale, mypcb.request_r_scale,
   1566 	    mypcb.requested_s_scale);
   1567 	printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
   1568 	    mypcb.ts_recent, mypcb.ts_recent_age, mypcb.last_ack_sent);
   1569 }
   1570 
   1571 #endif /*INET6*/
   1572