xref: /onnv-gate/usr/src/cmd/mdb/common/modules/genunix/net.c (revision 1676:37f4a3e2bd99)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*1676Sjpk  * Common Development and Distribution License (the "License").
6*1676Sjpk  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*1676Sjpk  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
290Sstevel@tonic-gate #include <mdb/mdb_ks.h>
300Sstevel@tonic-gate #include <mdb/mdb_ctf.h>
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/tihdr.h>
330Sstevel@tonic-gate #include <inet/led.h>
340Sstevel@tonic-gate #include <inet/common.h>
350Sstevel@tonic-gate #include <netinet/in.h>
360Sstevel@tonic-gate #include <netinet/ip6.h>
370Sstevel@tonic-gate #include <netinet/icmp6.h>
380Sstevel@tonic-gate #include <inet/ip.h>
390Sstevel@tonic-gate #include <inet/ip6.h>
400Sstevel@tonic-gate #include <inet/ipclassifier.h>
410Sstevel@tonic-gate #include <inet/tcp.h>
420Sstevel@tonic-gate #include <sys/stream.h>
430Sstevel@tonic-gate #include <sys/vfs.h>
440Sstevel@tonic-gate #include <sys/stropts.h>
450Sstevel@tonic-gate #include <sys/tpicommon.h>
460Sstevel@tonic-gate #include <sys/socket.h>
470Sstevel@tonic-gate #include <sys/socketvar.h>
480Sstevel@tonic-gate #include <sys/cred_impl.h>
490Sstevel@tonic-gate #include <inet/udp_impl.h>
500Sstevel@tonic-gate #include <inet/arp_impl.h>
510Sstevel@tonic-gate #include <inet/rawip_impl.h>
520Sstevel@tonic-gate #include <inet/mi.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #define	MIH2MIO(mihp) (&(mihp)->mh_o)
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #define	ADDR_V6_WIDTH	23
570Sstevel@tonic-gate #define	ADDR_V4_WIDTH	15
580Sstevel@tonic-gate 
59*1676Sjpk #define	NETSTAT_ALL	0x01
60*1676Sjpk #define	NETSTAT_VERBOSE	0x02
61*1676Sjpk #define	NETSTAT_ROUTE	0x04
62*1676Sjpk #define	NETSTAT_V4	0x08
63*1676Sjpk #define	NETSTAT_V6	0x10
64*1676Sjpk #define	NETSTAT_UNIX	0x20
65*1676Sjpk 
66*1676Sjpk #define	NETSTAT_FIRST	0x80000000u
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate  * Print an IPv4 address and port number in a compact and easy to read format
700Sstevel@tonic-gate  * The arguments are in network byte order
710Sstevel@tonic-gate  */
720Sstevel@tonic-gate static void
730Sstevel@tonic-gate net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport)
740Sstevel@tonic-gate {
750Sstevel@tonic-gate 	uint32_t naddr = V4_PART_OF_V6((*nipv6addr));
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	mdb_nhconvert(&nport, &nport, sizeof (nport));
780Sstevel@tonic-gate 	mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport);
790Sstevel@tonic-gate }
800Sstevel@tonic-gate 
810Sstevel@tonic-gate /*
820Sstevel@tonic-gate  * Print an IPv6 address and port number in a compact and easy to read format
830Sstevel@tonic-gate  * The arguments are in network byte order
840Sstevel@tonic-gate  */
850Sstevel@tonic-gate static void
860Sstevel@tonic-gate net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport)
870Sstevel@tonic-gate {
880Sstevel@tonic-gate 	mdb_nhconvert(&nport, &nport, sizeof (nport));
890Sstevel@tonic-gate 	mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport);
900Sstevel@tonic-gate }
910Sstevel@tonic-gate 
920Sstevel@tonic-gate static int
930Sstevel@tonic-gate net_tcp_active(const tcp_t *tcp)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate 	return (tcp->tcp_state >= TCPS_ESTABLISHED);
960Sstevel@tonic-gate }
970Sstevel@tonic-gate 
980Sstevel@tonic-gate static int
990Sstevel@tonic-gate net_tcp_ipv4(const tcp_t *tcp)
1000Sstevel@tonic-gate {
1010Sstevel@tonic-gate 	return ((tcp->tcp_ipversion == IPV4_VERSION) ||
1020Sstevel@tonic-gate 	    (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_ip_src_v6) &&
1030Sstevel@tonic-gate 	    (tcp->tcp_state <= TCPS_LISTEN)));
1040Sstevel@tonic-gate }
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate static int
1070Sstevel@tonic-gate net_tcp_ipv6(const tcp_t *tcp)
1080Sstevel@tonic-gate {
1090Sstevel@tonic-gate 	return (tcp->tcp_ipversion == IPV6_VERSION);
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate static int
1130Sstevel@tonic-gate net_udp_active(const udp_t *udp)
1140Sstevel@tonic-gate {
115741Smasputra 	return ((udp->udp_state == TS_IDLE) ||
116741Smasputra 	    (udp->udp_state == TS_DATA_XFER));
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate static int
1200Sstevel@tonic-gate net_udp_ipv4(const udp_t *udp)
1210Sstevel@tonic-gate {
1220Sstevel@tonic-gate 	return ((udp->udp_ipversion == IPV4_VERSION) ||
1230Sstevel@tonic-gate 	    (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src) &&
1240Sstevel@tonic-gate 	    (udp->udp_state <= TS_IDLE)));
1250Sstevel@tonic-gate }
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate static int
1280Sstevel@tonic-gate net_udp_ipv6(const udp_t *udp)
1290Sstevel@tonic-gate {
1300Sstevel@tonic-gate 	return (udp->udp_ipversion == IPV6_VERSION);
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate int
1340Sstevel@tonic-gate sonode_walk_init(mdb_walk_state_t *wsp)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
1370Sstevel@tonic-gate 		GElf_Sym sym;
1380Sstevel@tonic-gate 		struct socklist *slp;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 		if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) {
1410Sstevel@tonic-gate 			mdb_warn("failed to lookup sockfs`socklist");
1420Sstevel@tonic-gate 			return (WALK_ERR);
1430Sstevel@tonic-gate 		}
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 		slp = (struct socklist *)(uintptr_t)sym.st_value;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 		if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),
1480Sstevel@tonic-gate 		    (uintptr_t)&slp->sl_list) == -1) {
1490Sstevel@tonic-gate 			mdb_warn("failed to read address of initial sonode "
1500Sstevel@tonic-gate 			    "at %p", &slp->sl_list);
1510Sstevel@tonic-gate 			return (WALK_ERR);
1520Sstevel@tonic-gate 		}
1530Sstevel@tonic-gate 	}
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (struct sonode), UM_SLEEP);
1560Sstevel@tonic-gate 	return (WALK_NEXT);
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate int
1600Sstevel@tonic-gate sonode_walk_step(mdb_walk_state_t *wsp)
1610Sstevel@tonic-gate {
1620Sstevel@tonic-gate 	int status;
1630Sstevel@tonic-gate 	struct sonode *sonodep;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
1660Sstevel@tonic-gate 		return (WALK_DONE);
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (struct sonode),
1690Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
1700Sstevel@tonic-gate 		mdb_warn("failed to read sonode at %p", wsp->walk_addr);
1710Sstevel@tonic-gate 		return (WALK_ERR);
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1750Sstevel@tonic-gate 	    wsp->walk_cbdata);
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	sonodep = wsp->walk_data;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)sonodep->so_next;
1800Sstevel@tonic-gate 	return (status);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate void
1840Sstevel@tonic-gate sonode_walk_fini(mdb_walk_state_t *wsp)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct sonode));
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate struct mi_walk_data {
1900Sstevel@tonic-gate 	uintptr_t mi_wd_miofirst;
1910Sstevel@tonic-gate 	MI_O mi_wd_miodata;
1920Sstevel@tonic-gate };
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate int
1950Sstevel@tonic-gate mi_walk_init(mdb_walk_state_t *wsp)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate 	struct mi_walk_data *wdp;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
2000Sstevel@tonic-gate 		mdb_warn("mi doesn't support global walks\n");
2010Sstevel@tonic-gate 		return (WALK_ERR);
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP);
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	/* So that we do not immediately return WALK_DONE below */
2070Sstevel@tonic-gate 	wdp->mi_wd_miofirst = NULL;
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	wsp->walk_data = wdp;
2100Sstevel@tonic-gate 	return (WALK_NEXT);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate int
2140Sstevel@tonic-gate mi_walk_step(mdb_walk_state_t *wsp)
2150Sstevel@tonic-gate {
2160Sstevel@tonic-gate 	struct mi_walk_data *wdp = wsp->walk_data;
2170Sstevel@tonic-gate 	MI_OP miop = &wdp->mi_wd_miodata;
2180Sstevel@tonic-gate 	int status;
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	/* Always false in the first iteration */
2210Sstevel@tonic-gate 	if ((wsp->walk_addr == (uintptr_t)NULL) ||
2220Sstevel@tonic-gate 	    (wsp->walk_addr == wdp->mi_wd_miofirst)) {
2230Sstevel@tonic-gate 		return (WALK_DONE);
2240Sstevel@tonic-gate 	}
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) {
2270Sstevel@tonic-gate 		mdb_warn("failed to read MI object at %p", wsp->walk_addr);
2280Sstevel@tonic-gate 		return (WALK_ERR);
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, miop, wsp->walk_cbdata);
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	/* Only true in the first iteration */
2340Sstevel@tonic-gate 	if (wdp->mi_wd_miofirst == NULL)
2350Sstevel@tonic-gate 		wdp->mi_wd_miofirst = wsp->walk_addr;
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)miop->mi_o_next;
2380Sstevel@tonic-gate 	return (status);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate void
2420Sstevel@tonic-gate mi_walk_fini(mdb_walk_state_t *wsp)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct mi_walk_data));
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate typedef struct mi_payload_walk_data_s {
2480Sstevel@tonic-gate 	uintptr_t mi_pwd_first;
2490Sstevel@tonic-gate 	void *mi_pwd_data;
2500Sstevel@tonic-gate } mi_payload_walk_data_t;
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate static void
2530Sstevel@tonic-gate delete_mi_payload_walk_data(mi_payload_walk_data_t *pwdp, size_t payload_size)
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate 	mdb_free(pwdp->mi_pwd_data, payload_size);
2560Sstevel@tonic-gate 	mdb_free(pwdp, sizeof (mi_payload_walk_data_t));
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate typedef struct mi_payload_walk_arg_s {
2600Sstevel@tonic-gate 	const char *mi_pwa_obj;		/* load object of mi_o_head_t * */
2610Sstevel@tonic-gate 	const char *mi_pwa_sym;		/* symbol name of mi_o_head_t * */
2620Sstevel@tonic-gate 	const size_t mi_pwa_size;	/* size of mi payload */
2630Sstevel@tonic-gate 	const uint_t mi_pwa_flags;	/* device and/or module */
2640Sstevel@tonic-gate } mi_payload_walk_arg_t;
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate #define	MI_PAYLOAD_DEVICE	0x1
2670Sstevel@tonic-gate #define	MI_PAYLOAD_MODULE	0x2
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate int
2700Sstevel@tonic-gate mi_payload_walk_init(mdb_walk_state_t *wsp)
2710Sstevel@tonic-gate {
2720Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
2730Sstevel@tonic-gate 	mi_payload_walk_data_t *pwdp;
2740Sstevel@tonic-gate 	GElf_Sym sym;
2750Sstevel@tonic-gate 	mi_head_t *mihp;
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	/* Determine the address to start or end the walk with */
2780Sstevel@tonic-gate 	if (mdb_lookup_by_obj(arg->mi_pwa_obj, arg->mi_pwa_sym, &sym) == -1) {
2790Sstevel@tonic-gate 		mdb_warn("failed to lookup %s`%s",
2800Sstevel@tonic-gate 		    arg->mi_pwa_obj, arg->mi_pwa_sym);
2810Sstevel@tonic-gate 		return (WALK_ERR);
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	if (mdb_vread(&mihp, sizeof (mihp), (uintptr_t)sym.st_value) == -1) {
2850Sstevel@tonic-gate 		mdb_warn("failed to read address of global MI Head "
2860Sstevel@tonic-gate 		    "mi_o_head_t at %p", (uintptr_t)sym.st_value);
2870Sstevel@tonic-gate 		return (WALK_ERR);
2880Sstevel@tonic-gate 	}
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	pwdp = mdb_alloc(sizeof (mi_payload_walk_data_t), UM_SLEEP);
2910Sstevel@tonic-gate 	pwdp->mi_pwd_data = mdb_alloc(arg->mi_pwa_size, UM_SLEEP);
2920Sstevel@tonic-gate 	wsp->walk_data = pwdp;
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
2950Sstevel@tonic-gate 		/* Do not immediately return WALK_DONE below */
2960Sstevel@tonic-gate 		pwdp->mi_pwd_first = NULL;
2970Sstevel@tonic-gate 		/* We determined where to begin */
2980Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)MIH2MIO(mihp);
2990Sstevel@tonic-gate 	} else {
3000Sstevel@tonic-gate 		/* Do not cycle through all of the MI_O objects */
3010Sstevel@tonic-gate 		pwdp->mi_pwd_first = (uintptr_t)MIH2MIO(mihp);
3020Sstevel@tonic-gate 		/* We were given where to begin */
3030Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)((MI_OP)wsp->walk_addr - 1);
3040Sstevel@tonic-gate 	}
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	if (mdb_layered_walk("genunix`mi", wsp) == -1) {
3070Sstevel@tonic-gate 		mdb_warn("failed to walk genunix`mi");
3080Sstevel@tonic-gate 		delete_mi_payload_walk_data(pwdp, arg->mi_pwa_size);
3090Sstevel@tonic-gate 		return (WALK_ERR);
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	return (WALK_NEXT);
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate int
3160Sstevel@tonic-gate mi_payload_walk_step(mdb_walk_state_t *wsp)
3170Sstevel@tonic-gate {
3180Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
3190Sstevel@tonic-gate 	mi_payload_walk_data_t *pwdp = wsp->walk_data;
3200Sstevel@tonic-gate 	void *payload = pwdp->mi_pwd_data;
3210Sstevel@tonic-gate 	uintptr_t payload_kaddr = (uintptr_t)((MI_OP)wsp->walk_addr + 1);
3220Sstevel@tonic-gate 	const MI_O *mio = wsp->walk_layer;
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	/* If this is a local walk, prevent cycling */
3250Sstevel@tonic-gate 	if (wsp->walk_addr == pwdp->mi_pwd_first)
3260Sstevel@tonic-gate 		return (WALK_DONE);
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	/*
3290Sstevel@tonic-gate 	 * This was a global walk, prevent reading this payload as the
3300Sstevel@tonic-gate 	 * initial MI_O is the head of the list and is not the header
3310Sstevel@tonic-gate 	 * to a valid payload
3320Sstevel@tonic-gate 	 */
3330Sstevel@tonic-gate 	if (pwdp->mi_pwd_first == NULL) {
3340Sstevel@tonic-gate 		pwdp->mi_pwd_first = wsp->walk_addr;
3350Sstevel@tonic-gate 		return (WALK_NEXT);
3360Sstevel@tonic-gate 	}
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	if (mio->mi_o_isdev == B_FALSE) {
3390Sstevel@tonic-gate 		/* mio is a module */
3400Sstevel@tonic-gate 		if (!(arg->mi_pwa_flags & MI_PAYLOAD_MODULE))
3410Sstevel@tonic-gate 			return (WALK_NEXT);
3420Sstevel@tonic-gate 	} else {
3430Sstevel@tonic-gate 		/* mio is a device */
3440Sstevel@tonic-gate 		if (!(arg->mi_pwa_flags & MI_PAYLOAD_DEVICE))
3450Sstevel@tonic-gate 			return (WALK_NEXT);
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	if (mdb_vread(payload, arg->mi_pwa_size, payload_kaddr) == -1) {
3490Sstevel@tonic-gate 		mdb_warn("failed to read payload at %p", payload_kaddr);
3500Sstevel@tonic-gate 		return (WALK_ERR);
3510Sstevel@tonic-gate 	}
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	return (wsp->walk_callback(payload_kaddr, payload, wsp->walk_cbdata));
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate void
3570Sstevel@tonic-gate mi_payload_walk_fini(mdb_walk_state_t *wsp)
3580Sstevel@tonic-gate {
3590Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	delete_mi_payload_walk_data(wsp->walk_data, arg->mi_pwa_size);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate const mi_payload_walk_arg_t mi_ar_arg = {
3650Sstevel@tonic-gate 	"arp", "ar_g_head", sizeof (ar_t),
3660Sstevel@tonic-gate 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
3670Sstevel@tonic-gate };
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate const mi_payload_walk_arg_t mi_icmp_arg = {
3700Sstevel@tonic-gate 	"icmp", "icmp_g_head", sizeof (icmp_t),
3710Sstevel@tonic-gate 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
3720Sstevel@tonic-gate };
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate const mi_payload_walk_arg_t mi_ill_arg =
3750Sstevel@tonic-gate 	{ "ip", "ip_g_head", sizeof (ill_t), MI_PAYLOAD_MODULE };
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate int
3780Sstevel@tonic-gate sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3790Sstevel@tonic-gate {
3800Sstevel@tonic-gate 	const char *optf = NULL;
3810Sstevel@tonic-gate 	const char *optt = NULL;
3820Sstevel@tonic-gate 	const char *optp = NULL;
3830Sstevel@tonic-gate 	int family, type, proto;
3840Sstevel@tonic-gate 	int filter = 0;
3850Sstevel@tonic-gate 	struct sonode so;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
3880Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`sonode", "genunix`sonode", argc,
3890Sstevel@tonic-gate 		    argv) == -1) {
3900Sstevel@tonic-gate 			mdb_warn("failed to walk sonode");
3910Sstevel@tonic-gate 			return (DCMD_ERR);
3920Sstevel@tonic-gate 		}
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 		return (DCMD_OK);
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
3980Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &optf,
3990Sstevel@tonic-gate 	    't', MDB_OPT_STR, &optt,
4000Sstevel@tonic-gate 	    'p', MDB_OPT_STR, &optp,
4010Sstevel@tonic-gate 	    NULL) != argc)
4020Sstevel@tonic-gate 		return (DCMD_USAGE);
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	if (optf != NULL) {
4050Sstevel@tonic-gate 		if (strcmp("inet", optf) == 0)
4060Sstevel@tonic-gate 			family = AF_INET;
4070Sstevel@tonic-gate 		else if (strcmp("inet6", optf) == 0)
4080Sstevel@tonic-gate 			family = AF_INET6;
4090Sstevel@tonic-gate 		else if (strcmp("unix", optf) == 0)
4100Sstevel@tonic-gate 			family = AF_UNIX;
4110Sstevel@tonic-gate 		else
4120Sstevel@tonic-gate 			family = mdb_strtoull(optf);
4130Sstevel@tonic-gate 		filter = 1;
4140Sstevel@tonic-gate 	}
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	if (optt != NULL) {
4170Sstevel@tonic-gate 		if (strcmp("stream", optt) == 0)
4180Sstevel@tonic-gate 			type = SOCK_STREAM;
4190Sstevel@tonic-gate 		else if (strcmp("dgram", optt) == 0)
4200Sstevel@tonic-gate 			type = SOCK_DGRAM;
4210Sstevel@tonic-gate 		else if (strcmp("raw", optt) == 0)
4220Sstevel@tonic-gate 			type = SOCK_RAW;
4230Sstevel@tonic-gate 		else
4240Sstevel@tonic-gate 			type = mdb_strtoull(optt);
4250Sstevel@tonic-gate 		filter = 1;
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	if (optp != NULL) {
4290Sstevel@tonic-gate 		proto = mdb_strtoull(optp);
4300Sstevel@tonic-gate 		filter = 1;
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !filter) {
4340Sstevel@tonic-gate 		mdb_printf("%<u>%-?s Family Type Proto State Mode Flag "
4350Sstevel@tonic-gate 		    "AccessVP%</u>\n", "Sonode:");
4360Sstevel@tonic-gate 	}
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	if (mdb_vread(&so, sizeof (so), addr) == -1) {
4390Sstevel@tonic-gate 		mdb_warn("failed to read sonode at %p", addr);
4400Sstevel@tonic-gate 		return (DCMD_ERR);
4410Sstevel@tonic-gate 	}
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	if ((optf != NULL) && (so.so_family != family))
4440Sstevel@tonic-gate 		return (DCMD_OK);
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	if ((optt != NULL) && (so.so_type != type))
4470Sstevel@tonic-gate 		return (DCMD_OK);
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	if ((optp != NULL) && (so.so_protocol != proto))
4500Sstevel@tonic-gate 		return (DCMD_OK);
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	if (filter) {
4530Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
4540Sstevel@tonic-gate 		return (DCMD_OK);
4550Sstevel@tonic-gate 	}
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	mdb_printf("%0?p ", addr);
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	switch (so.so_family) {
4600Sstevel@tonic-gate 	    case AF_UNIX:
4610Sstevel@tonic-gate 		mdb_printf("unix  ");
4620Sstevel@tonic-gate 		break;
4630Sstevel@tonic-gate 	    case AF_INET:
4640Sstevel@tonic-gate 		mdb_printf("inet  ");
4650Sstevel@tonic-gate 		break;
4660Sstevel@tonic-gate 	    case AF_INET6:
4670Sstevel@tonic-gate 		mdb_printf("inet6 ");
4680Sstevel@tonic-gate 		break;
4690Sstevel@tonic-gate 	    default:
4700Sstevel@tonic-gate 		mdb_printf("%6hi", so.so_family);
4710Sstevel@tonic-gate 	}
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	switch (so.so_type) {
4740Sstevel@tonic-gate 	    case SOCK_STREAM:
4750Sstevel@tonic-gate 		mdb_printf(" strm");
4760Sstevel@tonic-gate 		break;
4770Sstevel@tonic-gate 	    case SOCK_DGRAM:
4780Sstevel@tonic-gate 		mdb_printf(" dgrm");
4790Sstevel@tonic-gate 		break;
4800Sstevel@tonic-gate 	    case SOCK_RAW:
4810Sstevel@tonic-gate 		mdb_printf(" raw ");
4820Sstevel@tonic-gate 		break;
4830Sstevel@tonic-gate 	    default:
4840Sstevel@tonic-gate 		mdb_printf(" %4hi", so.so_type);
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	mdb_printf(" %5hi %05x %04x %04hx %0?p\n",
4880Sstevel@tonic-gate 	    so.so_protocol, so.so_state, so.so_mode,
4890Sstevel@tonic-gate 	    so.so_flag, so.so_accessvp);
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	return (DCMD_OK);
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate #define	MI_PAYLOAD	0x1
4950Sstevel@tonic-gate #define	MI_DEVICE	0x2
4960Sstevel@tonic-gate #define	MI_MODULE	0x4
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate int
4990Sstevel@tonic-gate mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate 	uint_t opts = 0;
5020Sstevel@tonic-gate 	MI_O	mio;
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
5050Sstevel@tonic-gate 		return (DCMD_USAGE);
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
5080Sstevel@tonic-gate 	    'p', MDB_OPT_SETBITS, MI_PAYLOAD, &opts,
5090Sstevel@tonic-gate 	    'd', MDB_OPT_SETBITS, MI_DEVICE, &opts,
5100Sstevel@tonic-gate 	    'm', MDB_OPT_SETBITS, MI_MODULE, &opts,
5110Sstevel@tonic-gate 	    NULL) != argc)
5120Sstevel@tonic-gate 		return (DCMD_USAGE);
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	if ((opts & (MI_DEVICE | MI_MODULE)) == (MI_DEVICE | MI_MODULE)) {
5150Sstevel@tonic-gate 		mdb_warn("at most one filter, d for devices or m "
5160Sstevel@tonic-gate 		    "for modules, may be specified\n");
5170Sstevel@tonic-gate 		return (DCMD_USAGE);
5180Sstevel@tonic-gate 	}
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	if ((opts == 0) && (DCMD_HDRSPEC(flags))) {
5210Sstevel@tonic-gate 		mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n",
5220Sstevel@tonic-gate 		    "MI_O", "Next", "Prev");
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	if (mdb_vread(&mio, sizeof (mio), addr) == -1) {
5260Sstevel@tonic-gate 		mdb_warn("failed to read mi object MI_O at %p", addr);
5270Sstevel@tonic-gate 		return (DCMD_ERR);
5280Sstevel@tonic-gate 	}
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	if (opts != 0) {
5310Sstevel@tonic-gate 		if (mio.mi_o_isdev == B_FALSE) {
5320Sstevel@tonic-gate 			/* mio is a module */
5330Sstevel@tonic-gate 			if (!(opts & MI_MODULE) && (opts & MI_DEVICE))
5340Sstevel@tonic-gate 				return (DCMD_OK);
5350Sstevel@tonic-gate 		} else {
5360Sstevel@tonic-gate 			/* mio is a device */
5370Sstevel@tonic-gate 			if (!(opts & MI_DEVICE) && (opts & MI_MODULE))
5380Sstevel@tonic-gate 				return (DCMD_OK);
5390Sstevel@tonic-gate 		}
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 		if (opts & MI_PAYLOAD)
5420Sstevel@tonic-gate 			mdb_printf("%p\n", addr + sizeof (MI_O));
5430Sstevel@tonic-gate 		else
5440Sstevel@tonic-gate 			mdb_printf("%p\n", addr);
5450Sstevel@tonic-gate 		return (DCMD_OK);
5460Sstevel@tonic-gate 	}
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev);
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	if (mio.mi_o_isdev == B_FALSE)
5510Sstevel@tonic-gate 		mdb_printf("FALSE");
5520Sstevel@tonic-gate 	else
5530Sstevel@tonic-gate 		mdb_printf("TRUE ");
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	mdb_printf(" %0?p\n", mio.mi_o_dev);
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	return (DCMD_OK);
5580Sstevel@tonic-gate }
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate static void
5610Sstevel@tonic-gate netstat_tcp_verbose_pr(const tcp_t *tcp)
5620Sstevel@tonic-gate {
5630Sstevel@tonic-gate 	mdb_printf("       %5i %08x %08x %5i %08x %08x %5li %5i\n",
5640Sstevel@tonic-gate 	    tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
5650Sstevel@tonic-gate 	    tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
5660Sstevel@tonic-gate }
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate /*ARGSUSED*/
5690Sstevel@tonic-gate static int
5700Sstevel@tonic-gate netstat_tcp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data, int af)
5710Sstevel@tonic-gate {
5720Sstevel@tonic-gate 	const uintptr_t opts = (uintptr_t)cb_data;
5730Sstevel@tonic-gate 	static size_t itc_size = 0;
5740Sstevel@tonic-gate 	uintptr_t tcp_kaddr;
5750Sstevel@tonic-gate 	conn_t *connp;
5760Sstevel@tonic-gate 	tcp_t *tcp;
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	if (itc_size == 0) {
5790Sstevel@tonic-gate 		mdb_ctf_id_t id;
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 		if (mdb_ctf_lookup_by_name("itc_t", &id) != 0) {
5820Sstevel@tonic-gate 			mdb_warn("failed to lookup type 'itc_t'");
5830Sstevel@tonic-gate 			return (WALK_ERR);
5840Sstevel@tonic-gate 		}
5850Sstevel@tonic-gate 		itc_size = mdb_ctf_type_size(id);
5860Sstevel@tonic-gate 	}
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	connp = (conn_t *)mdb_alloc(itc_size, UM_SLEEP | UM_GC);
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	if (mdb_vread(connp, itc_size, kaddr) == -1) {
5910Sstevel@tonic-gate 		mdb_warn("failed to read connection info at %p", kaddr);
5920Sstevel@tonic-gate 		return (WALK_ERR);
5930Sstevel@tonic-gate 	}
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	tcp_kaddr = (uintptr_t)connp->conn_tcp;
5960Sstevel@tonic-gate 	tcp = (tcp_t *)((uintptr_t)connp + (tcp_kaddr - kaddr));
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	if ((uintptr_t)tcp < (uintptr_t)connp ||
599741Smasputra 	    (uintptr_t)(tcp + 1) > (uintptr_t)connp + itc_size ||
6000Sstevel@tonic-gate 	    (uintptr_t)tcp->tcp_connp != kaddr) {
6010Sstevel@tonic-gate 		mdb_warn("conn_tcp %p is invalid", tcp_kaddr);
6020Sstevel@tonic-gate 		return (WALK_NEXT);
6030Sstevel@tonic-gate 	}
6040Sstevel@tonic-gate 	connp->conn_tcp = tcp;
6050Sstevel@tonic-gate 	tcp->tcp_connp = connp;
6060Sstevel@tonic-gate 
607741Smasputra 	if (!((opts & NETSTAT_ALL) || net_tcp_active(tcp)) ||
6080Sstevel@tonic-gate 	    (af == AF_INET && !net_tcp_ipv4(tcp)) ||
6090Sstevel@tonic-gate 	    (af == AF_INET6 && !net_tcp_ipv6(tcp))) {
6100Sstevel@tonic-gate 		return (WALK_NEXT);
6110Sstevel@tonic-gate 	}
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state);
6140Sstevel@tonic-gate 	if (af == AF_INET) {
6150Sstevel@tonic-gate 		net_ipv4addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport);
6160Sstevel@tonic-gate 		mdb_printf(" ");
6170Sstevel@tonic-gate 		net_ipv4addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport);
6180Sstevel@tonic-gate 	} else if (af == AF_INET6) {
6190Sstevel@tonic-gate 		net_ipv6addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport);
6200Sstevel@tonic-gate 		mdb_printf(" ");
6210Sstevel@tonic-gate 		net_ipv6addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport);
6220Sstevel@tonic-gate 	}
6230Sstevel@tonic-gate 	mdb_printf(" %4i\n", connp->conn_zoneid);
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	if (opts & NETSTAT_VERBOSE)
6260Sstevel@tonic-gate 		netstat_tcp_verbose_pr(tcp);
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	return (WALK_NEXT);
6290Sstevel@tonic-gate }
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate static int
6320Sstevel@tonic-gate netstat_tcpv4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
6330Sstevel@tonic-gate {
6340Sstevel@tonic-gate 	return (netstat_tcp_cb(kaddr, walk_data, cb_data, AF_INET));
6350Sstevel@tonic-gate }
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate static int
6380Sstevel@tonic-gate netstat_tcpv6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
6390Sstevel@tonic-gate {
6400Sstevel@tonic-gate 	return (netstat_tcp_cb(kaddr, walk_data, cb_data, AF_INET6));
6410Sstevel@tonic-gate }
6420Sstevel@tonic-gate 
643741Smasputra /*ARGSUSED*/
6440Sstevel@tonic-gate static int
645741Smasputra netstat_udp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data, int af)
6460Sstevel@tonic-gate {
6470Sstevel@tonic-gate 	const uintptr_t opts = (uintptr_t)cb_data;
648741Smasputra 	udp_t udp;
649741Smasputra 	conn_t connp;
650741Smasputra 
651741Smasputra 	if (mdb_vread(&udp, sizeof (udp_t), kaddr) == -1) {
652741Smasputra 		mdb_warn("failed to read udp at %p", kaddr);
653741Smasputra 		return (WALK_ERR);
654741Smasputra 	}
6550Sstevel@tonic-gate 
656741Smasputra 	if (mdb_vread(&connp, sizeof (conn_t),
657741Smasputra 	    (uintptr_t)udp.udp_connp) == -1) {
658741Smasputra 		mdb_warn("failed to read udp_connp at %p",
659741Smasputra 		    (uintptr_t)udp.udp_connp);
660741Smasputra 		return (WALK_ERR);
661741Smasputra 	}
6620Sstevel@tonic-gate 
663741Smasputra 	if (!((opts & NETSTAT_ALL) || net_udp_active(&udp)) ||
664741Smasputra 	    (af == AF_INET && !net_udp_ipv4(&udp)) ||
665741Smasputra 	    (af == AF_INET6 && !net_udp_ipv6(&udp))) {
666741Smasputra 		return (WALK_NEXT);
667741Smasputra 	}
668741Smasputra 
669741Smasputra 	mdb_printf("%0?p %2i ", kaddr, udp.udp_state);
670741Smasputra 	if (af == AF_INET) {
671741Smasputra 		net_ipv4addrport_pr(&udp.udp_v6src, udp.udp_port);
672741Smasputra 		mdb_printf(" ");
673741Smasputra 		net_ipv4addrport_pr(&udp.udp_v6dst, udp.udp_dstport);
674741Smasputra 	} else if (af == AF_INET6) {
675741Smasputra 		net_ipv6addrport_pr(&udp.udp_v6src, udp.udp_port);
676741Smasputra 		mdb_printf(" ");
677741Smasputra 		net_ipv6addrport_pr(&udp.udp_v6dst, udp.udp_dstport);
678741Smasputra 	}
679741Smasputra 	mdb_printf(" %4i\n", connp.conn_zoneid);
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	return (WALK_NEXT);
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate static int
685741Smasputra netstat_udpv4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
686741Smasputra {
687741Smasputra 	return (netstat_udp_cb(kaddr, walk_data, cb_data, AF_INET));
688741Smasputra }
689741Smasputra 
690741Smasputra static int
6910Sstevel@tonic-gate netstat_udpv6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
6920Sstevel@tonic-gate {
693741Smasputra 	return (netstat_udp_cb(kaddr, walk_data, cb_data, AF_INET6));
6940Sstevel@tonic-gate }
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate /*
6970Sstevel@tonic-gate  * print the address of a unix domain socket
6980Sstevel@tonic-gate  *
6990Sstevel@tonic-gate  * so is the address of a AF_UNIX struct sonode in mdb's address space
7000Sstevel@tonic-gate  * soa is the address of the struct soaddr to print
7010Sstevel@tonic-gate  *
7020Sstevel@tonic-gate  * returns 0 on success, -1 otherwise
7030Sstevel@tonic-gate  */
7040Sstevel@tonic-gate static int
7050Sstevel@tonic-gate netstat_unix_name_pr(const struct sonode *so, const struct soaddr *soa)
7060Sstevel@tonic-gate {
7070Sstevel@tonic-gate 	const char none[] = " (none)";
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) {
7100Sstevel@tonic-gate 		if (so->so_state & SS_FADDR_NOXLATE) {
7110Sstevel@tonic-gate 			mdb_printf("%-14s ", " (socketpair)");
7120Sstevel@tonic-gate 		} else {
7130Sstevel@tonic-gate 			if (soa->soa_len > sizeof (sa_family_t)) {
7140Sstevel@tonic-gate 				char addr[MAXPATHLEN + 1];
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 				if (mdb_readstr(addr, sizeof (addr),
7170Sstevel@tonic-gate 				    (uintptr_t)&soa->soa_sa->sa_data) == -1) {
7180Sstevel@tonic-gate 					mdb_warn("failed to read unix address "
7190Sstevel@tonic-gate 					    "at %p", &soa->soa_sa->sa_data);
7200Sstevel@tonic-gate 					return (-1);
7210Sstevel@tonic-gate 				}
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 				mdb_printf("%-14s ", addr);
7240Sstevel@tonic-gate 			} else {
7250Sstevel@tonic-gate 				mdb_printf("%-14s ", none);
7260Sstevel@tonic-gate 			}
7270Sstevel@tonic-gate 		}
7280Sstevel@tonic-gate 	} else {
7290Sstevel@tonic-gate 		mdb_printf("%-14s ", none);
7300Sstevel@tonic-gate 	}
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	return (0);
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate /* based on sockfs_snapshot */
7360Sstevel@tonic-gate /*ARGSUSED*/
7370Sstevel@tonic-gate static int
7380Sstevel@tonic-gate netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
7390Sstevel@tonic-gate {
7400Sstevel@tonic-gate 	const struct sonode *so = walk_data;
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 	if (so->so_accessvp == NULL)
7430Sstevel@tonic-gate 		return (WALK_NEXT);
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	if (so->so_family != AF_UNIX) {
7460Sstevel@tonic-gate 		mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr);
7470Sstevel@tonic-gate 		return (WALK_ERR);
7480Sstevel@tonic-gate 	}
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	mdb_printf("%-?p ", kaddr);
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	switch (so->so_serv_type) {
7530Sstevel@tonic-gate 	    case T_CLTS:
7540Sstevel@tonic-gate 		mdb_printf("%-10s ", "dgram");
7550Sstevel@tonic-gate 		break;
7560Sstevel@tonic-gate 	    case T_COTS:
7570Sstevel@tonic-gate 		mdb_printf("%-10s ", "stream");
7580Sstevel@tonic-gate 		break;
7590Sstevel@tonic-gate 	    case T_COTS_ORD:
7600Sstevel@tonic-gate 		mdb_printf("%-10s ", "stream-ord");
7610Sstevel@tonic-gate 		break;
7620Sstevel@tonic-gate 	    default:
7630Sstevel@tonic-gate 		    mdb_printf("%-10i ", so->so_serv_type);
7640Sstevel@tonic-gate 	}
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	if ((so->so_state & SS_ISBOUND) &&
7670Sstevel@tonic-gate 	    (so->so_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
7680Sstevel@tonic-gate 		mdb_printf("%0?p ", so->so_ux_laddr.soua_vp);
7690Sstevel@tonic-gate 	} else {
7700Sstevel@tonic-gate 		mdb_printf("%0?p ", NULL);
7710Sstevel@tonic-gate 	}
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	if ((so->so_state & SS_ISCONNECTED) &&
7740Sstevel@tonic-gate 	    (so->so_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
7750Sstevel@tonic-gate 		mdb_printf("%0?p ", so->so_ux_faddr.soua_vp);
7760Sstevel@tonic-gate 	} else {
7770Sstevel@tonic-gate 		mdb_printf("%0?p ", NULL);
7780Sstevel@tonic-gate 	}
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	if (netstat_unix_name_pr(so, &so->so_laddr) == -1)
7810Sstevel@tonic-gate 		return (WALK_ERR);
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 	if (netstat_unix_name_pr(so, &so->so_faddr) == -1)
7840Sstevel@tonic-gate 		return (WALK_ERR);
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	mdb_printf("%4i\n", so->so_zoneid);
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	return (WALK_NEXT);
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate static void
7920Sstevel@tonic-gate netstat_tcp_verbose_header_pr(void)
7930Sstevel@tonic-gate {
7940Sstevel@tonic-gate 	mdb_printf("       %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n",
7950Sstevel@tonic-gate 	    "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss");
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate 
798*1676Sjpk static void
799*1676Sjpk get_ifname(const ire_t *ire, char *intf)
800*1676Sjpk {
801*1676Sjpk 	ill_t ill;
802*1676Sjpk 
803*1676Sjpk 	*intf = '\0';
804*1676Sjpk 	if (ire->ire_type == IRE_CACHE) {
805*1676Sjpk 		queue_t stq;
806*1676Sjpk 
807*1676Sjpk 		if (mdb_vread(&stq, sizeof (stq), (uintptr_t)ire->ire_stq) ==
808*1676Sjpk 		    -1)
809*1676Sjpk 			return;
810*1676Sjpk 		if (mdb_vread(&ill, sizeof (ill), (uintptr_t)stq.q_ptr) == -1)
811*1676Sjpk 			return;
812*1676Sjpk 		(void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
813*1676Sjpk 		    (uintptr_t)ill.ill_name);
814*1676Sjpk 	} else if (ire->ire_ipif != NULL) {
815*1676Sjpk 		ipif_t ipif;
816*1676Sjpk 		char *cp;
817*1676Sjpk 
818*1676Sjpk 		if (mdb_vread(&ipif, sizeof (ipif),
819*1676Sjpk 		    (uintptr_t)ire->ire_ipif) == -1)
820*1676Sjpk 			return;
821*1676Sjpk 		if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ipif.ipif_ill) ==
822*1676Sjpk 		    -1)
823*1676Sjpk 			return;
824*1676Sjpk 		(void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
825*1676Sjpk 		    (uintptr_t)ill.ill_name);
826*1676Sjpk 		if (ipif.ipif_id != 0) {
827*1676Sjpk 			cp = intf + strlen(intf);
828*1676Sjpk 			(void) mdb_snprintf(cp, LIFNAMSIZ + 1 - (cp - intf),
829*1676Sjpk 			    ":%u", ipif.ipif_id);
830*1676Sjpk 		}
831*1676Sjpk 	}
832*1676Sjpk }
833*1676Sjpk 
834*1676Sjpk static void
835*1676Sjpk get_v4flags(const ire_t *ire, char *flags)
836*1676Sjpk {
837*1676Sjpk 	(void) strcpy(flags, "U");
838*1676Sjpk 	if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX ||
839*1676Sjpk 	    ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT)
840*1676Sjpk 		(void) strcat(flags, "G");
841*1676Sjpk 	if (ire->ire_mask == IP_HOST_MASK)
842*1676Sjpk 		(void) strcat(flags, "H");
843*1676Sjpk 	if (ire->ire_type == IRE_HOST_REDIRECT)
844*1676Sjpk 		(void) strcat(flags, "D");
845*1676Sjpk 	if (ire->ire_type == IRE_CACHE)
846*1676Sjpk 		(void) strcat(flags, "A");
847*1676Sjpk 	if (ire->ire_type == IRE_BROADCAST)
848*1676Sjpk 		(void) strcat(flags, "B");
849*1676Sjpk 	if (ire->ire_type == IRE_LOCAL)
850*1676Sjpk 		(void) strcat(flags, "L");
851*1676Sjpk 	if (ire->ire_flags & RTF_MULTIRT)
852*1676Sjpk 		(void) strcat(flags, "M");
853*1676Sjpk 	if (ire->ire_flags & RTF_SETSRC)
854*1676Sjpk 		(void) strcat(flags, "S");
855*1676Sjpk }
856*1676Sjpk 
857*1676Sjpk static int
858*1676Sjpk ip_mask_to_plen(ipaddr_t mask)
859*1676Sjpk {
860*1676Sjpk 	int i;
861*1676Sjpk 
862*1676Sjpk 	if (mask == 0)
863*1676Sjpk 		return (0);
864*1676Sjpk 	for (i = 32; i > 0; i--, mask >>= 1)
865*1676Sjpk 		if (mask & 1)
866*1676Sjpk 			break;
867*1676Sjpk 	return (i);
868*1676Sjpk }
869*1676Sjpk 
870*1676Sjpk static int
871*1676Sjpk netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
872*1676Sjpk {
873*1676Sjpk 	const ire_t *ire = walk_data;
874*1676Sjpk 	uint_t *opts = cb_data;
875*1676Sjpk 	ipaddr_t gate;
876*1676Sjpk 	char flags[10], intf[LIFNAMSIZ + 1];
877*1676Sjpk 
878*1676Sjpk 	if (ire->ire_ipversion != IPV4_VERSION || ire->ire_in_src_addr != 0 ||
879*1676Sjpk 	    ire->ire_in_ill != NULL)
880*1676Sjpk 		return (WALK_NEXT);
881*1676Sjpk 
882*1676Sjpk 	if (!(*opts & NETSTAT_ALL) && (ire->ire_type == IRE_CACHE ||
883*1676Sjpk 	    ire->ire_type == IRE_BROADCAST || ire->ire_type == IRE_LOCAL))
884*1676Sjpk 		return (WALK_NEXT);
885*1676Sjpk 
886*1676Sjpk 	if (*opts & NETSTAT_FIRST) {
887*1676Sjpk 		*opts &= ~NETSTAT_FIRST;
888*1676Sjpk 		mdb_printf("%<u>%s Table: IPv4%</u>\n",
889*1676Sjpk 		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
890*1676Sjpk 		if (*opts & NETSTAT_VERBOSE) {
891*1676Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt  "
892*1676Sjpk 			    " Ref Flg Out   In/Fwd%</u>\n",
893*1676Sjpk 			    "Address", ADDR_V4_WIDTH, "Destination",
894*1676Sjpk 			    ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway");
895*1676Sjpk 		} else {
896*1676Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref  Use   "
897*1676Sjpk 			    "Interface%</u>\n",
898*1676Sjpk 			    "Address", ADDR_V4_WIDTH, "Destination",
899*1676Sjpk 			    ADDR_V4_WIDTH, "Gateway");
900*1676Sjpk 		}
901*1676Sjpk 	}
902*1676Sjpk 
903*1676Sjpk 	gate = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK|IRE_BROADCAST)) ?
904*1676Sjpk 	    ire->ire_src_addr : ire->ire_gateway_addr;
905*1676Sjpk 
906*1676Sjpk 	get_v4flags(ire, flags);
907*1676Sjpk 
908*1676Sjpk 	get_ifname(ire, intf);
909*1676Sjpk 
910*1676Sjpk 	if (*opts & NETSTAT_VERBOSE) {
911*1676Sjpk 		mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u "
912*1676Sjpk 		    "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH,
913*1676Sjpk 		    ire->ire_mask, ADDR_V4_WIDTH, gate, intf,
914*1676Sjpk 		    ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ',
915*1676Sjpk 		    ire->ire_uinfo.iulp_rtt, ire->ire_refcnt, flags,
916*1676Sjpk 		    ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
917*1676Sjpk 	} else {
918*1676Sjpk 		mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr,
919*1676Sjpk 		    ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags,
920*1676Sjpk 		    ire->ire_refcnt,
921*1676Sjpk 		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
922*1676Sjpk 	}
923*1676Sjpk 
924*1676Sjpk 	return (WALK_NEXT);
925*1676Sjpk }
926*1676Sjpk 
927*1676Sjpk static int
928*1676Sjpk netstat_irev4src_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
929*1676Sjpk {
930*1676Sjpk 	const ire_t *ire = walk_data;
931*1676Sjpk 	uint_t *opts = cb_data;
932*1676Sjpk 	ipaddr_t gate;
933*1676Sjpk 	char flags[10], intf[LIFNAMSIZ + 1], srcif[LIFNAMSIZ + 1];
934*1676Sjpk 	char dest[ADDR_V4_WIDTH + 3 + 1];
935*1676Sjpk 	ill_t ill;
936*1676Sjpk 
937*1676Sjpk 	if (ire->ire_ipversion != IPV4_VERSION ||
938*1676Sjpk 	    (ire->ire_in_src_addr == 0 && ire->ire_in_ill == NULL))
939*1676Sjpk 		return (WALK_NEXT);
940*1676Sjpk 
941*1676Sjpk 	if (!(*opts & NETSTAT_ALL) && (ire->ire_type == IRE_CACHE ||
942*1676Sjpk 	    ire->ire_type == IRE_BROADCAST || ire->ire_type == IRE_LOCAL))
943*1676Sjpk 		return (WALK_NEXT);
944*1676Sjpk 
945*1676Sjpk 	if (*opts & NETSTAT_FIRST) {
946*1676Sjpk 		*opts &= ~NETSTAT_FIRST;
947*1676Sjpk 		mdb_printf("\n%<u>%s Table: IPv4 Source-Specific%</u>\n",
948*1676Sjpk 		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
949*1676Sjpk 		if (*opts & NETSTAT_VERBOSE) {
950*1676Sjpk 			mdb_printf("%<u>%-?s %-*s In If       %-*s %-*s "
951*1676Sjpk 			    "Out If      Mxfrg Rtt   Ref Flg Out   In/Fwd"
952*1676Sjpk 			    "%</u>\n",
953*1676Sjpk 			    "Address", ADDR_V4_WIDTH+3, "Destination",
954*1676Sjpk 			    ADDR_V4_WIDTH, "Source", ADDR_V4_WIDTH, "Gateway");
955*1676Sjpk 		} else {
956*1676Sjpk 			mdb_printf("%<u>%-?s %-*s In If    %-*s %-*s Flags "
957*1676Sjpk 			    "Ref  Use   Out If%</u>\n",
958*1676Sjpk 			    "Address", ADDR_V4_WIDTH+3, "Destination",
959*1676Sjpk 			    ADDR_V4_WIDTH, "Source", ADDR_V4_WIDTH, "Gateway");
960*1676Sjpk 		}
961*1676Sjpk 	}
962*1676Sjpk 
963*1676Sjpk 	gate = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK|IRE_BROADCAST)) ?
964*1676Sjpk 	    ire->ire_src_addr : ire->ire_gateway_addr;
965*1676Sjpk 
966*1676Sjpk 	get_v4flags(ire, flags);
967*1676Sjpk 
968*1676Sjpk 	get_ifname(ire, intf);
969*1676Sjpk 
970*1676Sjpk 	srcif[0] = '\0';
971*1676Sjpk 	if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ire->ire_in_ill) != -1)
972*1676Sjpk 		(void) mdb_readstr(srcif, MIN(LIFNAMSIZ, ill.ill_name_length),
973*1676Sjpk 		    (uintptr_t)ill.ill_name);
974*1676Sjpk 
975*1676Sjpk 	if (ire->ire_in_src_addr != 0 && ire->ire_addr == 0 &&
976*1676Sjpk 	    ire->ire_mask == 0)
977*1676Sjpk 		strcpy(dest, "  --");
978*1676Sjpk 	else
979*1676Sjpk 		mdb_snprintf(dest, sizeof (dest), "%I/%d", ire->ire_addr,
980*1676Sjpk 		    ip_mask_to_plen(ire->ire_mask));
981*1676Sjpk 
982*1676Sjpk 	if (*opts & NETSTAT_VERBOSE) {
983*1676Sjpk 		mdb_printf("%?p %-*s %-11s %-*I %-*I %-11s %5u%c %4u %3u %-3s "
984*1676Sjpk 		    "%5u %u\n", kaddr, ADDR_V4_WIDTH+3, dest, srcif,
985*1676Sjpk 		    ADDR_V4_WIDTH, ire->ire_in_src_addr, ADDR_V4_WIDTH, gate,
986*1676Sjpk 		    intf, ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ',
987*1676Sjpk 		    ire->ire_uinfo.iulp_rtt, ire->ire_refcnt, flags,
988*1676Sjpk 		    ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
989*1676Sjpk 	} else {
990*1676Sjpk 		mdb_printf("%?p %-*s %-8s %-*I %-*I %-5s %4u %5u %s\n", kaddr,
991*1676Sjpk 		    ADDR_V4_WIDTH+3, dest, srcif, ADDR_V4_WIDTH,
992*1676Sjpk 		    ire->ire_in_src_addr, ADDR_V4_WIDTH, gate, flags,
993*1676Sjpk 		    ire->ire_refcnt,
994*1676Sjpk 		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
995*1676Sjpk 	}
996*1676Sjpk 
997*1676Sjpk 	return (WALK_NEXT);
998*1676Sjpk }
999*1676Sjpk 
1000*1676Sjpk int
1001*1676Sjpk ip_mask_to_plen_v6(const in6_addr_t *v6mask)
1002*1676Sjpk {
1003*1676Sjpk 	int plen;
1004*1676Sjpk 	int i;
1005*1676Sjpk 	uint32_t val;
1006*1676Sjpk 
1007*1676Sjpk 	for (i = 3; i >= 0; i--)
1008*1676Sjpk 		if (v6mask->s6_addr32[i] != 0)
1009*1676Sjpk 			break;
1010*1676Sjpk 	if (i < 0)
1011*1676Sjpk 		return (0);
1012*1676Sjpk 	plen = 32 + 32 * i;
1013*1676Sjpk 	val = v6mask->s6_addr32[i];
1014*1676Sjpk 	while (!(val & 1)) {
1015*1676Sjpk 		val >>= 1;
1016*1676Sjpk 		plen--;
1017*1676Sjpk 	}
1018*1676Sjpk 
1019*1676Sjpk 	return (plen);
1020*1676Sjpk }
1021*1676Sjpk 
1022*1676Sjpk static int
1023*1676Sjpk netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
1024*1676Sjpk {
1025*1676Sjpk 	const ire_t *ire = walk_data;
1026*1676Sjpk 	uint_t *opts = cb_data;
1027*1676Sjpk 	const in6_addr_t *gatep;
1028*1676Sjpk 	char deststr[ADDR_V6_WIDTH + 5];
1029*1676Sjpk 	char flags[10], intf[LIFNAMSIZ + 1];
1030*1676Sjpk 	int masklen;
1031*1676Sjpk 
1032*1676Sjpk 	if (ire->ire_ipversion != IPV6_VERSION)
1033*1676Sjpk 		return (WALK_NEXT);
1034*1676Sjpk 
1035*1676Sjpk 	if (!(*opts & NETSTAT_ALL) && ire->ire_type == IRE_CACHE)
1036*1676Sjpk 		return (WALK_NEXT);
1037*1676Sjpk 
1038*1676Sjpk 	if (*opts & NETSTAT_FIRST) {
1039*1676Sjpk 		*opts &= ~NETSTAT_FIRST;
1040*1676Sjpk 		mdb_printf("\n%<u>%s Table: IPv6%</u>\n",
1041*1676Sjpk 		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
1042*1676Sjpk 		if (*opts & NETSTAT_VERBOSE) {
1043*1676Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s If    PMTU   Rtt   Ref "
1044*1676Sjpk 			    "Flags Out    In/Fwd%</u>\n",
1045*1676Sjpk 			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
1046*1676Sjpk 			    ADDR_V6_WIDTH, "Gateway");
1047*1676Sjpk 		} else {
1048*1676Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use    If"
1049*1676Sjpk 			    "%</u>\n",
1050*1676Sjpk 			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
1051*1676Sjpk 			    ADDR_V6_WIDTH, "Gateway");
1052*1676Sjpk 		}
1053*1676Sjpk 	}
1054*1676Sjpk 
1055*1676Sjpk 	gatep = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK)) ?
1056*1676Sjpk 	    &ire->ire_src_addr_v6 : &ire->ire_gateway_addr_v6;
1057*1676Sjpk 
1058*1676Sjpk 	masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6);
1059*1676Sjpk 	(void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d",
1060*1676Sjpk 	    &ire->ire_addr_v6, masklen);
1061*1676Sjpk 
1062*1676Sjpk 	(void) strcpy(flags, "U");
1063*1676Sjpk 	if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX ||
1064*1676Sjpk 	    ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT)
1065*1676Sjpk 		(void) strcat(flags, "G");
1066*1676Sjpk 	if (masklen == IPV6_ABITS)
1067*1676Sjpk 		(void) strcat(flags, "H");
1068*1676Sjpk 	if (ire->ire_type == IRE_HOST_REDIRECT)
1069*1676Sjpk 		(void) strcat(flags, "D");
1070*1676Sjpk 	if (ire->ire_type == IRE_CACHE)
1071*1676Sjpk 		(void) strcat(flags, "A");
1072*1676Sjpk 	if (ire->ire_type == IRE_LOCAL)
1073*1676Sjpk 		(void) strcat(flags, "L");
1074*1676Sjpk 	if (ire->ire_flags & RTF_MULTIRT)
1075*1676Sjpk 		(void) strcat(flags, "M");
1076*1676Sjpk 	if (ire->ire_flags & RTF_SETSRC)
1077*1676Sjpk 		(void) strcat(flags, "S");
1078*1676Sjpk 
1079*1676Sjpk 	get_ifname(ire, intf);
1080*1676Sjpk 
1081*1676Sjpk 	if (*opts & NETSTAT_VERBOSE) {
1082*1676Sjpk 		mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n",
1083*1676Sjpk 		    kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep,
1084*1676Sjpk 		    intf, ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ',
1085*1676Sjpk 		    ire->ire_uinfo.iulp_rtt, ire->ire_refcnt,
1086*1676Sjpk 		    flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
1087*1676Sjpk 	} else {
1088*1676Sjpk 		mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr,
1089*1676Sjpk 		    ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags,
1090*1676Sjpk 		    ire->ire_refcnt,
1091*1676Sjpk 		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
1092*1676Sjpk 	}
1093*1676Sjpk 
1094*1676Sjpk 	return (WALK_NEXT);
1095*1676Sjpk }
1096*1676Sjpk 
10970Sstevel@tonic-gate /*ARGSUSED*/
10980Sstevel@tonic-gate int
10990Sstevel@tonic-gate netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
11000Sstevel@tonic-gate {
11010Sstevel@tonic-gate 	uint_t opts = 0;
11020Sstevel@tonic-gate 	const char *optf = NULL;
11030Sstevel@tonic-gate 	const char *optP = NULL;
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
11060Sstevel@tonic-gate 	    'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts,
11070Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &optf,
11080Sstevel@tonic-gate 	    'P', MDB_OPT_STR, &optP,
1109*1676Sjpk 	    'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts,
1110*1676Sjpk 	    'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts,
11110Sstevel@tonic-gate 	    NULL) != argc)
11120Sstevel@tonic-gate 		return (DCMD_USAGE);
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	if (optP != NULL) {
11150Sstevel@tonic-gate 		if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0))
11160Sstevel@tonic-gate 			return (DCMD_USAGE);
1117*1676Sjpk 		if (opts & NETSTAT_ROUTE)
1118*1676Sjpk 			return (DCMD_USAGE);
11190Sstevel@tonic-gate 	}
11200Sstevel@tonic-gate 
1121*1676Sjpk 	if (optf == NULL)
1122*1676Sjpk 		opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX;
1123*1676Sjpk 	else if (strcmp("inet", optf) == 0)
1124*1676Sjpk 		opts |= NETSTAT_V4;
1125*1676Sjpk 	else if (strcmp("inet6", optf) == 0)
1126*1676Sjpk 		opts |= NETSTAT_V6;
1127*1676Sjpk 	else if (strcmp("unix", optf) == 0)
1128*1676Sjpk 		opts |= NETSTAT_UNIX;
1129*1676Sjpk 	else
1130*1676Sjpk 		return (DCMD_USAGE);
1131*1676Sjpk 
1132*1676Sjpk 	if (opts & NETSTAT_ROUTE) {
1133*1676Sjpk 		if (!(opts & (NETSTAT_V4|NETSTAT_V6)))
11340Sstevel@tonic-gate 			return (DCMD_USAGE);
1135*1676Sjpk 		if (opts & NETSTAT_V4) {
1136*1676Sjpk 			opts |= NETSTAT_FIRST;
1137*1676Sjpk 			if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) {
1138*1676Sjpk 				mdb_warn("failed to walk ip`ire");
1139*1676Sjpk 				return (DCMD_ERR);
1140*1676Sjpk 			}
1141*1676Sjpk 			opts |= NETSTAT_FIRST;
1142*1676Sjpk 			if (mdb_walk("ip`ire", netstat_irev4src_cb,
1143*1676Sjpk 			    &opts) == -1) {
1144*1676Sjpk 				mdb_warn("failed to walk ip`ire");
1145*1676Sjpk 				return (DCMD_ERR);
1146*1676Sjpk 			}
1147*1676Sjpk 		}
1148*1676Sjpk 		if (opts & NETSTAT_V6) {
1149*1676Sjpk 			opts |= NETSTAT_FIRST;
1150*1676Sjpk 			if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) {
1151*1676Sjpk 				mdb_warn("failed to walk ip`ire");
1152*1676Sjpk 				return (DCMD_ERR);
1153*1676Sjpk 			}
1154*1676Sjpk 		}
1155*1676Sjpk 		return (DCMD_OK);
11560Sstevel@tonic-gate 	}
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
11590Sstevel@tonic-gate 		if ((optf == NULL) || (strcmp("inet", optf) == 0)) {
11600Sstevel@tonic-gate 			/* Print TCPv4 connection */
11610Sstevel@tonic-gate 			mdb_printf(
11620Sstevel@tonic-gate 			    "%<u>%-?s St %*s       %*s       %s%</u>\n",
11630Sstevel@tonic-gate 			    "TCPv4", ADDR_V4_WIDTH, "Local Address",
11640Sstevel@tonic-gate 			    ADDR_V4_WIDTH, "Remote Address", "Zone");
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 			if (opts & NETSTAT_VERBOSE)
11670Sstevel@tonic-gate 				netstat_tcp_verbose_header_pr();
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 			if (mdb_walk("ipcl_tcpconn_cache", netstat_tcpv4_cb,
11700Sstevel@tonic-gate 			    (void *)(uintptr_t)opts) == -1) {
11710Sstevel@tonic-gate 				mdb_warn("failed to walk ipcl_tcpconn_cache");
11720Sstevel@tonic-gate 				return (DCMD_ERR);
11730Sstevel@tonic-gate 			}
11740Sstevel@tonic-gate 		}
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 		if ((optf == NULL) || (strcmp("inet6", optf) == 0)) {
11770Sstevel@tonic-gate 			/* Print TCPv6 connection */
11780Sstevel@tonic-gate 			mdb_printf(
11790Sstevel@tonic-gate 			    "%<u>%-?s St %*s       %*s       %s\n%</u>",
11800Sstevel@tonic-gate 			    "TCPv6", ADDR_V6_WIDTH, "Local Address",
11810Sstevel@tonic-gate 			    ADDR_V6_WIDTH, "Remote Address", "Zone");
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 			if (opts & NETSTAT_VERBOSE)
11840Sstevel@tonic-gate 				netstat_tcp_verbose_header_pr();
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 			if (mdb_walk("ipcl_tcpconn_cache", netstat_tcpv6_cb,
11870Sstevel@tonic-gate 			    (void *)(uintptr_t)opts) == -1) {
11880Sstevel@tonic-gate 				mdb_warn("failed to walk ipcl_tcpconn_cache");
11890Sstevel@tonic-gate 				return (DCMD_ERR);
11900Sstevel@tonic-gate 			}
11910Sstevel@tonic-gate 		}
11920Sstevel@tonic-gate 	}
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 	if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
11950Sstevel@tonic-gate 		if ((optf == NULL) || (strcmp("inet", optf) == 0)) {
11960Sstevel@tonic-gate 			/* Print UDPv4 connection */
11970Sstevel@tonic-gate 			mdb_printf(
11980Sstevel@tonic-gate 			    "%<u>%-?s St %*s       %*s       %s\n%</u>",
11990Sstevel@tonic-gate 			    "UDPv4", ADDR_V4_WIDTH, "Local Address",
12000Sstevel@tonic-gate 			    ADDR_V4_WIDTH, "Remote Address", "Zone");
12010Sstevel@tonic-gate 
1202741Smasputra 			if (mdb_walk("udp_cache", netstat_udpv4_cb,
12030Sstevel@tonic-gate 			    (void *)(uintptr_t)opts) == -1) {
12040Sstevel@tonic-gate 				mdb_warn("failed to walk genunix`udp");
12050Sstevel@tonic-gate 				return (DCMD_ERR);
12060Sstevel@tonic-gate 			}
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate 		}
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 		if ((optf == NULL) || (strcmp("inet6", optf) == 0)) {
12110Sstevel@tonic-gate 			/* Print UDPv6 connection */
12120Sstevel@tonic-gate 			mdb_printf(
12130Sstevel@tonic-gate 			    "%<u>%-?s St %*s       %*s       %s\n%</u>",
12140Sstevel@tonic-gate 			    "UDPv6", ADDR_V6_WIDTH, "Local Address",
12150Sstevel@tonic-gate 			    ADDR_V6_WIDTH, "Remote Address", "Zone");
12160Sstevel@tonic-gate 
1217741Smasputra 			if (mdb_walk("udp_cache", netstat_udpv6_cb,
12180Sstevel@tonic-gate 			    (void *)(uintptr_t)opts) == -1) {
12190Sstevel@tonic-gate 				mdb_warn("failed to walk genunix`udp");
12200Sstevel@tonic-gate 				return (DCMD_ERR);
12210Sstevel@tonic-gate 			}
12220Sstevel@tonic-gate 		}
12230Sstevel@tonic-gate 	}
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	if (((optf == NULL) || (strcmp("unix", optf) == 0)) && (optP == NULL)) {
12260Sstevel@tonic-gate 		/* Print Unix Domain Sockets */
12270Sstevel@tonic-gate 		mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n",
12280Sstevel@tonic-gate 		    "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr",
12290Sstevel@tonic-gate 		    "Remote Addr", "Zone");
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 		if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) {
12320Sstevel@tonic-gate 			mdb_warn("failed to walk genunix`sonode");
12330Sstevel@tonic-gate 			return (DCMD_ERR);
12340Sstevel@tonic-gate 		}
12350Sstevel@tonic-gate 	}
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 	return (DCMD_OK);
12380Sstevel@tonic-gate }
1239