1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
30*0Sstevel@tonic-gate #include <mdb/mdb_ks.h>
31*0Sstevel@tonic-gate #include <mdb/mdb_ctf.h>
32*0Sstevel@tonic-gate #include <sys/types.h>
33*0Sstevel@tonic-gate #include <sys/tihdr.h>
34*0Sstevel@tonic-gate #include <inet/led.h>
35*0Sstevel@tonic-gate #include <inet/common.h>
36*0Sstevel@tonic-gate #include <netinet/in.h>
37*0Sstevel@tonic-gate #include <netinet/ip6.h>
38*0Sstevel@tonic-gate #include <netinet/icmp6.h>
39*0Sstevel@tonic-gate #include <inet/ip.h>
40*0Sstevel@tonic-gate #include <inet/ip6.h>
41*0Sstevel@tonic-gate #include <inet/ipclassifier.h>
42*0Sstevel@tonic-gate #include <inet/tcp.h>
43*0Sstevel@tonic-gate #include <sys/stream.h>
44*0Sstevel@tonic-gate #include <sys/vfs.h>
45*0Sstevel@tonic-gate #include <sys/stropts.h>
46*0Sstevel@tonic-gate #include <sys/tpicommon.h>
47*0Sstevel@tonic-gate #include <sys/socket.h>
48*0Sstevel@tonic-gate #include <sys/socketvar.h>
49*0Sstevel@tonic-gate #include <sys/cred_impl.h>
50*0Sstevel@tonic-gate #include <inet/udp_impl.h>
51*0Sstevel@tonic-gate #include <inet/arp_impl.h>
52*0Sstevel@tonic-gate #include <inet/rawip_impl.h>
53*0Sstevel@tonic-gate #include <inet/mi.h>
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate #define	MIH2MIO(mihp) (&(mihp)->mh_o)
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate #define	ADDR_V6_WIDTH	23
58*0Sstevel@tonic-gate #define	ADDR_V4_WIDTH	15
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate #define	NETSTAT_ALL	0x1
61*0Sstevel@tonic-gate #define	NETSTAT_VERBOSE	0x2
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate /*
64*0Sstevel@tonic-gate  * Print an IPv4 address and port number in a compact and easy to read format
65*0Sstevel@tonic-gate  * The arguments are in network byte order
66*0Sstevel@tonic-gate  */
67*0Sstevel@tonic-gate static void
68*0Sstevel@tonic-gate net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport)
69*0Sstevel@tonic-gate {
70*0Sstevel@tonic-gate 	uint32_t naddr = V4_PART_OF_V6((*nipv6addr));
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate 	mdb_nhconvert(&nport, &nport, sizeof (nport));
73*0Sstevel@tonic-gate 	mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport);
74*0Sstevel@tonic-gate }
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate /*
77*0Sstevel@tonic-gate  * Print an IPv6 address and port number in a compact and easy to read format
78*0Sstevel@tonic-gate  * The arguments are in network byte order
79*0Sstevel@tonic-gate  */
80*0Sstevel@tonic-gate static void
81*0Sstevel@tonic-gate net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport)
82*0Sstevel@tonic-gate {
83*0Sstevel@tonic-gate 	mdb_nhconvert(&nport, &nport, sizeof (nport));
84*0Sstevel@tonic-gate 	mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport);
85*0Sstevel@tonic-gate }
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate static int
88*0Sstevel@tonic-gate net_tcp_active(const tcp_t *tcp)
89*0Sstevel@tonic-gate {
90*0Sstevel@tonic-gate 	return (tcp->tcp_state >= TCPS_ESTABLISHED);
91*0Sstevel@tonic-gate }
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate static int
94*0Sstevel@tonic-gate net_tcp_ipv4(const tcp_t *tcp)
95*0Sstevel@tonic-gate {
96*0Sstevel@tonic-gate 	return ((tcp->tcp_ipversion == IPV4_VERSION) ||
97*0Sstevel@tonic-gate 	    (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_ip_src_v6) &&
98*0Sstevel@tonic-gate 	    (tcp->tcp_state <= TCPS_LISTEN)));
99*0Sstevel@tonic-gate }
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate static int
102*0Sstevel@tonic-gate net_tcp_ipv6(const tcp_t *tcp)
103*0Sstevel@tonic-gate {
104*0Sstevel@tonic-gate 	return (tcp->tcp_ipversion == IPV6_VERSION);
105*0Sstevel@tonic-gate }
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate static int
108*0Sstevel@tonic-gate net_udp_active(const udp_t *udp)
109*0Sstevel@tonic-gate {
110*0Sstevel@tonic-gate 	return ((udp->udp_state != TS_UNBND) && (udp->udp_state != TS_IDLE));
111*0Sstevel@tonic-gate }
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate static int
114*0Sstevel@tonic-gate net_udp_ipv4(const udp_t *udp)
115*0Sstevel@tonic-gate {
116*0Sstevel@tonic-gate 	return ((udp->udp_ipversion == IPV4_VERSION) ||
117*0Sstevel@tonic-gate 	    (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src) &&
118*0Sstevel@tonic-gate 	    (udp->udp_state <= TS_IDLE)));
119*0Sstevel@tonic-gate }
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate static int
122*0Sstevel@tonic-gate net_udp_ipv6(const udp_t *udp)
123*0Sstevel@tonic-gate {
124*0Sstevel@tonic-gate 	return (udp->udp_ipversion == IPV6_VERSION);
125*0Sstevel@tonic-gate }
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate int
128*0Sstevel@tonic-gate sonode_walk_init(mdb_walk_state_t *wsp)
129*0Sstevel@tonic-gate {
130*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
131*0Sstevel@tonic-gate 		GElf_Sym sym;
132*0Sstevel@tonic-gate 		struct socklist *slp;
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 		if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) {
135*0Sstevel@tonic-gate 			mdb_warn("failed to lookup sockfs`socklist");
136*0Sstevel@tonic-gate 			return (WALK_ERR);
137*0Sstevel@tonic-gate 		}
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 		slp = (struct socklist *)(uintptr_t)sym.st_value;
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 		if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),
142*0Sstevel@tonic-gate 		    (uintptr_t)&slp->sl_list) == -1) {
143*0Sstevel@tonic-gate 			mdb_warn("failed to read address of initial sonode "
144*0Sstevel@tonic-gate 			    "at %p", &slp->sl_list);
145*0Sstevel@tonic-gate 			return (WALK_ERR);
146*0Sstevel@tonic-gate 		}
147*0Sstevel@tonic-gate 	}
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 	wsp->walk_data = mdb_alloc(sizeof (struct sonode), UM_SLEEP);
150*0Sstevel@tonic-gate 	return (WALK_NEXT);
151*0Sstevel@tonic-gate }
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate int
154*0Sstevel@tonic-gate sonode_walk_step(mdb_walk_state_t *wsp)
155*0Sstevel@tonic-gate {
156*0Sstevel@tonic-gate 	int status;
157*0Sstevel@tonic-gate 	struct sonode *sonodep;
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
160*0Sstevel@tonic-gate 		return (WALK_DONE);
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	if (mdb_vread(wsp->walk_data, sizeof (struct sonode),
163*0Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
164*0Sstevel@tonic-gate 		mdb_warn("failed to read sonode at %p", wsp->walk_addr);
165*0Sstevel@tonic-gate 		return (WALK_ERR);
166*0Sstevel@tonic-gate 	}
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
169*0Sstevel@tonic-gate 	    wsp->walk_cbdata);
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	sonodep = wsp->walk_data;
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)sonodep->so_next;
174*0Sstevel@tonic-gate 	return (status);
175*0Sstevel@tonic-gate }
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate void
178*0Sstevel@tonic-gate sonode_walk_fini(mdb_walk_state_t *wsp)
179*0Sstevel@tonic-gate {
180*0Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct sonode));
181*0Sstevel@tonic-gate }
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate struct mi_walk_data {
184*0Sstevel@tonic-gate 	uintptr_t mi_wd_miofirst;
185*0Sstevel@tonic-gate 	MI_O mi_wd_miodata;
186*0Sstevel@tonic-gate };
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate int
189*0Sstevel@tonic-gate mi_walk_init(mdb_walk_state_t *wsp)
190*0Sstevel@tonic-gate {
191*0Sstevel@tonic-gate 	struct mi_walk_data *wdp;
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
194*0Sstevel@tonic-gate 		mdb_warn("mi doesn't support global walks\n");
195*0Sstevel@tonic-gate 		return (WALK_ERR);
196*0Sstevel@tonic-gate 	}
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 	wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP);
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 	/* So that we do not immediately return WALK_DONE below */
201*0Sstevel@tonic-gate 	wdp->mi_wd_miofirst = NULL;
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	wsp->walk_data = wdp;
204*0Sstevel@tonic-gate 	return (WALK_NEXT);
205*0Sstevel@tonic-gate }
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate int
208*0Sstevel@tonic-gate mi_walk_step(mdb_walk_state_t *wsp)
209*0Sstevel@tonic-gate {
210*0Sstevel@tonic-gate 	struct mi_walk_data *wdp = wsp->walk_data;
211*0Sstevel@tonic-gate 	MI_OP miop = &wdp->mi_wd_miodata;
212*0Sstevel@tonic-gate 	int status;
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	/* Always false in the first iteration */
215*0Sstevel@tonic-gate 	if ((wsp->walk_addr == (uintptr_t)NULL) ||
216*0Sstevel@tonic-gate 	    (wsp->walk_addr == wdp->mi_wd_miofirst)) {
217*0Sstevel@tonic-gate 		return (WALK_DONE);
218*0Sstevel@tonic-gate 	}
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) {
221*0Sstevel@tonic-gate 		mdb_warn("failed to read MI object at %p", wsp->walk_addr);
222*0Sstevel@tonic-gate 		return (WALK_ERR);
223*0Sstevel@tonic-gate 	}
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, miop, wsp->walk_cbdata);
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	/* Only true in the first iteration */
228*0Sstevel@tonic-gate 	if (wdp->mi_wd_miofirst == NULL)
229*0Sstevel@tonic-gate 		wdp->mi_wd_miofirst = wsp->walk_addr;
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)miop->mi_o_next;
232*0Sstevel@tonic-gate 	return (status);
233*0Sstevel@tonic-gate }
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate void
236*0Sstevel@tonic-gate mi_walk_fini(mdb_walk_state_t *wsp)
237*0Sstevel@tonic-gate {
238*0Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct mi_walk_data));
239*0Sstevel@tonic-gate }
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate typedef struct mi_payload_walk_data_s {
242*0Sstevel@tonic-gate 	uintptr_t mi_pwd_first;
243*0Sstevel@tonic-gate 	void *mi_pwd_data;
244*0Sstevel@tonic-gate } mi_payload_walk_data_t;
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate static void
247*0Sstevel@tonic-gate delete_mi_payload_walk_data(mi_payload_walk_data_t *pwdp, size_t payload_size)
248*0Sstevel@tonic-gate {
249*0Sstevel@tonic-gate 	mdb_free(pwdp->mi_pwd_data, payload_size);
250*0Sstevel@tonic-gate 	mdb_free(pwdp, sizeof (mi_payload_walk_data_t));
251*0Sstevel@tonic-gate }
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate typedef struct mi_payload_walk_arg_s {
254*0Sstevel@tonic-gate 	const char *mi_pwa_obj;		/* load object of mi_o_head_t * */
255*0Sstevel@tonic-gate 	const char *mi_pwa_sym;		/* symbol name of mi_o_head_t * */
256*0Sstevel@tonic-gate 	const size_t mi_pwa_size;	/* size of mi payload */
257*0Sstevel@tonic-gate 	const uint_t mi_pwa_flags;	/* device and/or module */
258*0Sstevel@tonic-gate } mi_payload_walk_arg_t;
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate #define	MI_PAYLOAD_DEVICE	0x1
261*0Sstevel@tonic-gate #define	MI_PAYLOAD_MODULE	0x2
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate int
264*0Sstevel@tonic-gate mi_payload_walk_init(mdb_walk_state_t *wsp)
265*0Sstevel@tonic-gate {
266*0Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
267*0Sstevel@tonic-gate 	mi_payload_walk_data_t *pwdp;
268*0Sstevel@tonic-gate 	GElf_Sym sym;
269*0Sstevel@tonic-gate 	mi_head_t *mihp;
270*0Sstevel@tonic-gate 
271*0Sstevel@tonic-gate 	/* Determine the address to start or end the walk with */
272*0Sstevel@tonic-gate 	if (mdb_lookup_by_obj(arg->mi_pwa_obj, arg->mi_pwa_sym, &sym) == -1) {
273*0Sstevel@tonic-gate 		mdb_warn("failed to lookup %s`%s",
274*0Sstevel@tonic-gate 		    arg->mi_pwa_obj, arg->mi_pwa_sym);
275*0Sstevel@tonic-gate 		return (WALK_ERR);
276*0Sstevel@tonic-gate 	}
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	if (mdb_vread(&mihp, sizeof (mihp), (uintptr_t)sym.st_value) == -1) {
279*0Sstevel@tonic-gate 		mdb_warn("failed to read address of global MI Head "
280*0Sstevel@tonic-gate 		    "mi_o_head_t at %p", (uintptr_t)sym.st_value);
281*0Sstevel@tonic-gate 		return (WALK_ERR);
282*0Sstevel@tonic-gate 	}
283*0Sstevel@tonic-gate 
284*0Sstevel@tonic-gate 	pwdp = mdb_alloc(sizeof (mi_payload_walk_data_t), UM_SLEEP);
285*0Sstevel@tonic-gate 	pwdp->mi_pwd_data = mdb_alloc(arg->mi_pwa_size, UM_SLEEP);
286*0Sstevel@tonic-gate 	wsp->walk_data = pwdp;
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
289*0Sstevel@tonic-gate 		/* Do not immediately return WALK_DONE below */
290*0Sstevel@tonic-gate 		pwdp->mi_pwd_first = NULL;
291*0Sstevel@tonic-gate 		/* We determined where to begin */
292*0Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)MIH2MIO(mihp);
293*0Sstevel@tonic-gate 	} else {
294*0Sstevel@tonic-gate 		/* Do not cycle through all of the MI_O objects */
295*0Sstevel@tonic-gate 		pwdp->mi_pwd_first = (uintptr_t)MIH2MIO(mihp);
296*0Sstevel@tonic-gate 		/* We were given where to begin */
297*0Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)((MI_OP)wsp->walk_addr - 1);
298*0Sstevel@tonic-gate 	}
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 	if (mdb_layered_walk("genunix`mi", wsp) == -1) {
301*0Sstevel@tonic-gate 		mdb_warn("failed to walk genunix`mi");
302*0Sstevel@tonic-gate 		delete_mi_payload_walk_data(pwdp, arg->mi_pwa_size);
303*0Sstevel@tonic-gate 		return (WALK_ERR);
304*0Sstevel@tonic-gate 	}
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	return (WALK_NEXT);
307*0Sstevel@tonic-gate }
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate int
310*0Sstevel@tonic-gate mi_payload_walk_step(mdb_walk_state_t *wsp)
311*0Sstevel@tonic-gate {
312*0Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
313*0Sstevel@tonic-gate 	mi_payload_walk_data_t *pwdp = wsp->walk_data;
314*0Sstevel@tonic-gate 	void *payload = pwdp->mi_pwd_data;
315*0Sstevel@tonic-gate 	uintptr_t payload_kaddr = (uintptr_t)((MI_OP)wsp->walk_addr + 1);
316*0Sstevel@tonic-gate 	const MI_O *mio = wsp->walk_layer;
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	/* If this is a local walk, prevent cycling */
319*0Sstevel@tonic-gate 	if (wsp->walk_addr == pwdp->mi_pwd_first)
320*0Sstevel@tonic-gate 		return (WALK_DONE);
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	/*
323*0Sstevel@tonic-gate 	 * This was a global walk, prevent reading this payload as the
324*0Sstevel@tonic-gate 	 * initial MI_O is the head of the list and is not the header
325*0Sstevel@tonic-gate 	 * to a valid payload
326*0Sstevel@tonic-gate 	 */
327*0Sstevel@tonic-gate 	if (pwdp->mi_pwd_first == NULL) {
328*0Sstevel@tonic-gate 		pwdp->mi_pwd_first = wsp->walk_addr;
329*0Sstevel@tonic-gate 		return (WALK_NEXT);
330*0Sstevel@tonic-gate 	}
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	if (mio->mi_o_isdev == B_FALSE) {
333*0Sstevel@tonic-gate 		/* mio is a module */
334*0Sstevel@tonic-gate 		if (!(arg->mi_pwa_flags & MI_PAYLOAD_MODULE))
335*0Sstevel@tonic-gate 			return (WALK_NEXT);
336*0Sstevel@tonic-gate 	} else {
337*0Sstevel@tonic-gate 		/* mio is a device */
338*0Sstevel@tonic-gate 		if (!(arg->mi_pwa_flags & MI_PAYLOAD_DEVICE))
339*0Sstevel@tonic-gate 			return (WALK_NEXT);
340*0Sstevel@tonic-gate 	}
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	if (mdb_vread(payload, arg->mi_pwa_size, payload_kaddr) == -1) {
343*0Sstevel@tonic-gate 		mdb_warn("failed to read payload at %p", payload_kaddr);
344*0Sstevel@tonic-gate 		return (WALK_ERR);
345*0Sstevel@tonic-gate 	}
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	return (wsp->walk_callback(payload_kaddr, payload, wsp->walk_cbdata));
348*0Sstevel@tonic-gate }
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate void
351*0Sstevel@tonic-gate mi_payload_walk_fini(mdb_walk_state_t *wsp)
352*0Sstevel@tonic-gate {
353*0Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	delete_mi_payload_walk_data(wsp->walk_data, arg->mi_pwa_size);
356*0Sstevel@tonic-gate }
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate const mi_payload_walk_arg_t mi_udp_arg = {
359*0Sstevel@tonic-gate 	"udp", "udp_g_head", sizeof (udp_t),
360*0Sstevel@tonic-gate 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
361*0Sstevel@tonic-gate };
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate const mi_payload_walk_arg_t mi_ar_arg = {
364*0Sstevel@tonic-gate 	"arp", "ar_g_head", sizeof (ar_t),
365*0Sstevel@tonic-gate 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
366*0Sstevel@tonic-gate };
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate const mi_payload_walk_arg_t mi_icmp_arg = {
369*0Sstevel@tonic-gate 	"icmp", "icmp_g_head", sizeof (icmp_t),
370*0Sstevel@tonic-gate 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
371*0Sstevel@tonic-gate };
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate const mi_payload_walk_arg_t mi_ill_arg =
374*0Sstevel@tonic-gate 	{ "ip", "ip_g_head", sizeof (ill_t), MI_PAYLOAD_MODULE };
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate int
377*0Sstevel@tonic-gate sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
378*0Sstevel@tonic-gate {
379*0Sstevel@tonic-gate 	const char *optf = NULL;
380*0Sstevel@tonic-gate 	const char *optt = NULL;
381*0Sstevel@tonic-gate 	const char *optp = NULL;
382*0Sstevel@tonic-gate 	int family, type, proto;
383*0Sstevel@tonic-gate 	int filter = 0;
384*0Sstevel@tonic-gate 	struct sonode so;
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
387*0Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`sonode", "genunix`sonode", argc,
388*0Sstevel@tonic-gate 		    argv) == -1) {
389*0Sstevel@tonic-gate 			mdb_warn("failed to walk sonode");
390*0Sstevel@tonic-gate 			return (DCMD_ERR);
391*0Sstevel@tonic-gate 		}
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 		return (DCMD_OK);
394*0Sstevel@tonic-gate 	}
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
397*0Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &optf,
398*0Sstevel@tonic-gate 	    't', MDB_OPT_STR, &optt,
399*0Sstevel@tonic-gate 	    'p', MDB_OPT_STR, &optp,
400*0Sstevel@tonic-gate 	    NULL) != argc)
401*0Sstevel@tonic-gate 		return (DCMD_USAGE);
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 	if (optf != NULL) {
404*0Sstevel@tonic-gate 		if (strcmp("inet", optf) == 0)
405*0Sstevel@tonic-gate 			family = AF_INET;
406*0Sstevel@tonic-gate 		else if (strcmp("inet6", optf) == 0)
407*0Sstevel@tonic-gate 			family = AF_INET6;
408*0Sstevel@tonic-gate 		else if (strcmp("unix", optf) == 0)
409*0Sstevel@tonic-gate 			family = AF_UNIX;
410*0Sstevel@tonic-gate 		else
411*0Sstevel@tonic-gate 			family = mdb_strtoull(optf);
412*0Sstevel@tonic-gate 		filter = 1;
413*0Sstevel@tonic-gate 	}
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 	if (optt != NULL) {
416*0Sstevel@tonic-gate 		if (strcmp("stream", optt) == 0)
417*0Sstevel@tonic-gate 			type = SOCK_STREAM;
418*0Sstevel@tonic-gate 		else if (strcmp("dgram", optt) == 0)
419*0Sstevel@tonic-gate 			type = SOCK_DGRAM;
420*0Sstevel@tonic-gate 		else if (strcmp("raw", optt) == 0)
421*0Sstevel@tonic-gate 			type = SOCK_RAW;
422*0Sstevel@tonic-gate 		else
423*0Sstevel@tonic-gate 			type = mdb_strtoull(optt);
424*0Sstevel@tonic-gate 		filter = 1;
425*0Sstevel@tonic-gate 	}
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate 	if (optp != NULL) {
428*0Sstevel@tonic-gate 		proto = mdb_strtoull(optp);
429*0Sstevel@tonic-gate 		filter = 1;
430*0Sstevel@tonic-gate 	}
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !filter) {
433*0Sstevel@tonic-gate 		mdb_printf("%<u>%-?s Family Type Proto State Mode Flag "
434*0Sstevel@tonic-gate 		    "AccessVP%</u>\n", "Sonode:");
435*0Sstevel@tonic-gate 	}
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	if (mdb_vread(&so, sizeof (so), addr) == -1) {
438*0Sstevel@tonic-gate 		mdb_warn("failed to read sonode at %p", addr);
439*0Sstevel@tonic-gate 		return (DCMD_ERR);
440*0Sstevel@tonic-gate 	}
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	if ((optf != NULL) && (so.so_family != family))
443*0Sstevel@tonic-gate 		return (DCMD_OK);
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	if ((optt != NULL) && (so.so_type != type))
446*0Sstevel@tonic-gate 		return (DCMD_OK);
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate 	if ((optp != NULL) && (so.so_protocol != proto))
449*0Sstevel@tonic-gate 		return (DCMD_OK);
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	if (filter) {
452*0Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
453*0Sstevel@tonic-gate 		return (DCMD_OK);
454*0Sstevel@tonic-gate 	}
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	mdb_printf("%0?p ", addr);
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	switch (so.so_family) {
459*0Sstevel@tonic-gate 	    case AF_UNIX:
460*0Sstevel@tonic-gate 		mdb_printf("unix  ");
461*0Sstevel@tonic-gate 		break;
462*0Sstevel@tonic-gate 	    case AF_INET:
463*0Sstevel@tonic-gate 		mdb_printf("inet  ");
464*0Sstevel@tonic-gate 		break;
465*0Sstevel@tonic-gate 	    case AF_INET6:
466*0Sstevel@tonic-gate 		mdb_printf("inet6 ");
467*0Sstevel@tonic-gate 		break;
468*0Sstevel@tonic-gate 	    default:
469*0Sstevel@tonic-gate 		mdb_printf("%6hi", so.so_family);
470*0Sstevel@tonic-gate 	}
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	switch (so.so_type) {
473*0Sstevel@tonic-gate 	    case SOCK_STREAM:
474*0Sstevel@tonic-gate 		mdb_printf(" strm");
475*0Sstevel@tonic-gate 		break;
476*0Sstevel@tonic-gate 	    case SOCK_DGRAM:
477*0Sstevel@tonic-gate 		mdb_printf(" dgrm");
478*0Sstevel@tonic-gate 		break;
479*0Sstevel@tonic-gate 	    case SOCK_RAW:
480*0Sstevel@tonic-gate 		mdb_printf(" raw ");
481*0Sstevel@tonic-gate 		break;
482*0Sstevel@tonic-gate 	    default:
483*0Sstevel@tonic-gate 		mdb_printf(" %4hi", so.so_type);
484*0Sstevel@tonic-gate 	}
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 	mdb_printf(" %5hi %05x %04x %04hx %0?p\n",
487*0Sstevel@tonic-gate 	    so.so_protocol, so.so_state, so.so_mode,
488*0Sstevel@tonic-gate 	    so.so_flag, so.so_accessvp);
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 	return (DCMD_OK);
491*0Sstevel@tonic-gate }
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate #define	MI_PAYLOAD	0x1
494*0Sstevel@tonic-gate #define	MI_DEVICE	0x2
495*0Sstevel@tonic-gate #define	MI_MODULE	0x4
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate int
498*0Sstevel@tonic-gate mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
499*0Sstevel@tonic-gate {
500*0Sstevel@tonic-gate 	uint_t opts = 0;
501*0Sstevel@tonic-gate 	MI_O	mio;
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
504*0Sstevel@tonic-gate 		return (DCMD_USAGE);
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
507*0Sstevel@tonic-gate 	    'p', MDB_OPT_SETBITS, MI_PAYLOAD, &opts,
508*0Sstevel@tonic-gate 	    'd', MDB_OPT_SETBITS, MI_DEVICE, &opts,
509*0Sstevel@tonic-gate 	    'm', MDB_OPT_SETBITS, MI_MODULE, &opts,
510*0Sstevel@tonic-gate 	    NULL) != argc)
511*0Sstevel@tonic-gate 		return (DCMD_USAGE);
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 	if ((opts & (MI_DEVICE | MI_MODULE)) == (MI_DEVICE | MI_MODULE)) {
514*0Sstevel@tonic-gate 		mdb_warn("at most one filter, d for devices or m "
515*0Sstevel@tonic-gate 		    "for modules, may be specified\n");
516*0Sstevel@tonic-gate 		return (DCMD_USAGE);
517*0Sstevel@tonic-gate 	}
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 	if ((opts == 0) && (DCMD_HDRSPEC(flags))) {
520*0Sstevel@tonic-gate 		mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n",
521*0Sstevel@tonic-gate 		    "MI_O", "Next", "Prev");
522*0Sstevel@tonic-gate 	}
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 	if (mdb_vread(&mio, sizeof (mio), addr) == -1) {
525*0Sstevel@tonic-gate 		mdb_warn("failed to read mi object MI_O at %p", addr);
526*0Sstevel@tonic-gate 		return (DCMD_ERR);
527*0Sstevel@tonic-gate 	}
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 	if (opts != 0) {
530*0Sstevel@tonic-gate 		if (mio.mi_o_isdev == B_FALSE) {
531*0Sstevel@tonic-gate 			/* mio is a module */
532*0Sstevel@tonic-gate 			if (!(opts & MI_MODULE) && (opts & MI_DEVICE))
533*0Sstevel@tonic-gate 				return (DCMD_OK);
534*0Sstevel@tonic-gate 		} else {
535*0Sstevel@tonic-gate 			/* mio is a device */
536*0Sstevel@tonic-gate 			if (!(opts & MI_DEVICE) && (opts & MI_MODULE))
537*0Sstevel@tonic-gate 				return (DCMD_OK);
538*0Sstevel@tonic-gate 		}
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate 		if (opts & MI_PAYLOAD)
541*0Sstevel@tonic-gate 			mdb_printf("%p\n", addr + sizeof (MI_O));
542*0Sstevel@tonic-gate 		else
543*0Sstevel@tonic-gate 			mdb_printf("%p\n", addr);
544*0Sstevel@tonic-gate 		return (DCMD_OK);
545*0Sstevel@tonic-gate 	}
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 	mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev);
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 	if (mio.mi_o_isdev == B_FALSE)
550*0Sstevel@tonic-gate 		mdb_printf("FALSE");
551*0Sstevel@tonic-gate 	else
552*0Sstevel@tonic-gate 		mdb_printf("TRUE ");
553*0Sstevel@tonic-gate 
554*0Sstevel@tonic-gate 	mdb_printf(" %0?p\n", mio.mi_o_dev);
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	return (DCMD_OK);
557*0Sstevel@tonic-gate }
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate static void
560*0Sstevel@tonic-gate netstat_tcp_verbose_pr(const tcp_t *tcp)
561*0Sstevel@tonic-gate {
562*0Sstevel@tonic-gate 	mdb_printf("       %5i %08x %08x %5i %08x %08x %5li %5i\n",
563*0Sstevel@tonic-gate 	    tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
564*0Sstevel@tonic-gate 	    tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
565*0Sstevel@tonic-gate }
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate /*ARGSUSED*/
568*0Sstevel@tonic-gate static int
569*0Sstevel@tonic-gate netstat_tcp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data, int af)
570*0Sstevel@tonic-gate {
571*0Sstevel@tonic-gate 	const uintptr_t opts = (uintptr_t)cb_data;
572*0Sstevel@tonic-gate 	static size_t itc_size = 0;
573*0Sstevel@tonic-gate 	uintptr_t tcp_kaddr;
574*0Sstevel@tonic-gate 	conn_t *connp;
575*0Sstevel@tonic-gate 	tcp_t *tcp;
576*0Sstevel@tonic-gate 
577*0Sstevel@tonic-gate 	if (itc_size == 0) {
578*0Sstevel@tonic-gate 		mdb_ctf_id_t id;
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 		if (mdb_ctf_lookup_by_name("itc_t", &id) != 0) {
581*0Sstevel@tonic-gate 			mdb_warn("failed to lookup type 'itc_t'");
582*0Sstevel@tonic-gate 			return (WALK_ERR);
583*0Sstevel@tonic-gate 		}
584*0Sstevel@tonic-gate 		itc_size = mdb_ctf_type_size(id);
585*0Sstevel@tonic-gate 	}
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate 	connp = (conn_t *)mdb_alloc(itc_size, UM_SLEEP | UM_GC);
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 	if (mdb_vread(connp, itc_size, kaddr) == -1) {
590*0Sstevel@tonic-gate 		mdb_warn("failed to read connection info at %p", kaddr);
591*0Sstevel@tonic-gate 		return (WALK_ERR);
592*0Sstevel@tonic-gate 	}
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 	tcp_kaddr = (uintptr_t)connp->conn_tcp;
595*0Sstevel@tonic-gate 	tcp = (tcp_t *)((uintptr_t)connp + (tcp_kaddr - kaddr));
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate 	if ((uintptr_t)tcp < (uintptr_t)connp ||
598*0Sstevel@tonic-gate 	    (uintptr_t)&tcp->tcp_connp > (uintptr_t)connp + itc_size ||
599*0Sstevel@tonic-gate 	    (uintptr_t)tcp->tcp_connp != kaddr) {
600*0Sstevel@tonic-gate 		mdb_warn("conn_tcp %p is invalid", tcp_kaddr);
601*0Sstevel@tonic-gate 		return (WALK_NEXT);
602*0Sstevel@tonic-gate 	}
603*0Sstevel@tonic-gate 	connp->conn_tcp = tcp;
604*0Sstevel@tonic-gate 	tcp->tcp_connp = connp;
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 	if (!(opts & NETSTAT_ALL || net_tcp_active(tcp)) ||
607*0Sstevel@tonic-gate 	    (af == AF_INET && !net_tcp_ipv4(tcp)) ||
608*0Sstevel@tonic-gate 	    (af == AF_INET6 && !net_tcp_ipv6(tcp))) {
609*0Sstevel@tonic-gate 		return (WALK_NEXT);
610*0Sstevel@tonic-gate 	}
611*0Sstevel@tonic-gate 
612*0Sstevel@tonic-gate 	mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state);
613*0Sstevel@tonic-gate 	if (af == AF_INET) {
614*0Sstevel@tonic-gate 		net_ipv4addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport);
615*0Sstevel@tonic-gate 		mdb_printf(" ");
616*0Sstevel@tonic-gate 		net_ipv4addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport);
617*0Sstevel@tonic-gate 	} else if (af == AF_INET6) {
618*0Sstevel@tonic-gate 		net_ipv6addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport);
619*0Sstevel@tonic-gate 		mdb_printf(" ");
620*0Sstevel@tonic-gate 		net_ipv6addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport);
621*0Sstevel@tonic-gate 	}
622*0Sstevel@tonic-gate 	mdb_printf(" %4i\n", connp->conn_zoneid);
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 	if (opts & NETSTAT_VERBOSE)
625*0Sstevel@tonic-gate 		netstat_tcp_verbose_pr(tcp);
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 	return (WALK_NEXT);
628*0Sstevel@tonic-gate }
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate static int
631*0Sstevel@tonic-gate netstat_tcpv4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
632*0Sstevel@tonic-gate {
633*0Sstevel@tonic-gate 	return (netstat_tcp_cb(kaddr, walk_data, cb_data, AF_INET));
634*0Sstevel@tonic-gate }
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate static int
637*0Sstevel@tonic-gate netstat_tcpv6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
638*0Sstevel@tonic-gate {
639*0Sstevel@tonic-gate 	return (netstat_tcp_cb(kaddr, walk_data, cb_data, AF_INET6));
640*0Sstevel@tonic-gate }
641*0Sstevel@tonic-gate 
642*0Sstevel@tonic-gate static int
643*0Sstevel@tonic-gate netstat_udpv4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
644*0Sstevel@tonic-gate {
645*0Sstevel@tonic-gate 	const udp_t *udp = walk_data;
646*0Sstevel@tonic-gate 	const uintptr_t opts = (uintptr_t)cb_data;
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 	if (!((opts & NETSTAT_ALL || net_udp_active(udp)) && net_udp_ipv4(udp)))
649*0Sstevel@tonic-gate 		return (WALK_NEXT);
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 	mdb_printf("%0?p %2i ", kaddr, udp->udp_state);
652*0Sstevel@tonic-gate 	net_ipv4addrport_pr(&udp->udp_v6src, udp->udp_port);
653*0Sstevel@tonic-gate 	mdb_printf(" ");
654*0Sstevel@tonic-gate 	net_ipv4addrport_pr(&udp->udp_v6dst, udp->udp_dstport);
655*0Sstevel@tonic-gate 	mdb_printf(" %4i\n", udp->udp_zoneid);
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	return (WALK_NEXT);
658*0Sstevel@tonic-gate }
659*0Sstevel@tonic-gate 
660*0Sstevel@tonic-gate static int
661*0Sstevel@tonic-gate netstat_udpv6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
662*0Sstevel@tonic-gate {
663*0Sstevel@tonic-gate 	const udp_t *udp = walk_data;
664*0Sstevel@tonic-gate 	const uintptr_t opts = (uintptr_t)cb_data;
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 	if (!((opts & NETSTAT_ALL || net_udp_active(udp)) && net_udp_ipv6(udp)))
667*0Sstevel@tonic-gate 		return (WALK_NEXT);
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	mdb_printf("%0?p %2i ", kaddr, udp->udp_state);
670*0Sstevel@tonic-gate 	net_ipv6addrport_pr(&udp->udp_v6src, udp->udp_port);
671*0Sstevel@tonic-gate 	mdb_printf(" ");
672*0Sstevel@tonic-gate 
673*0Sstevel@tonic-gate 	/* Remote */
674*0Sstevel@tonic-gate 	if (udp->udp_state == TS_DATA_XFER)
675*0Sstevel@tonic-gate 		net_ipv6addrport_pr(&udp->udp_v6dst, udp->udp_dstport);
676*0Sstevel@tonic-gate 	else
677*0Sstevel@tonic-gate 		mdb_printf("%*s.0    ", ADDR_V6_WIDTH, "0:0:0:0:0:0:0:0");
678*0Sstevel@tonic-gate 	mdb_printf(" %4i\n", udp->udp_zoneid);
679*0Sstevel@tonic-gate 
680*0Sstevel@tonic-gate 	return (WALK_NEXT);
681*0Sstevel@tonic-gate }
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate /*
684*0Sstevel@tonic-gate  * print the address of a unix domain socket
685*0Sstevel@tonic-gate  *
686*0Sstevel@tonic-gate  * so is the address of a AF_UNIX struct sonode in mdb's address space
687*0Sstevel@tonic-gate  * soa is the address of the struct soaddr to print
688*0Sstevel@tonic-gate  *
689*0Sstevel@tonic-gate  * returns 0 on success, -1 otherwise
690*0Sstevel@tonic-gate  */
691*0Sstevel@tonic-gate static int
692*0Sstevel@tonic-gate netstat_unix_name_pr(const struct sonode *so, const struct soaddr *soa)
693*0Sstevel@tonic-gate {
694*0Sstevel@tonic-gate 	const char none[] = " (none)";
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate 	if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) {
697*0Sstevel@tonic-gate 		if (so->so_state & SS_FADDR_NOXLATE) {
698*0Sstevel@tonic-gate 			mdb_printf("%-14s ", " (socketpair)");
699*0Sstevel@tonic-gate 		} else {
700*0Sstevel@tonic-gate 			if (soa->soa_len > sizeof (sa_family_t)) {
701*0Sstevel@tonic-gate 				char addr[MAXPATHLEN + 1];
702*0Sstevel@tonic-gate 
703*0Sstevel@tonic-gate 				if (mdb_readstr(addr, sizeof (addr),
704*0Sstevel@tonic-gate 				    (uintptr_t)&soa->soa_sa->sa_data) == -1) {
705*0Sstevel@tonic-gate 					mdb_warn("failed to read unix address "
706*0Sstevel@tonic-gate 					    "at %p", &soa->soa_sa->sa_data);
707*0Sstevel@tonic-gate 					return (-1);
708*0Sstevel@tonic-gate 				}
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate 				mdb_printf("%-14s ", addr);
711*0Sstevel@tonic-gate 			} else {
712*0Sstevel@tonic-gate 				mdb_printf("%-14s ", none);
713*0Sstevel@tonic-gate 			}
714*0Sstevel@tonic-gate 		}
715*0Sstevel@tonic-gate 	} else {
716*0Sstevel@tonic-gate 		mdb_printf("%-14s ", none);
717*0Sstevel@tonic-gate 	}
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 	return (0);
720*0Sstevel@tonic-gate }
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate /* based on sockfs_snapshot */
723*0Sstevel@tonic-gate /*ARGSUSED*/
724*0Sstevel@tonic-gate static int
725*0Sstevel@tonic-gate netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
726*0Sstevel@tonic-gate {
727*0Sstevel@tonic-gate 	const struct sonode *so = walk_data;
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 	if (so->so_accessvp == NULL)
730*0Sstevel@tonic-gate 		return (WALK_NEXT);
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 	if (so->so_family != AF_UNIX) {
733*0Sstevel@tonic-gate 		mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr);
734*0Sstevel@tonic-gate 		return (WALK_ERR);
735*0Sstevel@tonic-gate 	}
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 	mdb_printf("%-?p ", kaddr);
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate 	switch (so->so_serv_type) {
740*0Sstevel@tonic-gate 	    case T_CLTS:
741*0Sstevel@tonic-gate 		mdb_printf("%-10s ", "dgram");
742*0Sstevel@tonic-gate 		break;
743*0Sstevel@tonic-gate 	    case T_COTS:
744*0Sstevel@tonic-gate 		mdb_printf("%-10s ", "stream");
745*0Sstevel@tonic-gate 		break;
746*0Sstevel@tonic-gate 	    case T_COTS_ORD:
747*0Sstevel@tonic-gate 		mdb_printf("%-10s ", "stream-ord");
748*0Sstevel@tonic-gate 		break;
749*0Sstevel@tonic-gate 	    default:
750*0Sstevel@tonic-gate 		    mdb_printf("%-10i ", so->so_serv_type);
751*0Sstevel@tonic-gate 	}
752*0Sstevel@tonic-gate 
753*0Sstevel@tonic-gate 	if ((so->so_state & SS_ISBOUND) &&
754*0Sstevel@tonic-gate 	    (so->so_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
755*0Sstevel@tonic-gate 		mdb_printf("%0?p ", so->so_ux_laddr.soua_vp);
756*0Sstevel@tonic-gate 	} else {
757*0Sstevel@tonic-gate 		mdb_printf("%0?p ", NULL);
758*0Sstevel@tonic-gate 	}
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 	if ((so->so_state & SS_ISCONNECTED) &&
761*0Sstevel@tonic-gate 	    (so->so_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
762*0Sstevel@tonic-gate 		mdb_printf("%0?p ", so->so_ux_faddr.soua_vp);
763*0Sstevel@tonic-gate 	} else {
764*0Sstevel@tonic-gate 		mdb_printf("%0?p ", NULL);
765*0Sstevel@tonic-gate 	}
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate 	if (netstat_unix_name_pr(so, &so->so_laddr) == -1)
768*0Sstevel@tonic-gate 		return (WALK_ERR);
769*0Sstevel@tonic-gate 
770*0Sstevel@tonic-gate 	if (netstat_unix_name_pr(so, &so->so_faddr) == -1)
771*0Sstevel@tonic-gate 		return (WALK_ERR);
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	mdb_printf("%4i\n", so->so_zoneid);
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 	return (WALK_NEXT);
776*0Sstevel@tonic-gate }
777*0Sstevel@tonic-gate 
778*0Sstevel@tonic-gate static void
779*0Sstevel@tonic-gate netstat_tcp_verbose_header_pr(void)
780*0Sstevel@tonic-gate {
781*0Sstevel@tonic-gate 	mdb_printf("       %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n",
782*0Sstevel@tonic-gate 	    "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss");
783*0Sstevel@tonic-gate }
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate /*ARGSUSED*/
786*0Sstevel@tonic-gate int
787*0Sstevel@tonic-gate netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
788*0Sstevel@tonic-gate {
789*0Sstevel@tonic-gate 	uint_t opts = 0;
790*0Sstevel@tonic-gate 	const char *optf = NULL;
791*0Sstevel@tonic-gate 	const char *optP = NULL;
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
794*0Sstevel@tonic-gate 	    'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts,
795*0Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts,
796*0Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &optf,
797*0Sstevel@tonic-gate 	    'P', MDB_OPT_STR, &optP,
798*0Sstevel@tonic-gate 	    NULL) != argc)
799*0Sstevel@tonic-gate 		return (DCMD_USAGE);
800*0Sstevel@tonic-gate 
801*0Sstevel@tonic-gate 	if (optP != NULL) {
802*0Sstevel@tonic-gate 		if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0))
803*0Sstevel@tonic-gate 			return (DCMD_USAGE);
804*0Sstevel@tonic-gate 
805*0Sstevel@tonic-gate 	}
806*0Sstevel@tonic-gate 
807*0Sstevel@tonic-gate 	if (optf != NULL) {
808*0Sstevel@tonic-gate 		if ((strcmp("inet", optf) != 0) &&
809*0Sstevel@tonic-gate 		    (strcmp("inet6", optf) != 0) &&
810*0Sstevel@tonic-gate 		    (strcmp("unix", optf) != 0))
811*0Sstevel@tonic-gate 			return (DCMD_USAGE);
812*0Sstevel@tonic-gate 	}
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 	if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
815*0Sstevel@tonic-gate 		if ((optf == NULL) || (strcmp("inet", optf) == 0)) {
816*0Sstevel@tonic-gate 			/* Print TCPv4 connection */
817*0Sstevel@tonic-gate 			mdb_printf(
818*0Sstevel@tonic-gate 			    "%<u>%-?s St %*s       %*s       %s%</u>\n",
819*0Sstevel@tonic-gate 			    "TCPv4", ADDR_V4_WIDTH, "Local Address",
820*0Sstevel@tonic-gate 			    ADDR_V4_WIDTH, "Remote Address", "Zone");
821*0Sstevel@tonic-gate 
822*0Sstevel@tonic-gate 			if (opts & NETSTAT_VERBOSE)
823*0Sstevel@tonic-gate 				netstat_tcp_verbose_header_pr();
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 			if (mdb_walk("ipcl_tcpconn_cache", netstat_tcpv4_cb,
826*0Sstevel@tonic-gate 			    (void *)(uintptr_t)opts) == -1) {
827*0Sstevel@tonic-gate 				mdb_warn("failed to walk ipcl_tcpconn_cache");
828*0Sstevel@tonic-gate 				return (DCMD_ERR);
829*0Sstevel@tonic-gate 			}
830*0Sstevel@tonic-gate 		}
831*0Sstevel@tonic-gate 
832*0Sstevel@tonic-gate 		if ((optf == NULL) || (strcmp("inet6", optf) == 0)) {
833*0Sstevel@tonic-gate 			/* Print TCPv6 connection */
834*0Sstevel@tonic-gate 			mdb_printf(
835*0Sstevel@tonic-gate 			    "%<u>%-?s St %*s       %*s       %s\n%</u>",
836*0Sstevel@tonic-gate 			    "TCPv6", ADDR_V6_WIDTH, "Local Address",
837*0Sstevel@tonic-gate 			    ADDR_V6_WIDTH, "Remote Address", "Zone");
838*0Sstevel@tonic-gate 
839*0Sstevel@tonic-gate 			if (opts & NETSTAT_VERBOSE)
840*0Sstevel@tonic-gate 				netstat_tcp_verbose_header_pr();
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 			if (mdb_walk("ipcl_tcpconn_cache", netstat_tcpv6_cb,
843*0Sstevel@tonic-gate 			    (void *)(uintptr_t)opts) == -1) {
844*0Sstevel@tonic-gate 				mdb_warn("failed to walk ipcl_tcpconn_cache");
845*0Sstevel@tonic-gate 				return (DCMD_ERR);
846*0Sstevel@tonic-gate 			}
847*0Sstevel@tonic-gate 		}
848*0Sstevel@tonic-gate 	}
849*0Sstevel@tonic-gate 
850*0Sstevel@tonic-gate 	if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
851*0Sstevel@tonic-gate 		if ((optf == NULL) || (strcmp("inet", optf) == 0)) {
852*0Sstevel@tonic-gate 			/* Print UDPv4 connection */
853*0Sstevel@tonic-gate 			mdb_printf(
854*0Sstevel@tonic-gate 			    "%<u>%-?s St %*s       %*s       %s\n%</u>",
855*0Sstevel@tonic-gate 			    "UDPv4", ADDR_V4_WIDTH, "Local Address",
856*0Sstevel@tonic-gate 			    ADDR_V4_WIDTH, "Remote Address", "Zone");
857*0Sstevel@tonic-gate 
858*0Sstevel@tonic-gate 			if (mdb_walk("genunix`udp", netstat_udpv4_cb,
859*0Sstevel@tonic-gate 			    (void *)(uintptr_t)opts) == -1) {
860*0Sstevel@tonic-gate 				mdb_warn("failed to walk genunix`udp");
861*0Sstevel@tonic-gate 				return (DCMD_ERR);
862*0Sstevel@tonic-gate 			}
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate 		}
865*0Sstevel@tonic-gate 
866*0Sstevel@tonic-gate 		if ((optf == NULL) || (strcmp("inet6", optf) == 0)) {
867*0Sstevel@tonic-gate 			/* Print UDPv6 connection */
868*0Sstevel@tonic-gate 			mdb_printf(
869*0Sstevel@tonic-gate 			    "%<u>%-?s St %*s       %*s       %s\n%</u>",
870*0Sstevel@tonic-gate 			    "UDPv6", ADDR_V6_WIDTH, "Local Address",
871*0Sstevel@tonic-gate 			    ADDR_V6_WIDTH, "Remote Address", "Zone");
872*0Sstevel@tonic-gate 
873*0Sstevel@tonic-gate 			if (mdb_walk("genunix`udp", netstat_udpv6_cb,
874*0Sstevel@tonic-gate 			    (void *)(uintptr_t)opts) == -1) {
875*0Sstevel@tonic-gate 				mdb_warn("failed to walk genunix`udp");
876*0Sstevel@tonic-gate 				return (DCMD_ERR);
877*0Sstevel@tonic-gate 			}
878*0Sstevel@tonic-gate 
879*0Sstevel@tonic-gate 		}
880*0Sstevel@tonic-gate 	}
881*0Sstevel@tonic-gate 
882*0Sstevel@tonic-gate 	if (((optf == NULL) || (strcmp("unix", optf) == 0)) && (optP == NULL)) {
883*0Sstevel@tonic-gate 		/* Print Unix Domain Sockets */
884*0Sstevel@tonic-gate 		mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n",
885*0Sstevel@tonic-gate 		    "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr",
886*0Sstevel@tonic-gate 		    "Remote Addr", "Zone");
887*0Sstevel@tonic-gate 
888*0Sstevel@tonic-gate 		if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) {
889*0Sstevel@tonic-gate 			mdb_warn("failed to walk genunix`sonode");
890*0Sstevel@tonic-gate 			return (DCMD_ERR);
891*0Sstevel@tonic-gate 		}
892*0Sstevel@tonic-gate 	}
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate 	return (DCMD_OK);
895*0Sstevel@tonic-gate }
896