xref: /onnv-gate/usr/src/cmd/mdb/common/modules/genunix/net.c (revision 741:40027a3621ac)
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
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
300Sstevel@tonic-gate #include <mdb/mdb_ks.h>
310Sstevel@tonic-gate #include <mdb/mdb_ctf.h>
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/tihdr.h>
340Sstevel@tonic-gate #include <inet/led.h>
350Sstevel@tonic-gate #include <inet/common.h>
360Sstevel@tonic-gate #include <netinet/in.h>
370Sstevel@tonic-gate #include <netinet/ip6.h>
380Sstevel@tonic-gate #include <netinet/icmp6.h>
390Sstevel@tonic-gate #include <inet/ip.h>
400Sstevel@tonic-gate #include <inet/ip6.h>
410Sstevel@tonic-gate #include <inet/ipclassifier.h>
420Sstevel@tonic-gate #include <inet/tcp.h>
430Sstevel@tonic-gate #include <sys/stream.h>
440Sstevel@tonic-gate #include <sys/vfs.h>
450Sstevel@tonic-gate #include <sys/stropts.h>
460Sstevel@tonic-gate #include <sys/tpicommon.h>
470Sstevel@tonic-gate #include <sys/socket.h>
480Sstevel@tonic-gate #include <sys/socketvar.h>
490Sstevel@tonic-gate #include <sys/cred_impl.h>
500Sstevel@tonic-gate #include <inet/udp_impl.h>
510Sstevel@tonic-gate #include <inet/arp_impl.h>
520Sstevel@tonic-gate #include <inet/rawip_impl.h>
530Sstevel@tonic-gate #include <inet/mi.h>
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #define	MIH2MIO(mihp) (&(mihp)->mh_o)
560Sstevel@tonic-gate 
570Sstevel@tonic-gate #define	ADDR_V6_WIDTH	23
580Sstevel@tonic-gate #define	ADDR_V4_WIDTH	15
590Sstevel@tonic-gate 
600Sstevel@tonic-gate #define	NETSTAT_ALL	0x1
610Sstevel@tonic-gate #define	NETSTAT_VERBOSE	0x2
620Sstevel@tonic-gate 
630Sstevel@tonic-gate /*
640Sstevel@tonic-gate  * Print an IPv4 address and port number in a compact and easy to read format
650Sstevel@tonic-gate  * The arguments are in network byte order
660Sstevel@tonic-gate  */
670Sstevel@tonic-gate static void
680Sstevel@tonic-gate net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport)
690Sstevel@tonic-gate {
700Sstevel@tonic-gate 	uint32_t naddr = V4_PART_OF_V6((*nipv6addr));
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 	mdb_nhconvert(&nport, &nport, sizeof (nport));
730Sstevel@tonic-gate 	mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport);
740Sstevel@tonic-gate }
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /*
770Sstevel@tonic-gate  * Print an IPv6 address and port number in a compact and easy to read format
780Sstevel@tonic-gate  * The arguments are in network byte order
790Sstevel@tonic-gate  */
800Sstevel@tonic-gate static void
810Sstevel@tonic-gate net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport)
820Sstevel@tonic-gate {
830Sstevel@tonic-gate 	mdb_nhconvert(&nport, &nport, sizeof (nport));
840Sstevel@tonic-gate 	mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport);
850Sstevel@tonic-gate }
860Sstevel@tonic-gate 
870Sstevel@tonic-gate static int
880Sstevel@tonic-gate net_tcp_active(const tcp_t *tcp)
890Sstevel@tonic-gate {
900Sstevel@tonic-gate 	return (tcp->tcp_state >= TCPS_ESTABLISHED);
910Sstevel@tonic-gate }
920Sstevel@tonic-gate 
930Sstevel@tonic-gate static int
940Sstevel@tonic-gate net_tcp_ipv4(const tcp_t *tcp)
950Sstevel@tonic-gate {
960Sstevel@tonic-gate 	return ((tcp->tcp_ipversion == IPV4_VERSION) ||
970Sstevel@tonic-gate 	    (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_ip_src_v6) &&
980Sstevel@tonic-gate 	    (tcp->tcp_state <= TCPS_LISTEN)));
990Sstevel@tonic-gate }
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate static int
1020Sstevel@tonic-gate net_tcp_ipv6(const tcp_t *tcp)
1030Sstevel@tonic-gate {
1040Sstevel@tonic-gate 	return (tcp->tcp_ipversion == IPV6_VERSION);
1050Sstevel@tonic-gate }
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate static int
1080Sstevel@tonic-gate net_udp_active(const udp_t *udp)
1090Sstevel@tonic-gate {
110*741Smasputra 	return ((udp->udp_state == TS_IDLE) ||
111*741Smasputra 	    (udp->udp_state == TS_DATA_XFER));
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate static int
1150Sstevel@tonic-gate net_udp_ipv4(const udp_t *udp)
1160Sstevel@tonic-gate {
1170Sstevel@tonic-gate 	return ((udp->udp_ipversion == IPV4_VERSION) ||
1180Sstevel@tonic-gate 	    (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src) &&
1190Sstevel@tonic-gate 	    (udp->udp_state <= TS_IDLE)));
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate static int
1230Sstevel@tonic-gate net_udp_ipv6(const udp_t *udp)
1240Sstevel@tonic-gate {
1250Sstevel@tonic-gate 	return (udp->udp_ipversion == IPV6_VERSION);
1260Sstevel@tonic-gate }
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate int
1290Sstevel@tonic-gate sonode_walk_init(mdb_walk_state_t *wsp)
1300Sstevel@tonic-gate {
1310Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
1320Sstevel@tonic-gate 		GElf_Sym sym;
1330Sstevel@tonic-gate 		struct socklist *slp;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 		if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) {
1360Sstevel@tonic-gate 			mdb_warn("failed to lookup sockfs`socklist");
1370Sstevel@tonic-gate 			return (WALK_ERR);
1380Sstevel@tonic-gate 		}
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 		slp = (struct socklist *)(uintptr_t)sym.st_value;
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 		if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),
1430Sstevel@tonic-gate 		    (uintptr_t)&slp->sl_list) == -1) {
1440Sstevel@tonic-gate 			mdb_warn("failed to read address of initial sonode "
1450Sstevel@tonic-gate 			    "at %p", &slp->sl_list);
1460Sstevel@tonic-gate 			return (WALK_ERR);
1470Sstevel@tonic-gate 		}
1480Sstevel@tonic-gate 	}
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (struct sonode), UM_SLEEP);
1510Sstevel@tonic-gate 	return (WALK_NEXT);
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate int
1550Sstevel@tonic-gate sonode_walk_step(mdb_walk_state_t *wsp)
1560Sstevel@tonic-gate {
1570Sstevel@tonic-gate 	int status;
1580Sstevel@tonic-gate 	struct sonode *sonodep;
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
1610Sstevel@tonic-gate 		return (WALK_DONE);
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (struct sonode),
1640Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
1650Sstevel@tonic-gate 		mdb_warn("failed to read sonode at %p", wsp->walk_addr);
1660Sstevel@tonic-gate 		return (WALK_ERR);
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1700Sstevel@tonic-gate 	    wsp->walk_cbdata);
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	sonodep = wsp->walk_data;
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)sonodep->so_next;
1750Sstevel@tonic-gate 	return (status);
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate void
1790Sstevel@tonic-gate sonode_walk_fini(mdb_walk_state_t *wsp)
1800Sstevel@tonic-gate {
1810Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct sonode));
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate struct mi_walk_data {
1850Sstevel@tonic-gate 	uintptr_t mi_wd_miofirst;
1860Sstevel@tonic-gate 	MI_O mi_wd_miodata;
1870Sstevel@tonic-gate };
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate int
1900Sstevel@tonic-gate mi_walk_init(mdb_walk_state_t *wsp)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	struct mi_walk_data *wdp;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
1950Sstevel@tonic-gate 		mdb_warn("mi doesn't support global walks\n");
1960Sstevel@tonic-gate 		return (WALK_ERR);
1970Sstevel@tonic-gate 	}
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP);
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	/* So that we do not immediately return WALK_DONE below */
2020Sstevel@tonic-gate 	wdp->mi_wd_miofirst = NULL;
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	wsp->walk_data = wdp;
2050Sstevel@tonic-gate 	return (WALK_NEXT);
2060Sstevel@tonic-gate }
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate int
2090Sstevel@tonic-gate mi_walk_step(mdb_walk_state_t *wsp)
2100Sstevel@tonic-gate {
2110Sstevel@tonic-gate 	struct mi_walk_data *wdp = wsp->walk_data;
2120Sstevel@tonic-gate 	MI_OP miop = &wdp->mi_wd_miodata;
2130Sstevel@tonic-gate 	int status;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	/* Always false in the first iteration */
2160Sstevel@tonic-gate 	if ((wsp->walk_addr == (uintptr_t)NULL) ||
2170Sstevel@tonic-gate 	    (wsp->walk_addr == wdp->mi_wd_miofirst)) {
2180Sstevel@tonic-gate 		return (WALK_DONE);
2190Sstevel@tonic-gate 	}
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) {
2220Sstevel@tonic-gate 		mdb_warn("failed to read MI object at %p", wsp->walk_addr);
2230Sstevel@tonic-gate 		return (WALK_ERR);
2240Sstevel@tonic-gate 	}
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, miop, wsp->walk_cbdata);
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	/* Only true in the first iteration */
2290Sstevel@tonic-gate 	if (wdp->mi_wd_miofirst == NULL)
2300Sstevel@tonic-gate 		wdp->mi_wd_miofirst = wsp->walk_addr;
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)miop->mi_o_next;
2330Sstevel@tonic-gate 	return (status);
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate void
2370Sstevel@tonic-gate mi_walk_fini(mdb_walk_state_t *wsp)
2380Sstevel@tonic-gate {
2390Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct mi_walk_data));
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate typedef struct mi_payload_walk_data_s {
2430Sstevel@tonic-gate 	uintptr_t mi_pwd_first;
2440Sstevel@tonic-gate 	void *mi_pwd_data;
2450Sstevel@tonic-gate } mi_payload_walk_data_t;
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate static void
2480Sstevel@tonic-gate delete_mi_payload_walk_data(mi_payload_walk_data_t *pwdp, size_t payload_size)
2490Sstevel@tonic-gate {
2500Sstevel@tonic-gate 	mdb_free(pwdp->mi_pwd_data, payload_size);
2510Sstevel@tonic-gate 	mdb_free(pwdp, sizeof (mi_payload_walk_data_t));
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate typedef struct mi_payload_walk_arg_s {
2550Sstevel@tonic-gate 	const char *mi_pwa_obj;		/* load object of mi_o_head_t * */
2560Sstevel@tonic-gate 	const char *mi_pwa_sym;		/* symbol name of mi_o_head_t * */
2570Sstevel@tonic-gate 	const size_t mi_pwa_size;	/* size of mi payload */
2580Sstevel@tonic-gate 	const uint_t mi_pwa_flags;	/* device and/or module */
2590Sstevel@tonic-gate } mi_payload_walk_arg_t;
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate #define	MI_PAYLOAD_DEVICE	0x1
2620Sstevel@tonic-gate #define	MI_PAYLOAD_MODULE	0x2
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate int
2650Sstevel@tonic-gate mi_payload_walk_init(mdb_walk_state_t *wsp)
2660Sstevel@tonic-gate {
2670Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
2680Sstevel@tonic-gate 	mi_payload_walk_data_t *pwdp;
2690Sstevel@tonic-gate 	GElf_Sym sym;
2700Sstevel@tonic-gate 	mi_head_t *mihp;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	/* Determine the address to start or end the walk with */
2730Sstevel@tonic-gate 	if (mdb_lookup_by_obj(arg->mi_pwa_obj, arg->mi_pwa_sym, &sym) == -1) {
2740Sstevel@tonic-gate 		mdb_warn("failed to lookup %s`%s",
2750Sstevel@tonic-gate 		    arg->mi_pwa_obj, arg->mi_pwa_sym);
2760Sstevel@tonic-gate 		return (WALK_ERR);
2770Sstevel@tonic-gate 	}
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	if (mdb_vread(&mihp, sizeof (mihp), (uintptr_t)sym.st_value) == -1) {
2800Sstevel@tonic-gate 		mdb_warn("failed to read address of global MI Head "
2810Sstevel@tonic-gate 		    "mi_o_head_t at %p", (uintptr_t)sym.st_value);
2820Sstevel@tonic-gate 		return (WALK_ERR);
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	pwdp = mdb_alloc(sizeof (mi_payload_walk_data_t), UM_SLEEP);
2860Sstevel@tonic-gate 	pwdp->mi_pwd_data = mdb_alloc(arg->mi_pwa_size, UM_SLEEP);
2870Sstevel@tonic-gate 	wsp->walk_data = pwdp;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
2900Sstevel@tonic-gate 		/* Do not immediately return WALK_DONE below */
2910Sstevel@tonic-gate 		pwdp->mi_pwd_first = NULL;
2920Sstevel@tonic-gate 		/* We determined where to begin */
2930Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)MIH2MIO(mihp);
2940Sstevel@tonic-gate 	} else {
2950Sstevel@tonic-gate 		/* Do not cycle through all of the MI_O objects */
2960Sstevel@tonic-gate 		pwdp->mi_pwd_first = (uintptr_t)MIH2MIO(mihp);
2970Sstevel@tonic-gate 		/* We were given where to begin */
2980Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)((MI_OP)wsp->walk_addr - 1);
2990Sstevel@tonic-gate 	}
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	if (mdb_layered_walk("genunix`mi", wsp) == -1) {
3020Sstevel@tonic-gate 		mdb_warn("failed to walk genunix`mi");
3030Sstevel@tonic-gate 		delete_mi_payload_walk_data(pwdp, arg->mi_pwa_size);
3040Sstevel@tonic-gate 		return (WALK_ERR);
3050Sstevel@tonic-gate 	}
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	return (WALK_NEXT);
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate int
3110Sstevel@tonic-gate mi_payload_walk_step(mdb_walk_state_t *wsp)
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
3140Sstevel@tonic-gate 	mi_payload_walk_data_t *pwdp = wsp->walk_data;
3150Sstevel@tonic-gate 	void *payload = pwdp->mi_pwd_data;
3160Sstevel@tonic-gate 	uintptr_t payload_kaddr = (uintptr_t)((MI_OP)wsp->walk_addr + 1);
3170Sstevel@tonic-gate 	const MI_O *mio = wsp->walk_layer;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	/* If this is a local walk, prevent cycling */
3200Sstevel@tonic-gate 	if (wsp->walk_addr == pwdp->mi_pwd_first)
3210Sstevel@tonic-gate 		return (WALK_DONE);
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	/*
3240Sstevel@tonic-gate 	 * This was a global walk, prevent reading this payload as the
3250Sstevel@tonic-gate 	 * initial MI_O is the head of the list and is not the header
3260Sstevel@tonic-gate 	 * to a valid payload
3270Sstevel@tonic-gate 	 */
3280Sstevel@tonic-gate 	if (pwdp->mi_pwd_first == NULL) {
3290Sstevel@tonic-gate 		pwdp->mi_pwd_first = wsp->walk_addr;
3300Sstevel@tonic-gate 		return (WALK_NEXT);
3310Sstevel@tonic-gate 	}
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	if (mio->mi_o_isdev == B_FALSE) {
3340Sstevel@tonic-gate 		/* mio is a module */
3350Sstevel@tonic-gate 		if (!(arg->mi_pwa_flags & MI_PAYLOAD_MODULE))
3360Sstevel@tonic-gate 			return (WALK_NEXT);
3370Sstevel@tonic-gate 	} else {
3380Sstevel@tonic-gate 		/* mio is a device */
3390Sstevel@tonic-gate 		if (!(arg->mi_pwa_flags & MI_PAYLOAD_DEVICE))
3400Sstevel@tonic-gate 			return (WALK_NEXT);
3410Sstevel@tonic-gate 	}
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	if (mdb_vread(payload, arg->mi_pwa_size, payload_kaddr) == -1) {
3440Sstevel@tonic-gate 		mdb_warn("failed to read payload at %p", payload_kaddr);
3450Sstevel@tonic-gate 		return (WALK_ERR);
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	return (wsp->walk_callback(payload_kaddr, payload, wsp->walk_cbdata));
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate void
3520Sstevel@tonic-gate mi_payload_walk_fini(mdb_walk_state_t *wsp)
3530Sstevel@tonic-gate {
3540Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	delete_mi_payload_walk_data(wsp->walk_data, arg->mi_pwa_size);
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate const mi_payload_walk_arg_t mi_ar_arg = {
3600Sstevel@tonic-gate 	"arp", "ar_g_head", sizeof (ar_t),
3610Sstevel@tonic-gate 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
3620Sstevel@tonic-gate };
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate const mi_payload_walk_arg_t mi_icmp_arg = {
3650Sstevel@tonic-gate 	"icmp", "icmp_g_head", sizeof (icmp_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_ill_arg =
3700Sstevel@tonic-gate 	{ "ip", "ip_g_head", sizeof (ill_t), MI_PAYLOAD_MODULE };
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate int
3730Sstevel@tonic-gate sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3740Sstevel@tonic-gate {
3750Sstevel@tonic-gate 	const char *optf = NULL;
3760Sstevel@tonic-gate 	const char *optt = NULL;
3770Sstevel@tonic-gate 	const char *optp = NULL;
3780Sstevel@tonic-gate 	int family, type, proto;
3790Sstevel@tonic-gate 	int filter = 0;
3800Sstevel@tonic-gate 	struct sonode so;
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
3830Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`sonode", "genunix`sonode", argc,
3840Sstevel@tonic-gate 		    argv) == -1) {
3850Sstevel@tonic-gate 			mdb_warn("failed to walk sonode");
3860Sstevel@tonic-gate 			return (DCMD_ERR);
3870Sstevel@tonic-gate 		}
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 		return (DCMD_OK);
3900Sstevel@tonic-gate 	}
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
3930Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &optf,
3940Sstevel@tonic-gate 	    't', MDB_OPT_STR, &optt,
3950Sstevel@tonic-gate 	    'p', MDB_OPT_STR, &optp,
3960Sstevel@tonic-gate 	    NULL) != argc)
3970Sstevel@tonic-gate 		return (DCMD_USAGE);
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	if (optf != NULL) {
4000Sstevel@tonic-gate 		if (strcmp("inet", optf) == 0)
4010Sstevel@tonic-gate 			family = AF_INET;
4020Sstevel@tonic-gate 		else if (strcmp("inet6", optf) == 0)
4030Sstevel@tonic-gate 			family = AF_INET6;
4040Sstevel@tonic-gate 		else if (strcmp("unix", optf) == 0)
4050Sstevel@tonic-gate 			family = AF_UNIX;
4060Sstevel@tonic-gate 		else
4070Sstevel@tonic-gate 			family = mdb_strtoull(optf);
4080Sstevel@tonic-gate 		filter = 1;
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	if (optt != NULL) {
4120Sstevel@tonic-gate 		if (strcmp("stream", optt) == 0)
4130Sstevel@tonic-gate 			type = SOCK_STREAM;
4140Sstevel@tonic-gate 		else if (strcmp("dgram", optt) == 0)
4150Sstevel@tonic-gate 			type = SOCK_DGRAM;
4160Sstevel@tonic-gate 		else if (strcmp("raw", optt) == 0)
4170Sstevel@tonic-gate 			type = SOCK_RAW;
4180Sstevel@tonic-gate 		else
4190Sstevel@tonic-gate 			type = mdb_strtoull(optt);
4200Sstevel@tonic-gate 		filter = 1;
4210Sstevel@tonic-gate 	}
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	if (optp != NULL) {
4240Sstevel@tonic-gate 		proto = mdb_strtoull(optp);
4250Sstevel@tonic-gate 		filter = 1;
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !filter) {
4290Sstevel@tonic-gate 		mdb_printf("%<u>%-?s Family Type Proto State Mode Flag "
4300Sstevel@tonic-gate 		    "AccessVP%</u>\n", "Sonode:");
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	if (mdb_vread(&so, sizeof (so), addr) == -1) {
4340Sstevel@tonic-gate 		mdb_warn("failed to read sonode at %p", addr);
4350Sstevel@tonic-gate 		return (DCMD_ERR);
4360Sstevel@tonic-gate 	}
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	if ((optf != NULL) && (so.so_family != family))
4390Sstevel@tonic-gate 		return (DCMD_OK);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	if ((optt != NULL) && (so.so_type != type))
4420Sstevel@tonic-gate 		return (DCMD_OK);
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	if ((optp != NULL) && (so.so_protocol != proto))
4450Sstevel@tonic-gate 		return (DCMD_OK);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	if (filter) {
4480Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
4490Sstevel@tonic-gate 		return (DCMD_OK);
4500Sstevel@tonic-gate 	}
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	mdb_printf("%0?p ", addr);
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	switch (so.so_family) {
4550Sstevel@tonic-gate 	    case AF_UNIX:
4560Sstevel@tonic-gate 		mdb_printf("unix  ");
4570Sstevel@tonic-gate 		break;
4580Sstevel@tonic-gate 	    case AF_INET:
4590Sstevel@tonic-gate 		mdb_printf("inet  ");
4600Sstevel@tonic-gate 		break;
4610Sstevel@tonic-gate 	    case AF_INET6:
4620Sstevel@tonic-gate 		mdb_printf("inet6 ");
4630Sstevel@tonic-gate 		break;
4640Sstevel@tonic-gate 	    default:
4650Sstevel@tonic-gate 		mdb_printf("%6hi", so.so_family);
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	switch (so.so_type) {
4690Sstevel@tonic-gate 	    case SOCK_STREAM:
4700Sstevel@tonic-gate 		mdb_printf(" strm");
4710Sstevel@tonic-gate 		break;
4720Sstevel@tonic-gate 	    case SOCK_DGRAM:
4730Sstevel@tonic-gate 		mdb_printf(" dgrm");
4740Sstevel@tonic-gate 		break;
4750Sstevel@tonic-gate 	    case SOCK_RAW:
4760Sstevel@tonic-gate 		mdb_printf(" raw ");
4770Sstevel@tonic-gate 		break;
4780Sstevel@tonic-gate 	    default:
4790Sstevel@tonic-gate 		mdb_printf(" %4hi", so.so_type);
4800Sstevel@tonic-gate 	}
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 	mdb_printf(" %5hi %05x %04x %04hx %0?p\n",
4830Sstevel@tonic-gate 	    so.so_protocol, so.so_state, so.so_mode,
4840Sstevel@tonic-gate 	    so.so_flag, so.so_accessvp);
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	return (DCMD_OK);
4870Sstevel@tonic-gate }
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate #define	MI_PAYLOAD	0x1
4900Sstevel@tonic-gate #define	MI_DEVICE	0x2
4910Sstevel@tonic-gate #define	MI_MODULE	0x4
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate int
4940Sstevel@tonic-gate mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4950Sstevel@tonic-gate {
4960Sstevel@tonic-gate 	uint_t opts = 0;
4970Sstevel@tonic-gate 	MI_O	mio;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
5000Sstevel@tonic-gate 		return (DCMD_USAGE);
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
5030Sstevel@tonic-gate 	    'p', MDB_OPT_SETBITS, MI_PAYLOAD, &opts,
5040Sstevel@tonic-gate 	    'd', MDB_OPT_SETBITS, MI_DEVICE, &opts,
5050Sstevel@tonic-gate 	    'm', MDB_OPT_SETBITS, MI_MODULE, &opts,
5060Sstevel@tonic-gate 	    NULL) != argc)
5070Sstevel@tonic-gate 		return (DCMD_USAGE);
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	if ((opts & (MI_DEVICE | MI_MODULE)) == (MI_DEVICE | MI_MODULE)) {
5100Sstevel@tonic-gate 		mdb_warn("at most one filter, d for devices or m "
5110Sstevel@tonic-gate 		    "for modules, may be specified\n");
5120Sstevel@tonic-gate 		return (DCMD_USAGE);
5130Sstevel@tonic-gate 	}
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	if ((opts == 0) && (DCMD_HDRSPEC(flags))) {
5160Sstevel@tonic-gate 		mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n",
5170Sstevel@tonic-gate 		    "MI_O", "Next", "Prev");
5180Sstevel@tonic-gate 	}
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	if (mdb_vread(&mio, sizeof (mio), addr) == -1) {
5210Sstevel@tonic-gate 		mdb_warn("failed to read mi object MI_O at %p", addr);
5220Sstevel@tonic-gate 		return (DCMD_ERR);
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	if (opts != 0) {
5260Sstevel@tonic-gate 		if (mio.mi_o_isdev == B_FALSE) {
5270Sstevel@tonic-gate 			/* mio is a module */
5280Sstevel@tonic-gate 			if (!(opts & MI_MODULE) && (opts & MI_DEVICE))
5290Sstevel@tonic-gate 				return (DCMD_OK);
5300Sstevel@tonic-gate 		} else {
5310Sstevel@tonic-gate 			/* mio is a device */
5320Sstevel@tonic-gate 			if (!(opts & MI_DEVICE) && (opts & MI_MODULE))
5330Sstevel@tonic-gate 				return (DCMD_OK);
5340Sstevel@tonic-gate 		}
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 		if (opts & MI_PAYLOAD)
5370Sstevel@tonic-gate 			mdb_printf("%p\n", addr + sizeof (MI_O));
5380Sstevel@tonic-gate 		else
5390Sstevel@tonic-gate 			mdb_printf("%p\n", addr);
5400Sstevel@tonic-gate 		return (DCMD_OK);
5410Sstevel@tonic-gate 	}
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev);
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	if (mio.mi_o_isdev == B_FALSE)
5460Sstevel@tonic-gate 		mdb_printf("FALSE");
5470Sstevel@tonic-gate 	else
5480Sstevel@tonic-gate 		mdb_printf("TRUE ");
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	mdb_printf(" %0?p\n", mio.mi_o_dev);
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	return (DCMD_OK);
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate static void
5560Sstevel@tonic-gate netstat_tcp_verbose_pr(const tcp_t *tcp)
5570Sstevel@tonic-gate {
5580Sstevel@tonic-gate 	mdb_printf("       %5i %08x %08x %5i %08x %08x %5li %5i\n",
5590Sstevel@tonic-gate 	    tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
5600Sstevel@tonic-gate 	    tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
5610Sstevel@tonic-gate }
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate /*ARGSUSED*/
5640Sstevel@tonic-gate static int
5650Sstevel@tonic-gate netstat_tcp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data, int af)
5660Sstevel@tonic-gate {
5670Sstevel@tonic-gate 	const uintptr_t opts = (uintptr_t)cb_data;
5680Sstevel@tonic-gate 	static size_t itc_size = 0;
5690Sstevel@tonic-gate 	uintptr_t tcp_kaddr;
5700Sstevel@tonic-gate 	conn_t *connp;
5710Sstevel@tonic-gate 	tcp_t *tcp;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	if (itc_size == 0) {
5740Sstevel@tonic-gate 		mdb_ctf_id_t id;
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 		if (mdb_ctf_lookup_by_name("itc_t", &id) != 0) {
5770Sstevel@tonic-gate 			mdb_warn("failed to lookup type 'itc_t'");
5780Sstevel@tonic-gate 			return (WALK_ERR);
5790Sstevel@tonic-gate 		}
5800Sstevel@tonic-gate 		itc_size = mdb_ctf_type_size(id);
5810Sstevel@tonic-gate 	}
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	connp = (conn_t *)mdb_alloc(itc_size, UM_SLEEP | UM_GC);
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	if (mdb_vread(connp, itc_size, kaddr) == -1) {
5860Sstevel@tonic-gate 		mdb_warn("failed to read connection info at %p", kaddr);
5870Sstevel@tonic-gate 		return (WALK_ERR);
5880Sstevel@tonic-gate 	}
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	tcp_kaddr = (uintptr_t)connp->conn_tcp;
5910Sstevel@tonic-gate 	tcp = (tcp_t *)((uintptr_t)connp + (tcp_kaddr - kaddr));
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	if ((uintptr_t)tcp < (uintptr_t)connp ||
594*741Smasputra 	    (uintptr_t)(tcp + 1) > (uintptr_t)connp + itc_size ||
5950Sstevel@tonic-gate 	    (uintptr_t)tcp->tcp_connp != kaddr) {
5960Sstevel@tonic-gate 		mdb_warn("conn_tcp %p is invalid", tcp_kaddr);
5970Sstevel@tonic-gate 		return (WALK_NEXT);
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 	connp->conn_tcp = tcp;
6000Sstevel@tonic-gate 	tcp->tcp_connp = connp;
6010Sstevel@tonic-gate 
602*741Smasputra 	if (!((opts & NETSTAT_ALL) || net_tcp_active(tcp)) ||
6030Sstevel@tonic-gate 	    (af == AF_INET && !net_tcp_ipv4(tcp)) ||
6040Sstevel@tonic-gate 	    (af == AF_INET6 && !net_tcp_ipv6(tcp))) {
6050Sstevel@tonic-gate 		return (WALK_NEXT);
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state);
6090Sstevel@tonic-gate 	if (af == AF_INET) {
6100Sstevel@tonic-gate 		net_ipv4addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport);
6110Sstevel@tonic-gate 		mdb_printf(" ");
6120Sstevel@tonic-gate 		net_ipv4addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport);
6130Sstevel@tonic-gate 	} else if (af == AF_INET6) {
6140Sstevel@tonic-gate 		net_ipv6addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport);
6150Sstevel@tonic-gate 		mdb_printf(" ");
6160Sstevel@tonic-gate 		net_ipv6addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport);
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate 	mdb_printf(" %4i\n", connp->conn_zoneid);
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	if (opts & NETSTAT_VERBOSE)
6210Sstevel@tonic-gate 		netstat_tcp_verbose_pr(tcp);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	return (WALK_NEXT);
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate static int
6270Sstevel@tonic-gate netstat_tcpv4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate 	return (netstat_tcp_cb(kaddr, walk_data, cb_data, AF_INET));
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate static int
6330Sstevel@tonic-gate netstat_tcpv6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
6340Sstevel@tonic-gate {
6350Sstevel@tonic-gate 	return (netstat_tcp_cb(kaddr, walk_data, cb_data, AF_INET6));
6360Sstevel@tonic-gate }
6370Sstevel@tonic-gate 
638*741Smasputra /*ARGSUSED*/
6390Sstevel@tonic-gate static int
640*741Smasputra netstat_udp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data, int af)
6410Sstevel@tonic-gate {
6420Sstevel@tonic-gate 	const uintptr_t opts = (uintptr_t)cb_data;
643*741Smasputra 	udp_t udp;
644*741Smasputra 	conn_t connp;
645*741Smasputra 
646*741Smasputra 	if (mdb_vread(&udp, sizeof (udp_t), kaddr) == -1) {
647*741Smasputra 		mdb_warn("failed to read udp at %p", kaddr);
648*741Smasputra 		return (WALK_ERR);
649*741Smasputra 	}
6500Sstevel@tonic-gate 
651*741Smasputra 	if (mdb_vread(&connp, sizeof (conn_t),
652*741Smasputra 	    (uintptr_t)udp.udp_connp) == -1) {
653*741Smasputra 		mdb_warn("failed to read udp_connp at %p",
654*741Smasputra 		    (uintptr_t)udp.udp_connp);
655*741Smasputra 		return (WALK_ERR);
656*741Smasputra 	}
6570Sstevel@tonic-gate 
658*741Smasputra 	if (!((opts & NETSTAT_ALL) || net_udp_active(&udp)) ||
659*741Smasputra 	    (af == AF_INET && !net_udp_ipv4(&udp)) ||
660*741Smasputra 	    (af == AF_INET6 && !net_udp_ipv6(&udp))) {
661*741Smasputra 		return (WALK_NEXT);
662*741Smasputra 	}
663*741Smasputra 
664*741Smasputra 	mdb_printf("%0?p %2i ", kaddr, udp.udp_state);
665*741Smasputra 	if (af == AF_INET) {
666*741Smasputra 		net_ipv4addrport_pr(&udp.udp_v6src, udp.udp_port);
667*741Smasputra 		mdb_printf(" ");
668*741Smasputra 		net_ipv4addrport_pr(&udp.udp_v6dst, udp.udp_dstport);
669*741Smasputra 	} else if (af == AF_INET6) {
670*741Smasputra 		net_ipv6addrport_pr(&udp.udp_v6src, udp.udp_port);
671*741Smasputra 		mdb_printf(" ");
672*741Smasputra 		net_ipv6addrport_pr(&udp.udp_v6dst, udp.udp_dstport);
673*741Smasputra 	}
674*741Smasputra 	mdb_printf(" %4i\n", connp.conn_zoneid);
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	return (WALK_NEXT);
6770Sstevel@tonic-gate }
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate static int
680*741Smasputra netstat_udpv4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
681*741Smasputra {
682*741Smasputra 	return (netstat_udp_cb(kaddr, walk_data, cb_data, AF_INET));
683*741Smasputra }
684*741Smasputra 
685*741Smasputra static int
6860Sstevel@tonic-gate netstat_udpv6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
6870Sstevel@tonic-gate {
688*741Smasputra 	return (netstat_udp_cb(kaddr, walk_data, cb_data, AF_INET6));
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate /*
6920Sstevel@tonic-gate  * print the address of a unix domain socket
6930Sstevel@tonic-gate  *
6940Sstevel@tonic-gate  * so is the address of a AF_UNIX struct sonode in mdb's address space
6950Sstevel@tonic-gate  * soa is the address of the struct soaddr to print
6960Sstevel@tonic-gate  *
6970Sstevel@tonic-gate  * returns 0 on success, -1 otherwise
6980Sstevel@tonic-gate  */
6990Sstevel@tonic-gate static int
7000Sstevel@tonic-gate netstat_unix_name_pr(const struct sonode *so, const struct soaddr *soa)
7010Sstevel@tonic-gate {
7020Sstevel@tonic-gate 	const char none[] = " (none)";
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) {
7050Sstevel@tonic-gate 		if (so->so_state & SS_FADDR_NOXLATE) {
7060Sstevel@tonic-gate 			mdb_printf("%-14s ", " (socketpair)");
7070Sstevel@tonic-gate 		} else {
7080Sstevel@tonic-gate 			if (soa->soa_len > sizeof (sa_family_t)) {
7090Sstevel@tonic-gate 				char addr[MAXPATHLEN + 1];
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 				if (mdb_readstr(addr, sizeof (addr),
7120Sstevel@tonic-gate 				    (uintptr_t)&soa->soa_sa->sa_data) == -1) {
7130Sstevel@tonic-gate 					mdb_warn("failed to read unix address "
7140Sstevel@tonic-gate 					    "at %p", &soa->soa_sa->sa_data);
7150Sstevel@tonic-gate 					return (-1);
7160Sstevel@tonic-gate 				}
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 				mdb_printf("%-14s ", addr);
7190Sstevel@tonic-gate 			} else {
7200Sstevel@tonic-gate 				mdb_printf("%-14s ", none);
7210Sstevel@tonic-gate 			}
7220Sstevel@tonic-gate 		}
7230Sstevel@tonic-gate 	} else {
7240Sstevel@tonic-gate 		mdb_printf("%-14s ", none);
7250Sstevel@tonic-gate 	}
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	return (0);
7280Sstevel@tonic-gate }
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate /* based on sockfs_snapshot */
7310Sstevel@tonic-gate /*ARGSUSED*/
7320Sstevel@tonic-gate static int
7330Sstevel@tonic-gate netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
7340Sstevel@tonic-gate {
7350Sstevel@tonic-gate 	const struct sonode *so = walk_data;
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	if (so->so_accessvp == NULL)
7380Sstevel@tonic-gate 		return (WALK_NEXT);
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	if (so->so_family != AF_UNIX) {
7410Sstevel@tonic-gate 		mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr);
7420Sstevel@tonic-gate 		return (WALK_ERR);
7430Sstevel@tonic-gate 	}
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	mdb_printf("%-?p ", kaddr);
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	switch (so->so_serv_type) {
7480Sstevel@tonic-gate 	    case T_CLTS:
7490Sstevel@tonic-gate 		mdb_printf("%-10s ", "dgram");
7500Sstevel@tonic-gate 		break;
7510Sstevel@tonic-gate 	    case T_COTS:
7520Sstevel@tonic-gate 		mdb_printf("%-10s ", "stream");
7530Sstevel@tonic-gate 		break;
7540Sstevel@tonic-gate 	    case T_COTS_ORD:
7550Sstevel@tonic-gate 		mdb_printf("%-10s ", "stream-ord");
7560Sstevel@tonic-gate 		break;
7570Sstevel@tonic-gate 	    default:
7580Sstevel@tonic-gate 		    mdb_printf("%-10i ", so->so_serv_type);
7590Sstevel@tonic-gate 	}
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	if ((so->so_state & SS_ISBOUND) &&
7620Sstevel@tonic-gate 	    (so->so_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
7630Sstevel@tonic-gate 		mdb_printf("%0?p ", so->so_ux_laddr.soua_vp);
7640Sstevel@tonic-gate 	} else {
7650Sstevel@tonic-gate 		mdb_printf("%0?p ", NULL);
7660Sstevel@tonic-gate 	}
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	if ((so->so_state & SS_ISCONNECTED) &&
7690Sstevel@tonic-gate 	    (so->so_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
7700Sstevel@tonic-gate 		mdb_printf("%0?p ", so->so_ux_faddr.soua_vp);
7710Sstevel@tonic-gate 	} else {
7720Sstevel@tonic-gate 		mdb_printf("%0?p ", NULL);
7730Sstevel@tonic-gate 	}
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	if (netstat_unix_name_pr(so, &so->so_laddr) == -1)
7760Sstevel@tonic-gate 		return (WALK_ERR);
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	if (netstat_unix_name_pr(so, &so->so_faddr) == -1)
7790Sstevel@tonic-gate 		return (WALK_ERR);
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	mdb_printf("%4i\n", so->so_zoneid);
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 	return (WALK_NEXT);
7840Sstevel@tonic-gate }
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate static void
7870Sstevel@tonic-gate netstat_tcp_verbose_header_pr(void)
7880Sstevel@tonic-gate {
7890Sstevel@tonic-gate 	mdb_printf("       %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n",
7900Sstevel@tonic-gate 	    "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss");
7910Sstevel@tonic-gate }
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate /*ARGSUSED*/
7940Sstevel@tonic-gate int
7950Sstevel@tonic-gate netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate 	uint_t opts = 0;
7980Sstevel@tonic-gate 	const char *optf = NULL;
7990Sstevel@tonic-gate 	const char *optP = NULL;
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
8020Sstevel@tonic-gate 	    'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts,
8030Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts,
8040Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &optf,
8050Sstevel@tonic-gate 	    'P', MDB_OPT_STR, &optP,
8060Sstevel@tonic-gate 	    NULL) != argc)
8070Sstevel@tonic-gate 		return (DCMD_USAGE);
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	if (optP != NULL) {
8100Sstevel@tonic-gate 		if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0))
8110Sstevel@tonic-gate 			return (DCMD_USAGE);
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 	}
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	if (optf != NULL) {
8160Sstevel@tonic-gate 		if ((strcmp("inet", optf) != 0) &&
8170Sstevel@tonic-gate 		    (strcmp("inet6", optf) != 0) &&
8180Sstevel@tonic-gate 		    (strcmp("unix", optf) != 0))
8190Sstevel@tonic-gate 			return (DCMD_USAGE);
8200Sstevel@tonic-gate 	}
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 	if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
8230Sstevel@tonic-gate 		if ((optf == NULL) || (strcmp("inet", optf) == 0)) {
8240Sstevel@tonic-gate 			/* Print TCPv4 connection */
8250Sstevel@tonic-gate 			mdb_printf(
8260Sstevel@tonic-gate 			    "%<u>%-?s St %*s       %*s       %s%</u>\n",
8270Sstevel@tonic-gate 			    "TCPv4", ADDR_V4_WIDTH, "Local Address",
8280Sstevel@tonic-gate 			    ADDR_V4_WIDTH, "Remote Address", "Zone");
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 			if (opts & NETSTAT_VERBOSE)
8310Sstevel@tonic-gate 				netstat_tcp_verbose_header_pr();
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 			if (mdb_walk("ipcl_tcpconn_cache", netstat_tcpv4_cb,
8340Sstevel@tonic-gate 			    (void *)(uintptr_t)opts) == -1) {
8350Sstevel@tonic-gate 				mdb_warn("failed to walk ipcl_tcpconn_cache");
8360Sstevel@tonic-gate 				return (DCMD_ERR);
8370Sstevel@tonic-gate 			}
8380Sstevel@tonic-gate 		}
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 		if ((optf == NULL) || (strcmp("inet6", optf) == 0)) {
8410Sstevel@tonic-gate 			/* Print TCPv6 connection */
8420Sstevel@tonic-gate 			mdb_printf(
8430Sstevel@tonic-gate 			    "%<u>%-?s St %*s       %*s       %s\n%</u>",
8440Sstevel@tonic-gate 			    "TCPv6", ADDR_V6_WIDTH, "Local Address",
8450Sstevel@tonic-gate 			    ADDR_V6_WIDTH, "Remote Address", "Zone");
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 			if (opts & NETSTAT_VERBOSE)
8480Sstevel@tonic-gate 				netstat_tcp_verbose_header_pr();
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 			if (mdb_walk("ipcl_tcpconn_cache", netstat_tcpv6_cb,
8510Sstevel@tonic-gate 			    (void *)(uintptr_t)opts) == -1) {
8520Sstevel@tonic-gate 				mdb_warn("failed to walk ipcl_tcpconn_cache");
8530Sstevel@tonic-gate 				return (DCMD_ERR);
8540Sstevel@tonic-gate 			}
8550Sstevel@tonic-gate 		}
8560Sstevel@tonic-gate 	}
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
8590Sstevel@tonic-gate 		if ((optf == NULL) || (strcmp("inet", optf) == 0)) {
8600Sstevel@tonic-gate 			/* Print UDPv4 connection */
8610Sstevel@tonic-gate 			mdb_printf(
8620Sstevel@tonic-gate 			    "%<u>%-?s St %*s       %*s       %s\n%</u>",
8630Sstevel@tonic-gate 			    "UDPv4", ADDR_V4_WIDTH, "Local Address",
8640Sstevel@tonic-gate 			    ADDR_V4_WIDTH, "Remote Address", "Zone");
8650Sstevel@tonic-gate 
866*741Smasputra 			if (mdb_walk("udp_cache", netstat_udpv4_cb,
8670Sstevel@tonic-gate 			    (void *)(uintptr_t)opts) == -1) {
8680Sstevel@tonic-gate 				mdb_warn("failed to walk genunix`udp");
8690Sstevel@tonic-gate 				return (DCMD_ERR);
8700Sstevel@tonic-gate 			}
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 		}
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 		if ((optf == NULL) || (strcmp("inet6", optf) == 0)) {
8750Sstevel@tonic-gate 			/* Print UDPv6 connection */
8760Sstevel@tonic-gate 			mdb_printf(
8770Sstevel@tonic-gate 			    "%<u>%-?s St %*s       %*s       %s\n%</u>",
8780Sstevel@tonic-gate 			    "UDPv6", ADDR_V6_WIDTH, "Local Address",
8790Sstevel@tonic-gate 			    ADDR_V6_WIDTH, "Remote Address", "Zone");
8800Sstevel@tonic-gate 
881*741Smasputra 			if (mdb_walk("udp_cache", netstat_udpv6_cb,
8820Sstevel@tonic-gate 			    (void *)(uintptr_t)opts) == -1) {
8830Sstevel@tonic-gate 				mdb_warn("failed to walk genunix`udp");
8840Sstevel@tonic-gate 				return (DCMD_ERR);
8850Sstevel@tonic-gate 			}
8860Sstevel@tonic-gate 		}
8870Sstevel@tonic-gate 	}
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	if (((optf == NULL) || (strcmp("unix", optf) == 0)) && (optP == NULL)) {
8900Sstevel@tonic-gate 		/* Print Unix Domain Sockets */
8910Sstevel@tonic-gate 		mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n",
8920Sstevel@tonic-gate 		    "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr",
8930Sstevel@tonic-gate 		    "Remote Addr", "Zone");
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 		if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) {
8960Sstevel@tonic-gate 			mdb_warn("failed to walk genunix`sonode");
8970Sstevel@tonic-gate 			return (DCMD_ERR);
8980Sstevel@tonic-gate 		}
8990Sstevel@tonic-gate 	}
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	return (DCMD_OK);
9020Sstevel@tonic-gate }
903