Home | History | Annotate | Download | only in genunix
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <mdb/mdb_modapi.h>
     27 #include <mdb/mdb_ks.h>
     28 #include <mdb/mdb_ctf.h>
     29 #include <sys/types.h>
     30 #include <sys/tihdr.h>
     31 #include <inet/led.h>
     32 #include <inet/common.h>
     33 #include <netinet/in.h>
     34 #include <netinet/ip6.h>
     35 #include <netinet/icmp6.h>
     36 #include <inet/ip.h>
     37 #include <inet/ip6.h>
     38 #include <inet/ipclassifier.h>
     39 #include <inet/tcp.h>
     40 #include <sys/stream.h>
     41 #include <sys/vfs.h>
     42 #include <sys/stropts.h>
     43 #include <sys/tpicommon.h>
     44 #include <sys/socket.h>
     45 #include <sys/socketvar.h>
     46 #include <sys/cred_impl.h>
     47 #include <inet/udp_impl.h>
     48 #include <inet/arp_impl.h>
     49 #include <inet/rawip_impl.h>
     50 #include <inet/mi.h>
     51 #include <fs/sockfs/socktpi_impl.h>
     52 #include <net/bridge_impl.h>
     53 #include <io/trill_impl.h>
     54 #include <sys/mac_impl.h>
     55 
     56 #define	ADDR_V6_WIDTH	23
     57 #define	ADDR_V4_WIDTH	15
     58 
     59 #define	NETSTAT_ALL	0x01
     60 #define	NETSTAT_VERBOSE	0x02
     61 #define	NETSTAT_ROUTE	0x04
     62 #define	NETSTAT_V4	0x08
     63 #define	NETSTAT_V6	0x10
     64 #define	NETSTAT_UNIX	0x20
     65 
     66 #define	NETSTAT_FIRST	0x80000000u
     67 
     68 typedef struct netstat_cb_data_s {
     69 	uint_t	opts;
     70 	conn_t	conn;
     71 	int	af;
     72 } netstat_cb_data_t;
     73 
     74 /* Walkers for various *_stack_t */
     75 int
     76 ar_stacks_walk_init(mdb_walk_state_t *wsp)
     77 {
     78 	if (mdb_layered_walk("netstack", wsp) == -1) {
     79 		mdb_warn("can't walk 'netstack'");
     80 		return (WALK_ERR);
     81 	}
     82 	return (WALK_NEXT);
     83 }
     84 
     85 int
     86 ar_stacks_walk_step(mdb_walk_state_t *wsp)
     87 {
     88 	uintptr_t kaddr;
     89 	netstack_t nss;
     90 
     91 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
     92 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
     93 		return (WALK_ERR);
     94 	}
     95 	kaddr = (uintptr_t)nss.netstack_modules[NS_ARP];
     96 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
     97 }
     98 
     99 int
    100 icmp_stacks_walk_init(mdb_walk_state_t *wsp)
    101 {
    102 	if (mdb_layered_walk("netstack", wsp) == -1) {
    103 		mdb_warn("can't walk 'netstack'");
    104 		return (WALK_ERR);
    105 	}
    106 	return (WALK_NEXT);
    107 }
    108 
    109 int
    110 icmp_stacks_walk_step(mdb_walk_state_t *wsp)
    111 {
    112 	uintptr_t kaddr;
    113 	netstack_t nss;
    114 
    115 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
    116 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
    117 		return (WALK_ERR);
    118 	}
    119 	kaddr = (uintptr_t)nss.netstack_modules[NS_ICMP];
    120 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
    121 }
    122 
    123 int
    124 tcp_stacks_walk_init(mdb_walk_state_t *wsp)
    125 {
    126 	if (mdb_layered_walk("netstack", wsp) == -1) {
    127 		mdb_warn("can't walk 'netstack'");
    128 		return (WALK_ERR);
    129 	}
    130 	return (WALK_NEXT);
    131 }
    132 
    133 int
    134 tcp_stacks_walk_step(mdb_walk_state_t *wsp)
    135 {
    136 	uintptr_t kaddr;
    137 	netstack_t nss;
    138 
    139 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
    140 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
    141 		return (WALK_ERR);
    142 	}
    143 	kaddr = (uintptr_t)nss.netstack_modules[NS_TCP];
    144 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
    145 }
    146 
    147 int
    148 udp_stacks_walk_init(mdb_walk_state_t *wsp)
    149 {
    150 	if (mdb_layered_walk("netstack", wsp) == -1) {
    151 		mdb_warn("can't walk 'netstack'");
    152 		return (WALK_ERR);
    153 	}
    154 	return (WALK_NEXT);
    155 }
    156 
    157 int
    158 udp_stacks_walk_step(mdb_walk_state_t *wsp)
    159 {
    160 	uintptr_t kaddr;
    161 	netstack_t nss;
    162 
    163 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
    164 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
    165 		return (WALK_ERR);
    166 	}
    167 	kaddr = (uintptr_t)nss.netstack_modules[NS_UDP];
    168 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
    169 }
    170 
    171 /*
    172  * Print an IPv4 address and port number in a compact and easy to read format
    173  * The arguments are in network byte order
    174  */
    175 static void
    176 net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport)
    177 {
    178 	uint32_t naddr = V4_PART_OF_V6((*nipv6addr));
    179 
    180 	mdb_nhconvert(&nport, &nport, sizeof (nport));
    181 	mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport);
    182 }
    183 
    184 /*
    185  * Print an IPv6 address and port number in a compact and easy to read format
    186  * The arguments are in network byte order
    187  */
    188 static void
    189 net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport)
    190 {
    191 	mdb_nhconvert(&nport, &nport, sizeof (nport));
    192 	mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport);
    193 }
    194 
    195 static int
    196 net_tcp_active(const tcp_t *tcp)
    197 {
    198 	return (tcp->tcp_state >= TCPS_ESTABLISHED);
    199 }
    200 
    201 static int
    202 net_tcp_ipv4(const tcp_t *tcp)
    203 {
    204 	return ((tcp->tcp_ipversion == IPV4_VERSION) ||
    205 	    (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_ip_src_v6) &&
    206 	    (tcp->tcp_state <= TCPS_LISTEN)));
    207 }
    208 
    209 static int
    210 net_tcp_ipv6(const tcp_t *tcp)
    211 {
    212 	return (tcp->tcp_ipversion == IPV6_VERSION);
    213 }
    214 
    215 static int
    216 net_udp_active(const udp_t *udp)
    217 {
    218 	return ((udp->udp_state == TS_IDLE) ||
    219 	    (udp->udp_state == TS_DATA_XFER));
    220 }
    221 
    222 static int
    223 net_udp_ipv4(const udp_t *udp)
    224 {
    225 	return ((udp->udp_ipversion == IPV4_VERSION) ||
    226 	    (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src) &&
    227 	    (udp->udp_state <= TS_IDLE)));
    228 }
    229 
    230 static int
    231 net_udp_ipv6(const udp_t *udp)
    232 {
    233 	return (udp->udp_ipversion == IPV6_VERSION);
    234 }
    235 
    236 int
    237 sonode_walk_init(mdb_walk_state_t *wsp)
    238 {
    239 	if (wsp->walk_addr == NULL) {
    240 		GElf_Sym sym;
    241 		struct socklist *slp;
    242 
    243 		if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) {
    244 			mdb_warn("failed to lookup sockfs`socklist");
    245 			return (WALK_ERR);
    246 		}
    247 
    248 		slp = (struct socklist *)(uintptr_t)sym.st_value;
    249 
    250 		if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),
    251 		    (uintptr_t)&slp->sl_list) == -1) {
    252 			mdb_warn("failed to read address of initial sonode "
    253 			    "at %p", &slp->sl_list);
    254 			return (WALK_ERR);
    255 		}
    256 	}
    257 
    258 	wsp->walk_data = mdb_alloc(sizeof (struct sotpi_sonode), UM_SLEEP);
    259 	return (WALK_NEXT);
    260 }
    261 
    262 int
    263 sonode_walk_step(mdb_walk_state_t *wsp)
    264 {
    265 	int status;
    266 	struct sotpi_sonode *stp;
    267 
    268 	if (wsp->walk_addr == NULL)
    269 		return (WALK_DONE);
    270 
    271 	if (mdb_vread(wsp->walk_data, sizeof (struct sotpi_sonode),
    272 	    wsp->walk_addr) == -1) {
    273 		mdb_warn("failed to read sonode at %p", wsp->walk_addr);
    274 		return (WALK_ERR);
    275 	}
    276 
    277 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
    278 	    wsp->walk_cbdata);
    279 
    280 	stp = wsp->walk_data;
    281 
    282 	wsp->walk_addr = (uintptr_t)stp->st_info.sti_next_so;
    283 	return (status);
    284 }
    285 
    286 void
    287 sonode_walk_fini(mdb_walk_state_t *wsp)
    288 {
    289 	mdb_free(wsp->walk_data, sizeof (struct sotpi_sonode));
    290 }
    291 
    292 struct mi_walk_data {
    293 	uintptr_t mi_wd_miofirst;
    294 	MI_O mi_wd_miodata;
    295 };
    296 
    297 int
    298 mi_walk_init(mdb_walk_state_t *wsp)
    299 {
    300 	struct mi_walk_data *wdp;
    301 
    302 	if (wsp->walk_addr == NULL) {
    303 		mdb_warn("mi doesn't support global walks\n");
    304 		return (WALK_ERR);
    305 	}
    306 
    307 	wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP);
    308 
    309 	/* So that we do not immediately return WALK_DONE below */
    310 	wdp->mi_wd_miofirst = NULL;
    311 
    312 	wsp->walk_data = wdp;
    313 	return (WALK_NEXT);
    314 }
    315 
    316 int
    317 mi_walk_step(mdb_walk_state_t *wsp)
    318 {
    319 	struct mi_walk_data *wdp = wsp->walk_data;
    320 	MI_OP miop = &wdp->mi_wd_miodata;
    321 	int status;
    322 
    323 	/* Always false in the first iteration */
    324 	if ((wsp->walk_addr == (uintptr_t)NULL) ||
    325 	    (wsp->walk_addr == wdp->mi_wd_miofirst)) {
    326 		return (WALK_DONE);
    327 	}
    328 
    329 	if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) {
    330 		mdb_warn("failed to read MI object at %p", wsp->walk_addr);
    331 		return (WALK_ERR);
    332 	}
    333 
    334 	/* Only true in the first iteration */
    335 	if (wdp->mi_wd_miofirst == NULL) {
    336 		wdp->mi_wd_miofirst = wsp->walk_addr;
    337 		status = WALK_NEXT;
    338 	} else {
    339 		status = wsp->walk_callback(wsp->walk_addr + sizeof (MI_O),
    340 		    &miop[1], wsp->walk_cbdata);
    341 	}
    342 
    343 	wsp->walk_addr = (uintptr_t)miop->mi_o_next;
    344 	return (status);
    345 }
    346 
    347 void
    348 mi_walk_fini(mdb_walk_state_t *wsp)
    349 {
    350 	mdb_free(wsp->walk_data, sizeof (struct mi_walk_data));
    351 }
    352 
    353 typedef struct mi_payload_walk_arg_s {
    354 	const char *mi_pwa_walker;	/* Underlying walker */
    355 	const off_t mi_pwa_head_off;	/* Offset for mi_o_head_t * in stack */
    356 	const size_t mi_pwa_size;	/* size of mi payload */
    357 	const uint_t mi_pwa_flags;	/* device and/or module */
    358 } mi_payload_walk_arg_t;
    359 
    360 #define	MI_PAYLOAD_DEVICE	0x1
    361 #define	MI_PAYLOAD_MODULE	0x2
    362 
    363 int
    364 mi_payload_walk_init(mdb_walk_state_t *wsp)
    365 {
    366 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
    367 
    368 	if (mdb_layered_walk(arg->mi_pwa_walker, wsp) == -1) {
    369 		mdb_warn("can't walk '%s'", arg->mi_pwa_walker);
    370 		return (WALK_ERR);
    371 	}
    372 	return (WALK_NEXT);
    373 }
    374 
    375 int
    376 mi_payload_walk_step(mdb_walk_state_t *wsp)
    377 {
    378 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
    379 	uintptr_t kaddr;
    380 
    381 	kaddr = wsp->walk_addr + arg->mi_pwa_head_off;
    382 
    383 	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
    384 		mdb_warn("can't read address of mi head at %p for %s",
    385 		    kaddr, arg->mi_pwa_walker);
    386 		return (WALK_ERR);
    387 	}
    388 
    389 	if (kaddr == 0) {
    390 		/* Empty list */
    391 		return (WALK_DONE);
    392 	}
    393 
    394 	if (mdb_pwalk("genunix`mi", wsp->walk_callback,
    395 	    wsp->walk_cbdata, kaddr) == -1) {
    396 		mdb_warn("failed to walk genunix`mi");
    397 		return (WALK_ERR);
    398 	}
    399 	return (WALK_NEXT);
    400 }
    401 
    402 const mi_payload_walk_arg_t mi_ar_arg = {
    403 	"ar_stacks", OFFSETOF(arp_stack_t, as_head), sizeof (ar_t),
    404 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
    405 };
    406 
    407 const mi_payload_walk_arg_t mi_icmp_arg = {
    408 	"icmp_stacks", OFFSETOF(icmp_stack_t, is_head), sizeof (icmp_t),
    409 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
    410 };
    411 
    412 int
    413 sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    414 {
    415 	const char *optf = NULL;
    416 	const char *optt = NULL;
    417 	const char *optp = NULL;
    418 	int family, type, proto;
    419 	int filter = 0;
    420 	struct sonode so;
    421 
    422 	if (!(flags & DCMD_ADDRSPEC)) {
    423 		if (mdb_walk_dcmd("genunix`sonode", "genunix`sonode", argc,
    424 		    argv) == -1) {
    425 			mdb_warn("failed to walk sonode");
    426 			return (DCMD_ERR);
    427 		}
    428 
    429 		return (DCMD_OK);
    430 	}
    431 
    432 	if (mdb_getopts(argc, argv,
    433 	    'f', MDB_OPT_STR, &optf,
    434 	    't', MDB_OPT_STR, &optt,
    435 	    'p', MDB_OPT_STR, &optp,
    436 	    NULL) != argc)
    437 		return (DCMD_USAGE);
    438 
    439 	if (optf != NULL) {
    440 		if (strcmp("inet", optf) == 0)
    441 			family = AF_INET;
    442 		else if (strcmp("inet6", optf) == 0)
    443 			family = AF_INET6;
    444 		else if (strcmp("unix", optf) == 0)
    445 			family = AF_UNIX;
    446 		else
    447 			family = mdb_strtoull(optf);
    448 		filter = 1;
    449 	}
    450 
    451 	if (optt != NULL) {
    452 		if (strcmp("stream", optt) == 0)
    453 			type = SOCK_STREAM;
    454 		else if (strcmp("dgram", optt) == 0)
    455 			type = SOCK_DGRAM;
    456 		else if (strcmp("raw", optt) == 0)
    457 			type = SOCK_RAW;
    458 		else
    459 			type = mdb_strtoull(optt);
    460 		filter = 1;
    461 	}
    462 
    463 	if (optp != NULL) {
    464 		proto = mdb_strtoull(optp);
    465 		filter = 1;
    466 	}
    467 
    468 	if (DCMD_HDRSPEC(flags) && !filter) {
    469 		mdb_printf("%<u>%-?s Family Type Proto State Mode Flag "
    470 		    "AccessVP%</u>\n", "Sonode:");
    471 	}
    472 
    473 	if (mdb_vread(&so, sizeof (so), addr) == -1) {
    474 		mdb_warn("failed to read sonode at %p", addr);
    475 		return (DCMD_ERR);
    476 	}
    477 
    478 	if ((optf != NULL) && (so.so_family != family))
    479 		return (DCMD_OK);
    480 
    481 	if ((optt != NULL) && (so.so_type != type))
    482 		return (DCMD_OK);
    483 
    484 	if ((optp != NULL) && (so.so_protocol != proto))
    485 		return (DCMD_OK);
    486 
    487 	if (filter) {
    488 		mdb_printf("%0?p\n", addr);
    489 		return (DCMD_OK);
    490 	}
    491 
    492 	mdb_printf("%0?p ", addr);
    493 
    494 	switch (so.so_family) {
    495 	case AF_UNIX:
    496 		mdb_printf("unix  ");
    497 		break;
    498 	case AF_INET:
    499 		mdb_printf("inet  ");
    500 		break;
    501 	case AF_INET6:
    502 		mdb_printf("inet6 ");
    503 		break;
    504 	default:
    505 		mdb_printf("%6hi", so.so_family);
    506 	}
    507 
    508 	switch (so.so_type) {
    509 	case SOCK_STREAM:
    510 		mdb_printf(" strm");
    511 		break;
    512 	case SOCK_DGRAM:
    513 		mdb_printf(" dgrm");
    514 		break;
    515 	case SOCK_RAW:
    516 		mdb_printf(" raw ");
    517 		break;
    518 	default:
    519 		mdb_printf(" %4hi", so.so_type);
    520 	}
    521 
    522 	mdb_printf(" %5hi %05x %04x %04hx\n",
    523 	    so.so_protocol, so.so_state, so.so_mode,
    524 	    so.so_flag);
    525 
    526 	return (DCMD_OK);
    527 }
    528 
    529 #define	MI_PAYLOAD	0x1
    530 #define	MI_DEVICE	0x2
    531 #define	MI_MODULE	0x4
    532 
    533 int
    534 mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    535 {
    536 	uint_t opts = 0;
    537 	MI_O	mio;
    538 
    539 	if (!(flags & DCMD_ADDRSPEC))
    540 		return (DCMD_USAGE);
    541 
    542 	if (mdb_getopts(argc, argv,
    543 	    'p', MDB_OPT_SETBITS, MI_PAYLOAD, &opts,
    544 	    'd', MDB_OPT_SETBITS, MI_DEVICE, &opts,
    545 	    'm', MDB_OPT_SETBITS, MI_MODULE, &opts,
    546 	    NULL) != argc)
    547 		return (DCMD_USAGE);
    548 
    549 	if ((opts & (MI_DEVICE | MI_MODULE)) == (MI_DEVICE | MI_MODULE)) {
    550 		mdb_warn("at most one filter, d for devices or m "
    551 		    "for modules, may be specified\n");
    552 		return (DCMD_USAGE);
    553 	}
    554 
    555 	if ((opts == 0) && (DCMD_HDRSPEC(flags))) {
    556 		mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n",
    557 		    "MI_O", "Next", "Prev");
    558 	}
    559 
    560 	if (mdb_vread(&mio, sizeof (mio), addr) == -1) {
    561 		mdb_warn("failed to read mi object MI_O at %p", addr);
    562 		return (DCMD_ERR);
    563 	}
    564 
    565 	if (opts != 0) {
    566 		if (mio.mi_o_isdev == B_FALSE) {
    567 			/* mio is a module */
    568 			if (!(opts & MI_MODULE) && (opts & MI_DEVICE))
    569 				return (DCMD_OK);
    570 		} else {
    571 			/* mio is a device */
    572 			if (!(opts & MI_DEVICE) && (opts & MI_MODULE))
    573 				return (DCMD_OK);
    574 		}
    575 
    576 		if (opts & MI_PAYLOAD)
    577 			mdb_printf("%p\n", addr + sizeof (MI_O));
    578 		else
    579 			mdb_printf("%p\n", addr);
    580 		return (DCMD_OK);
    581 	}
    582 
    583 	mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev);
    584 
    585 	if (mio.mi_o_isdev == B_FALSE)
    586 		mdb_printf("FALSE");
    587 	else
    588 		mdb_printf("TRUE ");
    589 
    590 	mdb_printf(" %0?p\n", mio.mi_o_dev);
    591 
    592 	return (DCMD_OK);
    593 }
    594 
    595 static int
    596 ns_to_stackid(uintptr_t kaddr)
    597 {
    598 	netstack_t nss;
    599 
    600 	if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
    601 		mdb_warn("failed to read netstack_t %p", kaddr);
    602 		return (0);
    603 	}
    604 	return (nss.netstack_stackid);
    605 }
    606 
    607 
    608 
    609 static void
    610 netstat_tcp_verbose_pr(const tcp_t *tcp)
    611 {
    612 	mdb_printf("       %5i %08x %08x %5i %08x %08x %5li %5i\n",
    613 	    tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
    614 	    tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
    615 }
    616 
    617 /*ARGSUSED*/
    618 static int
    619 netstat_tcp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
    620 {
    621 	netstat_cb_data_t *ncb = cb_data;
    622 	uint_t opts = ncb->opts;
    623 	int af = ncb->af;
    624 	uintptr_t tcp_kaddr;
    625 	conn_t *connp = &ncb->conn;
    626 	tcp_t tcps, *tcp;
    627 
    628 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
    629 		mdb_warn("failed to read conn_t at %p", kaddr);
    630 		return (WALK_ERR);
    631 	}
    632 
    633 	tcp_kaddr = (uintptr_t)connp->conn_tcp;
    634 	if (mdb_vread(&tcps, sizeof (tcp_t), tcp_kaddr) == -1) {
    635 		mdb_warn("failed to read tcp_t at %p", kaddr);
    636 		return (WALK_ERR);
    637 	}
    638 
    639 	tcp = &tcps;
    640 	connp->conn_tcp = tcp;
    641 	tcp->tcp_connp = connp;
    642 
    643 	if (!((opts & NETSTAT_ALL) || net_tcp_active(tcp)) ||
    644 	    (af == AF_INET && !net_tcp_ipv4(tcp)) ||
    645 	    (af == AF_INET6 && !net_tcp_ipv6(tcp))) {
    646 		return (WALK_NEXT);
    647 	}
    648 
    649 	mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state);
    650 	if (af == AF_INET) {
    651 		net_ipv4addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport);
    652 		mdb_printf(" ");
    653 		net_ipv4addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport);
    654 	} else if (af == AF_INET6) {
    655 		net_ipv6addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport);
    656 		mdb_printf(" ");
    657 		net_ipv6addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport);
    658 	}
    659 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
    660 	mdb_printf(" %4i\n", connp->conn_zoneid);
    661 	if (opts & NETSTAT_VERBOSE)
    662 		netstat_tcp_verbose_pr(tcp);
    663 
    664 	return (WALK_NEXT);
    665 }
    666 
    667 /*ARGSUSED*/
    668 static int
    669 netstat_udp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
    670 {
    671 	netstat_cb_data_t *ncb = cb_data;
    672 	uint_t opts = ncb->opts;
    673 	int af = ncb->af;
    674 	udp_t udp;
    675 	conn_t *connp = &ncb->conn;
    676 	char *state;
    677 
    678 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
    679 		mdb_warn("failed to read conn_t at %p", kaddr);
    680 		return (WALK_ERR);
    681 	}
    682 
    683 	if (mdb_vread(&udp, sizeof (udp_t),
    684 	    (uintptr_t)connp->conn_udp) == -1) {
    685 		mdb_warn("failed to read conn_udp at %p",
    686 		    (uintptr_t)connp->conn_udp);
    687 		return (WALK_ERR);
    688 	}
    689 
    690 	if (!((opts & NETSTAT_ALL) || net_udp_active(&udp)) ||
    691 	    (af == AF_INET && !net_udp_ipv4(&udp)) ||
    692 	    (af == AF_INET6 && !net_udp_ipv6(&udp))) {
    693 		return (WALK_NEXT);
    694 	}
    695 
    696 	if (udp.udp_state == TS_UNBND)
    697 		state = "UNBOUND";
    698 	else if (udp.udp_state == TS_IDLE)
    699 		state = "IDLE";
    700 	else if (udp.udp_state == TS_DATA_XFER)
    701 		state = "CONNECTED";
    702 	else
    703 		state = "UNKNOWN";
    704 
    705 	mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_udp, state);
    706 	if (af == AF_INET) {
    707 		net_ipv4addrport_pr(&udp.udp_v6src, udp.udp_port);
    708 		mdb_printf(" ");
    709 		net_ipv4addrport_pr(&udp.udp_v6dst, udp.udp_dstport);
    710 	} else if (af == AF_INET6) {
    711 		net_ipv6addrport_pr(&udp.udp_v6src, udp.udp_port);
    712 		mdb_printf(" ");
    713 		net_ipv6addrport_pr(&udp.udp_v6dst, udp.udp_dstport);
    714 	}
    715 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
    716 	mdb_printf(" %4i\n", connp->conn_zoneid);
    717 
    718 	return (WALK_NEXT);
    719 }
    720 
    721 /*ARGSUSED*/
    722 static int
    723 netstat_icmp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
    724 {
    725 	netstat_cb_data_t *ncb = cb_data;
    726 	int af = ncb->af;
    727 	icmp_t icmp;
    728 	conn_t *connp = &ncb->conn;
    729 	char *state;
    730 
    731 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
    732 		mdb_warn("failed to read conn_t at %p", kaddr);
    733 		return (WALK_ERR);
    734 	}
    735 
    736 	if (mdb_vread(&icmp, sizeof (icmp_t),
    737 	    (uintptr_t)connp->conn_icmp) == -1) {
    738 		mdb_warn("failed to read conn_icmp at %p",
    739 		    (uintptr_t)connp->conn_icmp);
    740 		return (WALK_ERR);
    741 	}
    742 
    743 	if ((af == AF_INET && icmp.icmp_ipversion != IPV4_VERSION) ||
    744 	    (af == AF_INET6 && icmp.icmp_ipversion != IPV6_VERSION)) {
    745 		return (WALK_NEXT);
    746 	}
    747 
    748 	if (icmp.icmp_state == TS_UNBND)
    749 		state = "UNBOUND";
    750 	else if (icmp.icmp_state == TS_IDLE)
    751 		state = "IDLE";
    752 	else if (icmp.icmp_state == TS_DATA_XFER)
    753 		state = "CONNECTED";
    754 	else
    755 		state = "UNKNOWN";
    756 
    757 	mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_icmp, state);
    758 	if (af == AF_INET) {
    759 		mdb_printf("%*I ", ADDR_V4_WIDTH,
    760 		    V4_PART_OF_V6((icmp.icmp_v6src)));
    761 		mdb_printf("%*I ", ADDR_V4_WIDTH,
    762 		    V4_PART_OF_V6((icmp.icmp_v6dst.sin6_addr)));
    763 	} else if (af == AF_INET6) {
    764 		mdb_printf("%*N ", ADDR_V6_WIDTH, &icmp.icmp_v6src);
    765 		mdb_printf("%*N ", ADDR_V6_WIDTH, &icmp.icmp_v6dst);
    766 	}
    767 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
    768 	mdb_printf(" %4i\n", icmp.icmp_zoneid);
    769 
    770 	return (WALK_NEXT);
    771 }
    772 
    773 /*
    774  * print the address of a unix domain socket
    775  *
    776  * so is the address of a AF_UNIX struct sonode in mdb's address space
    777  * soa is the address of the struct soaddr to print
    778  *
    779  * returns 0 on success, -1 otherwise
    780  */
    781 static int
    782 netstat_unix_name_pr(const struct sotpi_sonode *st, const struct soaddr *soa)
    783 {
    784 	const struct sonode *so = &st->st_sonode;
    785 	const char none[] = " (none)";
    786 
    787 	if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) {
    788 		if (st->st_info.sti_faddr_noxlate) {
    789 			mdb_printf("%-14s ", " (socketpair)");
    790 		} else {
    791 			if (soa->soa_len > sizeof (sa_family_t)) {
    792 				char addr[MAXPATHLEN + 1];
    793 
    794 				if (mdb_readstr(addr, sizeof (addr),
    795 				    (uintptr_t)&soa->soa_sa->sa_data) == -1) {
    796 					mdb_warn("failed to read unix address "
    797 					    "at %p", &soa->soa_sa->sa_data);
    798 					return (-1);
    799 				}
    800 
    801 				mdb_printf("%-14s ", addr);
    802 			} else {
    803 				mdb_printf("%-14s ", none);
    804 			}
    805 		}
    806 	} else {
    807 		mdb_printf("%-14s ", none);
    808 	}
    809 
    810 	return (0);
    811 }
    812 
    813 /* based on sockfs_snapshot */
    814 /*ARGSUSED*/
    815 static int
    816 netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
    817 {
    818 	const struct sotpi_sonode *st = walk_data;
    819 	const struct sonode *so = &st->st_sonode;
    820 	const struct sotpi_info *sti = &st->st_info;
    821 
    822 	if (so->so_count == 0)
    823 		return (WALK_NEXT);
    824 
    825 	if (so->so_family != AF_UNIX) {
    826 		mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr);
    827 		return (WALK_ERR);
    828 	}
    829 
    830 	mdb_printf("%-?p ", kaddr);
    831 
    832 	switch (sti->sti_serv_type) {
    833 	case T_CLTS:
    834 		mdb_printf("%-10s ", "dgram");
    835 		break;
    836 	case T_COTS:
    837 		mdb_printf("%-10s ", "stream");
    838 		break;
    839 	case T_COTS_ORD:
    840 		mdb_printf("%-10s ", "stream-ord");
    841 		break;
    842 	default:
    843 		mdb_printf("%-10i ", sti->sti_serv_type);
    844 	}
    845 
    846 	if ((so->so_state & SS_ISBOUND) &&
    847 	    (sti->sti_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
    848 		mdb_printf("%0?p ", sti->sti_ux_laddr.soua_vp);
    849 	} else {
    850 		mdb_printf("%0?p ", NULL);
    851 	}
    852 
    853 	if ((so->so_state & SS_ISCONNECTED) &&
    854 	    (sti->sti_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
    855 		mdb_printf("%0?p ", sti->sti_ux_faddr.soua_vp);
    856 	} else {
    857 		mdb_printf("%0?p ", NULL);
    858 	}
    859 
    860 	if (netstat_unix_name_pr(st, &sti->sti_laddr) == -1)
    861 		return (WALK_ERR);
    862 
    863 	if (netstat_unix_name_pr(st, &sti->sti_faddr) == -1)
    864 		return (WALK_ERR);
    865 
    866 	mdb_printf("%4i\n", so->so_zoneid);
    867 
    868 	return (WALK_NEXT);
    869 }
    870 
    871 static void
    872 netstat_tcp_verbose_header_pr(void)
    873 {
    874 	mdb_printf("       %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n",
    875 	    "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss");
    876 }
    877 
    878 static void
    879 get_ifname(const ire_t *ire, char *intf)
    880 {
    881 	ill_t ill;
    882 
    883 	*intf = '\0';
    884 	if (ire->ire_type == IRE_CACHE) {
    885 		queue_t stq;
    886 
    887 		if (mdb_vread(&stq, sizeof (stq), (uintptr_t)ire->ire_stq) ==
    888 		    -1)
    889 			return;
    890 		if (mdb_vread(&ill, sizeof (ill), (uintptr_t)stq.q_ptr) == -1)
    891 			return;
    892 		(void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
    893 		    (uintptr_t)ill.ill_name);
    894 	} else if (ire->ire_ipif != NULL) {
    895 		ipif_t ipif;
    896 		char *cp;
    897 
    898 		if (mdb_vread(&ipif, sizeof (ipif),
    899 		    (uintptr_t)ire->ire_ipif) == -1)
    900 			return;
    901 		if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ipif.ipif_ill) ==
    902 		    -1)
    903 			return;
    904 		(void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
    905 		    (uintptr_t)ill.ill_name);
    906 		if (ipif.ipif_id != 0) {
    907 			cp = intf + strlen(intf);
    908 			(void) mdb_snprintf(cp, LIFNAMSIZ + 1 - (cp - intf),
    909 			    ":%u", ipif.ipif_id);
    910 		}
    911 	}
    912 }
    913 
    914 static void
    915 get_v4flags(const ire_t *ire, char *flags)
    916 {
    917 	(void) strcpy(flags, "U");
    918 	if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX ||
    919 	    ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT)
    920 		(void) strcat(flags, "G");
    921 	if (ire->ire_mask == IP_HOST_MASK)
    922 		(void) strcat(flags, "H");
    923 	if (ire->ire_type == IRE_HOST_REDIRECT)
    924 		(void) strcat(flags, "D");
    925 	if (ire->ire_type == IRE_CACHE)
    926 		(void) strcat(flags, "A");
    927 	if (ire->ire_type == IRE_BROADCAST)
    928 		(void) strcat(flags, "B");
    929 	if (ire->ire_type == IRE_LOCAL)
    930 		(void) strcat(flags, "L");
    931 	if (ire->ire_flags & RTF_MULTIRT)
    932 		(void) strcat(flags, "M");
    933 	if (ire->ire_flags & RTF_SETSRC)
    934 		(void) strcat(flags, "S");
    935 }
    936 
    937 static int
    938 netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
    939 {
    940 	const ire_t *ire = walk_data;
    941 	uint_t *opts = cb_data;
    942 	ipaddr_t gate;
    943 	char flags[10], intf[LIFNAMSIZ + 1];
    944 
    945 	if (ire->ire_ipversion != IPV4_VERSION)
    946 		return (WALK_NEXT);
    947 
    948 	if (!(*opts & NETSTAT_ALL) && (ire->ire_type == IRE_CACHE ||
    949 	    ire->ire_type == IRE_BROADCAST || ire->ire_type == IRE_LOCAL))
    950 		return (WALK_NEXT);
    951 
    952 	if (*opts & NETSTAT_FIRST) {
    953 		*opts &= ~NETSTAT_FIRST;
    954 		mdb_printf("%<u>%s Table: IPv4%</u>\n",
    955 		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
    956 		if (*opts & NETSTAT_VERBOSE) {
    957 			mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt  "
    958 			    " Ref Flg Out   In/Fwd%</u>\n",
    959 			    "Address", ADDR_V4_WIDTH, "Destination",
    960 			    ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway");
    961 		} else {
    962 			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref  Use   "
    963 			    "Interface%</u>\n",
    964 			    "Address", ADDR_V4_WIDTH, "Destination",
    965 			    ADDR_V4_WIDTH, "Gateway");
    966 		}
    967 	}
    968 
    969 	gate = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK|IRE_BROADCAST)) ?
    970 	    ire->ire_src_addr : ire->ire_gateway_addr;
    971 
    972 	get_v4flags(ire, flags);
    973 
    974 	get_ifname(ire, intf);
    975 
    976 	if (*opts & NETSTAT_VERBOSE) {
    977 		mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u "
    978 		    "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH,
    979 		    ire->ire_mask, ADDR_V4_WIDTH, gate, intf,
    980 		    ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ',
    981 		    ire->ire_uinfo.iulp_rtt, ire->ire_refcnt, flags,
    982 		    ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
    983 	} else {
    984 		mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr,
    985 		    ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags,
    986 		    ire->ire_refcnt,
    987 		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
    988 	}
    989 
    990 	return (WALK_NEXT);
    991 }
    992 
    993 int
    994 ip_mask_to_plen_v6(const in6_addr_t *v6mask)
    995 {
    996 	int plen;
    997 	int i;
    998 	uint32_t val;
    999 
   1000 	for (i = 3; i >= 0; i--)
   1001 		if (v6mask->s6_addr32[i] != 0)
   1002 			break;
   1003 	if (i < 0)
   1004 		return (0);
   1005 	plen = 32 + 32 * i;
   1006 	val = v6mask->s6_addr32[i];
   1007 	while (!(val & 1)) {
   1008 		val >>= 1;
   1009 		plen--;
   1010 	}
   1011 
   1012 	return (plen);
   1013 }
   1014 
   1015 static int
   1016 netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
   1017 {
   1018 	const ire_t *ire = walk_data;
   1019 	uint_t *opts = cb_data;
   1020 	const in6_addr_t *gatep;
   1021 	char deststr[ADDR_V6_WIDTH + 5];
   1022 	char flags[10], intf[LIFNAMSIZ + 1];
   1023 	int masklen;
   1024 
   1025 	if (ire->ire_ipversion != IPV6_VERSION)
   1026 		return (WALK_NEXT);
   1027 
   1028 	if (!(*opts & NETSTAT_ALL) && ire->ire_type == IRE_CACHE)
   1029 		return (WALK_NEXT);
   1030 
   1031 	if (*opts & NETSTAT_FIRST) {
   1032 		*opts &= ~NETSTAT_FIRST;
   1033 		mdb_printf("\n%<u>%s Table: IPv6%</u>\n",
   1034 		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
   1035 		if (*opts & NETSTAT_VERBOSE) {
   1036 			mdb_printf("%<u>%-?s %-*s %-*s If    PMTU   Rtt   Ref "
   1037 			    "Flags Out    In/Fwd%</u>\n",
   1038 			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
   1039 			    ADDR_V6_WIDTH, "Gateway");
   1040 		} else {
   1041 			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use    If"
   1042 			    "%</u>\n",
   1043 			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
   1044 			    ADDR_V6_WIDTH, "Gateway");
   1045 		}
   1046 	}
   1047 
   1048 	gatep = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK)) ?
   1049 	    &ire->ire_src_addr_v6 : &ire->ire_gateway_addr_v6;
   1050 
   1051 	masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6);
   1052 	(void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d",
   1053 	    &ire->ire_addr_v6, masklen);
   1054 
   1055 	(void) strcpy(flags, "U");
   1056 	if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX ||
   1057 	    ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT)
   1058 		(void) strcat(flags, "G");
   1059 	if (masklen == IPV6_ABITS)
   1060 		(void) strcat(flags, "H");
   1061 	if (ire->ire_type == IRE_HOST_REDIRECT)
   1062 		(void) strcat(flags, "D");
   1063 	if (ire->ire_type == IRE_CACHE)
   1064 		(void) strcat(flags, "A");
   1065 	if (ire->ire_type == IRE_LOCAL)
   1066 		(void) strcat(flags, "L");
   1067 	if (ire->ire_flags & RTF_MULTIRT)
   1068 		(void) strcat(flags, "M");
   1069 	if (ire->ire_flags & RTF_SETSRC)
   1070 		(void) strcat(flags, "S");
   1071 
   1072 	get_ifname(ire, intf);
   1073 
   1074 	if (*opts & NETSTAT_VERBOSE) {
   1075 		mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n",
   1076 		    kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep,
   1077 		    intf, ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ',
   1078 		    ire->ire_uinfo.iulp_rtt, ire->ire_refcnt,
   1079 		    flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
   1080 	} else {
   1081 		mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr,
   1082 		    ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags,
   1083 		    ire->ire_refcnt,
   1084 		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
   1085 	}
   1086 
   1087 	return (WALK_NEXT);
   1088 }
   1089 
   1090 static void
   1091 netstat_header_v4(int proto)
   1092 {
   1093 	if (proto == IPPROTO_TCP)
   1094 		mdb_printf("%<u>%-?s ", "TCPv4");
   1095 	else if (proto == IPPROTO_UDP)
   1096 		mdb_printf("%<u>%-?s ", "UDPv4");
   1097 	else if (proto == IPPROTO_ICMP)
   1098 		mdb_printf("%<u>%-?s ", "ICMPv4");
   1099 	mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
   1100 	    "", ADDR_V4_WIDTH, "Local Address",
   1101 	    "", ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone");
   1102 }
   1103 
   1104 static void
   1105 netstat_header_v6(int proto)
   1106 {
   1107 	if (proto == IPPROTO_TCP)
   1108 		mdb_printf("%<u>%-?s ", "TCPv6");
   1109 	else if (proto == IPPROTO_UDP)
   1110 		mdb_printf("%<u>%-?s ", "UDPv6");
   1111 	else if (proto == IPPROTO_ICMP)
   1112 		mdb_printf("%<u>%-?s ", "ICMPv6");
   1113 	mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
   1114 	    "", ADDR_V6_WIDTH, "Local Address",
   1115 	    "", ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone");
   1116 }
   1117 
   1118 static int
   1119 netstat_print_conn(const char *cache, int proto, mdb_walk_cb_t cbfunc,
   1120     void *cbdata)
   1121 {
   1122 	netstat_cb_data_t *ncb = cbdata;
   1123 
   1124 	if ((ncb->opts & NETSTAT_VERBOSE) && proto == IPPROTO_TCP)
   1125 		netstat_tcp_verbose_header_pr();
   1126 	if (mdb_walk(cache, cbfunc, cbdata) == -1) {
   1127 		mdb_warn("failed to walk %s", cache);
   1128 		return (DCMD_ERR);
   1129 	}
   1130 	return (DCMD_OK);
   1131 }
   1132 
   1133 static int
   1134 netstat_print_common(const char *cache, int proto, mdb_walk_cb_t cbfunc,
   1135     void *cbdata)
   1136 {
   1137 	netstat_cb_data_t *ncb = cbdata;
   1138 	int af = ncb->af;
   1139 	int status = DCMD_OK;
   1140 
   1141 	if (af != AF_INET6) {
   1142 		ncb->af = AF_INET;
   1143 		netstat_header_v4(proto);
   1144 		status = netstat_print_conn(cache, proto, cbfunc, cbdata);
   1145 	}
   1146 	if (status == DCMD_OK && af != AF_INET) {
   1147 		ncb->af = AF_INET6;
   1148 		netstat_header_v6(proto);
   1149 		status = netstat_print_conn(cache, proto, cbfunc, cbdata);
   1150 	}
   1151 	ncb->af = af;
   1152 	return (status);
   1153 }
   1154 
   1155 /*ARGSUSED*/
   1156 int
   1157 netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1158 {
   1159 	uint_t opts = 0;
   1160 	const char *optf = NULL;
   1161 	const char *optP = NULL;
   1162 	netstat_cb_data_t *cbdata;
   1163 	int status;
   1164 	int af = 0;
   1165 
   1166 	if (mdb_getopts(argc, argv,
   1167 	    'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts,
   1168 	    'f', MDB_OPT_STR, &optf,
   1169 	    'P', MDB_OPT_STR, &optP,
   1170 	    'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts,
   1171 	    'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts,
   1172 	    NULL) != argc)
   1173 		return (DCMD_USAGE);
   1174 
   1175 	if (optP != NULL) {
   1176 		if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0) &&
   1177 		    (strcmp("icmp", optP) != 0))
   1178 			return (DCMD_USAGE);
   1179 		if (opts & NETSTAT_ROUTE)
   1180 			return (DCMD_USAGE);
   1181 	}
   1182 
   1183 	if (optf == NULL)
   1184 		opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX;
   1185 	else if (strcmp("inet", optf) == 0)
   1186 		opts |= NETSTAT_V4;
   1187 	else if (strcmp("inet6", optf) == 0)
   1188 		opts |= NETSTAT_V6;
   1189 	else if (strcmp("unix", optf) == 0)
   1190 		opts |= NETSTAT_UNIX;
   1191 	else
   1192 		return (DCMD_USAGE);
   1193 
   1194 	if (opts & NETSTAT_ROUTE) {
   1195 		if (!(opts & (NETSTAT_V4|NETSTAT_V6)))
   1196 			return (DCMD_USAGE);
   1197 		if (opts & NETSTAT_V4) {
   1198 			opts |= NETSTAT_FIRST;
   1199 			if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) {
   1200 				mdb_warn("failed to walk ip`ire");
   1201 				return (DCMD_ERR);
   1202 			}
   1203 		}
   1204 		if (opts & NETSTAT_V6) {
   1205 			opts |= NETSTAT_FIRST;
   1206 			if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) {
   1207 				mdb_warn("failed to walk ip`ire");
   1208 				return (DCMD_ERR);
   1209 			}
   1210 		}
   1211 		return (DCMD_OK);
   1212 	}
   1213 
   1214 	if ((opts & NETSTAT_UNIX) && (optP == NULL)) {
   1215 		/* Print Unix Domain Sockets */
   1216 		mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n",
   1217 		    "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr",
   1218 		    "Remote Addr", "Zone");
   1219 
   1220 		if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) {
   1221 			mdb_warn("failed to walk genunix`sonode");
   1222 			return (DCMD_ERR);
   1223 		}
   1224 		if (!(opts & (NETSTAT_V4 | NETSTAT_V6)))
   1225 			return (DCMD_OK);
   1226 	}
   1227 
   1228 	cbdata = mdb_alloc(sizeof (netstat_cb_data_t), UM_SLEEP);
   1229 	cbdata->opts = opts;
   1230 	if ((optf != NULL) && (opts & NETSTAT_V4))
   1231 		af = AF_INET;
   1232 	else if ((optf != NULL) && (opts & NETSTAT_V6))
   1233 		af = AF_INET6;
   1234 
   1235 	cbdata->af = af;
   1236 	if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
   1237 		status = netstat_print_common("tcp_conn_cache", IPPROTO_TCP,
   1238 		    netstat_tcp_cb, cbdata);
   1239 		if (status != DCMD_OK)
   1240 			goto out;
   1241 	}
   1242 
   1243 	if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
   1244 		status = netstat_print_common("udp_conn_cache", IPPROTO_UDP,
   1245 		    netstat_udp_cb, cbdata);
   1246 		if (status != DCMD_OK)
   1247 			goto out;
   1248 	}
   1249 
   1250 	if ((optP == NULL) || (strcmp("icmp", optP) == 0)) {
   1251 		status = netstat_print_common("rawip_conn_cache", IPPROTO_ICMP,
   1252 		    netstat_icmp_cb, cbdata);
   1253 		if (status != DCMD_OK)
   1254 			goto out;
   1255 	}
   1256 out:
   1257 	mdb_free(cbdata, sizeof (netstat_cb_data_t));
   1258 	return (status);
   1259 }
   1260 
   1261 /*
   1262  * "::dladm show-bridge" support
   1263  */
   1264 typedef struct {
   1265 	uint_t opt_l;
   1266 	uint_t opt_f;
   1267 	uint_t opt_t;
   1268 	const char *name;
   1269 	clock_t lbolt;
   1270 	boolean_t found;
   1271 	uint_t nlinks;
   1272 	uint_t nfwd;
   1273 
   1274 	/*
   1275 	 * These structures are kept inside the 'args' for allocation reasons.
   1276 	 * They're all large data structures (over 1K), and may cause the stack
   1277 	 * to explode.  mdb and kmdb will fail in these cases, and thus we
   1278 	 * allocate them from the heap.
   1279 	 */
   1280 	trill_inst_t ti;
   1281 	bridge_link_t bl;
   1282 	mac_impl_t mi;
   1283 } show_bridge_args_t;
   1284 
   1285 static void
   1286 show_vlans(const uint8_t *vlans)
   1287 {
   1288 	int i, bit;
   1289 	uint8_t val;
   1290 	int rstart = -1, rnext = -1;
   1291 
   1292 	for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) {
   1293 		val = vlans[i];
   1294 		if (i == 0)
   1295 			val &= ~1;
   1296 		while ((bit = mdb_ffs(val)) != 0) {
   1297 			bit--;
   1298 			val &= ~(1 << bit);
   1299 			bit += i * sizeof (*vlans) * NBBY;
   1300 			if (bit != rnext) {
   1301 				if (rnext != -1 && rstart + 1 != rnext)
   1302 					mdb_printf("-%d", rnext - 1);
   1303 				if (rstart != -1)
   1304 					mdb_printf(",");
   1305 				mdb_printf("%d", bit);
   1306 				rstart = bit;
   1307 			}
   1308 			rnext = bit + 1;
   1309 		}
   1310 	}
   1311 	if (rnext != -1 && rstart + 1 != rnext)
   1312 		mdb_printf("-%d", rnext - 1);
   1313 	mdb_printf("\n");
   1314 }
   1315 
   1316 /*
   1317  * This callback is invoked by a walk of the links attached to a bridge.  If
   1318  * we're showing link details, then they're printed here.  If not, then we just
   1319  * count up the links for the bridge summary.
   1320  */
   1321 static int
   1322 do_bridge_links(uintptr_t addr, const void *data, void *ptr)
   1323 {
   1324 	show_bridge_args_t *args = ptr;
   1325 	const bridge_link_t *blp = data;
   1326 	char macaddr[ETHERADDRL * 3];
   1327 	const char *name;
   1328 
   1329 	args->nlinks++;
   1330 
   1331 	if (!args->opt_l)
   1332 		return (WALK_NEXT);
   1333 
   1334 	if (mdb_vread(&args->mi, sizeof (args->mi),
   1335 	    (uintptr_t)blp->bl_mh) == -1) {
   1336 		mdb_warn("cannot read mac data at %p", blp->bl_mh);
   1337 		name = "?";
   1338 	} else  {
   1339 		name = args->mi.mi_name;
   1340 	}
   1341 
   1342 	mdb_mac_addr(blp->bl_local_mac, ETHERADDRL, macaddr,
   1343 	    sizeof (macaddr));
   1344 
   1345 	mdb_printf("%-?p %-16s %-17s %03X %-4d ", addr, name, macaddr,
   1346 	    blp->bl_flags, blp->bl_pvid);
   1347 
   1348 	if (blp->bl_trilldata == NULL) {
   1349 		switch (blp->bl_state) {
   1350 		case BLS_BLOCKLISTEN:
   1351 			name = "BLOCK";
   1352 			break;
   1353 		case BLS_LEARNING:
   1354 			name = "LEARN";
   1355 			break;
   1356 		case BLS_FORWARDING:
   1357 			name = "FWD";
   1358 			break;
   1359 		default:
   1360 			name = "?";
   1361 		}
   1362 		mdb_printf("%-5s ", name);
   1363 		show_vlans(blp->bl_vlans);
   1364 	} else {
   1365 		show_vlans(blp->bl_afs);
   1366 	}
   1367 
   1368 	return (WALK_NEXT);
   1369 }
   1370 
   1371 /*
   1372  * It seems a shame to duplicate this code, but merging it with the link
   1373  * printing code above is more trouble than it would be worth.
   1374  */
   1375 static void
   1376 print_link_name(show_bridge_args_t *args, uintptr_t addr, char sep)
   1377 {
   1378 	const char *name;
   1379 
   1380 	if (mdb_vread(&args->bl, sizeof (args->bl), addr) == -1) {
   1381 		mdb_warn("cannot read bridge link at %p", addr);
   1382 		return;
   1383 	}
   1384 
   1385 	if (mdb_vread(&args->mi, sizeof (args->mi),
   1386 	    (uintptr_t)args->bl.bl_mh) == -1) {
   1387 		name = "?";
   1388 	} else  {
   1389 		name = args->mi.mi_name;
   1390 	}
   1391 
   1392 	mdb_printf("%s%c", name, sep);
   1393 }
   1394 
   1395 static int
   1396 do_bridge_fwd(uintptr_t addr, const void *data, void *ptr)
   1397 {
   1398 	show_bridge_args_t *args = ptr;
   1399 	const bridge_fwd_t *bfp = data;
   1400 	char macaddr[ETHERADDRL * 3];
   1401 	int i;
   1402 #define	MAX_FWD_LINKS	16
   1403 	bridge_link_t *links[MAX_FWD_LINKS];
   1404 	uint_t nlinks;
   1405 
   1406 	args->nfwd++;
   1407 
   1408 	if (!args->opt_f)
   1409 		return (WALK_NEXT);
   1410 
   1411 	if ((nlinks = bfp->bf_nlinks) > MAX_FWD_LINKS)
   1412 		nlinks = MAX_FWD_LINKS;
   1413 
   1414 	if (mdb_vread(links, sizeof (links[0]) * nlinks,
   1415 	    (uintptr_t)bfp->bf_links) == -1) {
   1416 		mdb_warn("cannot read bridge forwarding links at %p",
   1417 		    bfp->bf_links);
   1418 		return (WALK_ERR);
   1419 	}
   1420 
   1421 	mdb_mac_addr(bfp->bf_dest, ETHERADDRL, macaddr, sizeof (macaddr));
   1422 
   1423 	mdb_printf("%-?p %-17s ", addr, macaddr);
   1424 	if (bfp->bf_flags & BFF_LOCALADDR)
   1425 		mdb_printf("%-7s", "[self]");
   1426 	else
   1427 		mdb_printf("t-%-5d", args->lbolt - bfp->bf_lastheard);
   1428 	mdb_printf(" %-7u ", bfp->bf_refs);
   1429 
   1430 	if (bfp->bf_trill_nick != 0) {
   1431 		mdb_printf("%d\n", bfp->bf_trill_nick);
   1432 	} else {
   1433 		for (i = 0; i < bfp->bf_nlinks; i++) {
   1434 			print_link_name(args, (uintptr_t)links[i],
   1435 			    i == bfp->bf_nlinks - 1 ? '\n' : ' ');
   1436 		}
   1437 	}
   1438 
   1439 	return (WALK_NEXT);
   1440 }
   1441 
   1442 static int
   1443 do_show_bridge(uintptr_t addr, const void *data, void *ptr)
   1444 {
   1445 	show_bridge_args_t *args = ptr;
   1446 	bridge_inst_t bi;
   1447 	const bridge_inst_t *bip;
   1448 	trill_node_t tn;
   1449 	trill_sock_t tsp;
   1450 	trill_nickinfo_t tni;
   1451 	char bname[MAXLINKNAMELEN];
   1452 	char macaddr[ETHERADDRL * 3];
   1453 	char *cp;
   1454 	uint_t nnicks;
   1455 	int i;
   1456 
   1457 	if (data != NULL) {
   1458 		bip = data;
   1459 	} else {
   1460 		if (mdb_vread(&bi, sizeof (bi), addr) == -1) {
   1461 			mdb_warn("cannot read bridge instance at %p", addr);
   1462 			return (WALK_ERR);
   1463 		}
   1464 		bip = &bi;
   1465 	}
   1466 
   1467 	(void) strncpy(bname, bip->bi_name, sizeof (bname) - 1);
   1468 	bname[MAXLINKNAMELEN - 1] = '\0';
   1469 	cp = bname + strlen(bname);
   1470 	if (cp > bname && cp[-1] == '0')
   1471 		cp[-1] = '\0';
   1472 
   1473 	if (args->name != NULL && strcmp(args->name, bname) != 0)
   1474 		return (WALK_NEXT);
   1475 
   1476 	args->found = B_TRUE;
   1477 	args->nlinks = args->nfwd = 0;
   1478 
   1479 	if (args->opt_l) {
   1480 		mdb_printf("%-?s %-16s %-17s %3s %-4s ", "ADDR", "LINK",
   1481 		    "MAC-ADDR", "FLG", "PVID");
   1482 		if (bip->bi_trilldata == NULL)
   1483 			mdb_printf("%-5s %s\n", "STATE", "VLANS");
   1484 		else
   1485 			mdb_printf("%s\n", "FWD-VLANS");
   1486 	}
   1487 
   1488 	if (!args->opt_f && !args->opt_t &&
   1489 	    mdb_pwalk("list", do_bridge_links, args,
   1490 	    addr + offsetof(bridge_inst_t, bi_links)) != DCMD_OK)
   1491 		return (WALK_ERR);
   1492 
   1493 	if (args->opt_f)
   1494 		mdb_printf("%-?s %-17s %-7s %-7s %s\n", "ADDR", "DEST", "TIME",
   1495 		    "REFS", "OUTPUT");
   1496 
   1497 	if (!args->opt_l && !args->opt_t &&
   1498 	    mdb_pwalk("avl", do_bridge_fwd, args,
   1499 	    addr + offsetof(bridge_inst_t, bi_fwd)) != DCMD_OK)
   1500 		return (WALK_ERR);
   1501 
   1502 	nnicks = 0;
   1503 	if (bip->bi_trilldata != NULL && !args->opt_l && !args->opt_f) {
   1504 		if (mdb_vread(&args->ti, sizeof (args->ti),
   1505 		    (uintptr_t)bip->bi_trilldata) == -1) {
   1506 			mdb_warn("cannot read trill instance at %p",
   1507 			    bip->bi_trilldata);
   1508 			return (WALK_ERR);
   1509 		}
   1510 		if (args->opt_t)
   1511 			mdb_printf("%-?s %-5s %-17s %s\n", "ADDR",
   1512 			    "NICK", "NEXT-HOP", "LINK");
   1513 		for (i = 0; i < RBRIDGE_NICKNAME_MAX; i++) {
   1514 			if (args->ti.ti_nodes[i] == NULL)
   1515 				continue;
   1516 			if (args->opt_t) {
   1517 				if (mdb_vread(&tn, sizeof (tn),
   1518 				    (uintptr_t)args->ti.ti_nodes[i]) == -1) {
   1519 					mdb_warn("cannot read trill node %d at "
   1520 					    "%p", i, args->ti.ti_nodes[i]);
   1521 					return (WALK_ERR);
   1522 				}
   1523 				if (mdb_vread(&tni, sizeof (tni),
   1524 				    (uintptr_t)tn.tn_ni) == -1) {
   1525 					mdb_warn("cannot read trill node info "
   1526 					    "%d at %p", i, tn.tn_ni);
   1527 					return (WALK_ERR);
   1528 				}
   1529 				mdb_mac_addr(tni.tni_adjsnpa, ETHERADDRL,
   1530 				    macaddr, sizeof (macaddr));
   1531 				if (tni.tni_nick == args->ti.ti_nick) {
   1532 					(void) strcpy(macaddr, "[self]");
   1533 				}
   1534 				mdb_printf("%-?p %-5u %-17s ",
   1535 				    args->ti.ti_nodes[i], tni.tni_nick,
   1536 				    macaddr);
   1537 				if (tn.tn_tsp != NULL) {
   1538 					if (mdb_vread(&tsp, sizeof (tsp),
   1539 					    (uintptr_t)tn.tn_tsp) == -1) {
   1540 						mdb_warn("cannot read trill "
   1541 						    "socket info at %p",
   1542 						    tn.tn_tsp);
   1543 						return (WALK_ERR);
   1544 					}
   1545 					if (tsp.ts_link != NULL) {
   1546 						print_link_name(args,
   1547 						    (uintptr_t)tsp.ts_link,
   1548 						    '\n');
   1549 						continue;
   1550 					}
   1551 				}
   1552 				mdb_printf("--\n");
   1553 			} else {
   1554 				nnicks++;
   1555 			}
   1556 		}
   1557 	} else {
   1558 		if (args->opt_t)
   1559 			mdb_printf("bridge is not running TRILL\n");
   1560 	}
   1561 
   1562 	if (!args->opt_l && !args->opt_f && !args->opt_t) {
   1563 		mdb_printf("%-?p %-7s %-16s %-7u %-7u", addr,
   1564 		    bip->bi_trilldata == NULL ? "stp" : "trill", bname,
   1565 		    args->nlinks, args->nfwd);
   1566 		if (bip->bi_trilldata != NULL)
   1567 			mdb_printf(" %-7u %u\n", nnicks, args->ti.ti_nick);
   1568 		else
   1569 			mdb_printf(" %-7s %s\n", "--", "--");
   1570 	}
   1571 	return (WALK_NEXT);
   1572 }
   1573 
   1574 static int
   1575 dladm_show_bridge(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1576 {
   1577 	show_bridge_args_t *args;
   1578 	GElf_Sym sym;
   1579 	int i;
   1580 
   1581 	args = mdb_zalloc(sizeof (*args), UM_SLEEP);
   1582 
   1583 	i = mdb_getopts(argc, argv,
   1584 	    'l', MDB_OPT_SETBITS, 1, &args->opt_l,
   1585 	    'f', MDB_OPT_SETBITS, 1, &args->opt_f,
   1586 	    't', MDB_OPT_SETBITS, 1, &args->opt_t,
   1587 	    NULL);
   1588 
   1589 	argc -= i;
   1590 	argv += i;
   1591 
   1592 	if (argc > 1 || (argc == 1 && argv[0].a_type != MDB_TYPE_STRING)) {
   1593 		mdb_free(args, sizeof (*args));
   1594 		return (DCMD_USAGE);
   1595 	}
   1596 	if (argc == 1)
   1597 		args->name = argv[0].a_un.a_str;
   1598 
   1599 	if (mdb_readvar(&args->lbolt,
   1600 	    mdb_prop_postmortem ? "panic_lbolt" : "lbolt") == -1) {
   1601 		mdb_warn("failed to read lbolt");
   1602 		goto err;
   1603 	}
   1604 
   1605 	if (flags & DCMD_ADDRSPEC) {
   1606 		if (args->name != NULL) {
   1607 			mdb_printf("bridge name and address are mutually "
   1608 			    "exclusive\n");
   1609 			goto err;
   1610 		}
   1611 		if (!args->opt_l && !args->opt_f && !args->opt_t)
   1612 			mdb_printf("%-?s %-7s %-16s %-7s %-7s\n", "ADDR",
   1613 			    "PROTECT", "NAME", "NLINKS", "NFWD");
   1614 		if (do_show_bridge(addr, NULL, args) != WALK_NEXT)
   1615 			goto err;
   1616 		mdb_free(args, sizeof (*args));
   1617 		return (DCMD_OK);
   1618 	} else {
   1619 		if ((args->opt_l || args->opt_f || args->opt_t) &&
   1620 		    args->name == NULL) {
   1621 			mdb_printf("need bridge name or address with -[lft]\n");
   1622 			goto err;
   1623 		}
   1624 		if (mdb_lookup_by_obj("bridge", "inst_list", &sym) == -1) {
   1625 			mdb_warn("failed to find 'bridge`inst_list'");
   1626 			goto err;
   1627 		}
   1628 		if (!args->opt_l && !args->opt_f && !args->opt_t)
   1629 			mdb_printf("%-?s %-7s %-16s %-7s %-7s %-7s %s\n",
   1630 			    "ADDR", "PROTECT", "NAME", "NLINKS", "NFWD",
   1631 			    "NNICKS", "NICK");
   1632 		if (mdb_pwalk("list", do_show_bridge, args,
   1633 		    (uintptr_t)sym.st_value) != DCMD_OK)
   1634 			goto err;
   1635 		if (!args->found && args->name != NULL) {
   1636 			mdb_printf("bridge instance %s not found\n",
   1637 			    args->name);
   1638 			goto err;
   1639 		}
   1640 		mdb_free(args, sizeof (*args));
   1641 		return (DCMD_OK);
   1642 	}
   1643 
   1644 err:
   1645 	mdb_free(args, sizeof (*args));
   1646 	return (DCMD_ERR);
   1647 }
   1648 
   1649 /*
   1650  * Support for the "::dladm" dcmd
   1651  */
   1652 int
   1653 dladm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1654 {
   1655 	if (argc < 1 || argv[0].a_type != MDB_TYPE_STRING)
   1656 		return (DCMD_USAGE);
   1657 
   1658 	/*
   1659 	 * This could be a bit more elaborate, once we support more of the
   1660 	 * dladm show-* subcommands.
   1661 	 */
   1662 	argc--;
   1663 	argv++;
   1664 	if (strcmp(argv[-1].a_un.a_str, "show-bridge") == 0)
   1665 		return (dladm_show_bridge(addr, flags, argc, argv));
   1666 
   1667 	return (DCMD_USAGE);
   1668 }
   1669 
   1670 void
   1671 dladm_help(void)
   1672 {
   1673 	mdb_printf("Subcommands:\n"
   1674 	    "  show-bridge [-flt] [<name>]\n"
   1675 	    "\t     Show bridge information; -l for links and -f for "
   1676 	    "forwarding\n"
   1677 	    "\t     entries, and -t for TRILL nicknames.  Address is required "
   1678 	    "if name\n"
   1679 	    "\t     is not specified.\n");
   1680 }
   1681