xref: /illumos-gate/usr/src/cmd/mdb/common/modules/genunix/net.c (revision 50dd07834a09a878d0649ea5b597e84ff6bcc445)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d5b6ed4bSVasumathi Sundaram - Sun Microsystems  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*50dd0783SToomas Soome  * Copyright 2024 MNX Cloud, Inc.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
287c478bd9Sstevel@tonic-gate #include <mdb/mdb_ks.h>
297c478bd9Sstevel@tonic-gate #include <mdb/mdb_ctf.h>
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
327c478bd9Sstevel@tonic-gate #include <inet/led.h>
337c478bd9Sstevel@tonic-gate #include <inet/common.h>
347c478bd9Sstevel@tonic-gate #include <netinet/in.h>
357c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
367c478bd9Sstevel@tonic-gate #include <netinet/icmp6.h>
377c478bd9Sstevel@tonic-gate #include <inet/ip.h>
387c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
397c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h>
407c478bd9Sstevel@tonic-gate #include <inet/tcp.h>
417c478bd9Sstevel@tonic-gate #include <sys/stream.h>
427c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
437c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
447c478bd9Sstevel@tonic-gate #include <sys/tpicommon.h>
457c478bd9Sstevel@tonic-gate #include <sys/socket.h>
467c478bd9Sstevel@tonic-gate #include <sys/socketvar.h>
477c478bd9Sstevel@tonic-gate #include <sys/cred_impl.h>
487c478bd9Sstevel@tonic-gate #include <inet/udp_impl.h>
497c478bd9Sstevel@tonic-gate #include <inet/rawip_impl.h>
507c478bd9Sstevel@tonic-gate #include <inet/mi.h>
510f1702c5SYu Xiangning #include <fs/sockfs/socktpi_impl.h>
524eaa4710SRishi Srivatsavai #include <net/bridge_impl.h>
534eaa4710SRishi Srivatsavai #include <io/trill_impl.h>
544eaa4710SRishi Srivatsavai #include <sys/mac_impl.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #define	ADDR_V6_WIDTH	23
577c478bd9Sstevel@tonic-gate #define	ADDR_V4_WIDTH	15
587c478bd9Sstevel@tonic-gate 
5945916cd2Sjpk #define	NETSTAT_ALL	0x01
6045916cd2Sjpk #define	NETSTAT_VERBOSE	0x02
6145916cd2Sjpk #define	NETSTAT_ROUTE	0x04
6245916cd2Sjpk #define	NETSTAT_V4	0x08
6345916cd2Sjpk #define	NETSTAT_V6	0x10
6445916cd2Sjpk #define	NETSTAT_UNIX	0x20
6545916cd2Sjpk 
6645916cd2Sjpk #define	NETSTAT_FIRST	0x80000000u
677c478bd9Sstevel@tonic-gate 
68d5b6ed4bSVasumathi Sundaram - Sun Microsystems typedef struct netstat_cb_data_s {
69d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	uint_t	opts;
70d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	conn_t	conn;
71d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	int	af;
72*50dd0783SToomas Soome 	union {
73*50dd0783SToomas Soome 		tcp_t tcp;
74*50dd0783SToomas Soome 		udp_t udp;
75*50dd0783SToomas Soome 		icmp_t icmp;
76*50dd0783SToomas Soome 	} cb_proto;
77d5b6ed4bSVasumathi Sundaram - Sun Microsystems } netstat_cb_data_t;
78f4b3ec61Sdh155122 
79f4b3ec61Sdh155122 int
icmp_stacks_walk_init(mdb_walk_state_t * wsp)80f4b3ec61Sdh155122 icmp_stacks_walk_init(mdb_walk_state_t *wsp)
81f4b3ec61Sdh155122 {
82f4b3ec61Sdh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
83f4b3ec61Sdh155122 		mdb_warn("can't walk 'netstack'");
84f4b3ec61Sdh155122 		return (WALK_ERR);
85f4b3ec61Sdh155122 	}
86f4b3ec61Sdh155122 	return (WALK_NEXT);
87f4b3ec61Sdh155122 }
88f4b3ec61Sdh155122 
89f4b3ec61Sdh155122 int
icmp_stacks_walk_step(mdb_walk_state_t * wsp)90f4b3ec61Sdh155122 icmp_stacks_walk_step(mdb_walk_state_t *wsp)
91f4b3ec61Sdh155122 {
92f4b3ec61Sdh155122 	uintptr_t kaddr;
93f4b3ec61Sdh155122 	netstack_t nss;
94f4b3ec61Sdh155122 
95f4b3ec61Sdh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
96f4b3ec61Sdh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
97f4b3ec61Sdh155122 		return (WALK_ERR);
98f4b3ec61Sdh155122 	}
99f4b3ec61Sdh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_ICMP];
100f4b3ec61Sdh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
101f4b3ec61Sdh155122 }
102f4b3ec61Sdh155122 
103f4b3ec61Sdh155122 int
tcp_stacks_walk_init(mdb_walk_state_t * wsp)104f4b3ec61Sdh155122 tcp_stacks_walk_init(mdb_walk_state_t *wsp)
105f4b3ec61Sdh155122 {
106f4b3ec61Sdh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
107f4b3ec61Sdh155122 		mdb_warn("can't walk 'netstack'");
108f4b3ec61Sdh155122 		return (WALK_ERR);
109f4b3ec61Sdh155122 	}
110f4b3ec61Sdh155122 	return (WALK_NEXT);
111f4b3ec61Sdh155122 }
112f4b3ec61Sdh155122 
113f4b3ec61Sdh155122 int
tcp_stacks_walk_step(mdb_walk_state_t * wsp)114f4b3ec61Sdh155122 tcp_stacks_walk_step(mdb_walk_state_t *wsp)
115f4b3ec61Sdh155122 {
116f4b3ec61Sdh155122 	uintptr_t kaddr;
117f4b3ec61Sdh155122 	netstack_t nss;
118f4b3ec61Sdh155122 
119f4b3ec61Sdh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
120f4b3ec61Sdh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
121f4b3ec61Sdh155122 		return (WALK_ERR);
122f4b3ec61Sdh155122 	}
123f4b3ec61Sdh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_TCP];
124f4b3ec61Sdh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
125f4b3ec61Sdh155122 }
126f4b3ec61Sdh155122 
127f4b3ec61Sdh155122 int
udp_stacks_walk_init(mdb_walk_state_t * wsp)128f4b3ec61Sdh155122 udp_stacks_walk_init(mdb_walk_state_t *wsp)
129f4b3ec61Sdh155122 {
130f4b3ec61Sdh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
131f4b3ec61Sdh155122 		mdb_warn("can't walk 'netstack'");
132f4b3ec61Sdh155122 		return (WALK_ERR);
133f4b3ec61Sdh155122 	}
134f4b3ec61Sdh155122 	return (WALK_NEXT);
135f4b3ec61Sdh155122 }
136f4b3ec61Sdh155122 
137f4b3ec61Sdh155122 int
udp_stacks_walk_step(mdb_walk_state_t * wsp)138f4b3ec61Sdh155122 udp_stacks_walk_step(mdb_walk_state_t *wsp)
139f4b3ec61Sdh155122 {
140f4b3ec61Sdh155122 	uintptr_t kaddr;
141f4b3ec61Sdh155122 	netstack_t nss;
142f4b3ec61Sdh155122 
143f4b3ec61Sdh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
144f4b3ec61Sdh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
145f4b3ec61Sdh155122 		return (WALK_ERR);
146f4b3ec61Sdh155122 	}
147f4b3ec61Sdh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_UDP];
148f4b3ec61Sdh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
149f4b3ec61Sdh155122 }
150f4b3ec61Sdh155122 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * Print an IPv4 address and port number in a compact and easy to read format
1537c478bd9Sstevel@tonic-gate  * The arguments are in network byte order
1547c478bd9Sstevel@tonic-gate  */
1557c478bd9Sstevel@tonic-gate static void
net_ipv4addrport_pr(const in6_addr_t * nipv6addr,in_port_t nport)1567c478bd9Sstevel@tonic-gate net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	uint32_t naddr = V4_PART_OF_V6((*nipv6addr));
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	mdb_nhconvert(&nport, &nport, sizeof (nport));
1617c478bd9Sstevel@tonic-gate 	mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport);
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate /*
1657c478bd9Sstevel@tonic-gate  * Print an IPv6 address and port number in a compact and easy to read format
1667c478bd9Sstevel@tonic-gate  * The arguments are in network byte order
1677c478bd9Sstevel@tonic-gate  */
1687c478bd9Sstevel@tonic-gate static void
net_ipv6addrport_pr(const in6_addr_t * naddr,in_port_t nport)1697c478bd9Sstevel@tonic-gate net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport)
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate 	mdb_nhconvert(&nport, &nport, sizeof (nport));
1727c478bd9Sstevel@tonic-gate 	mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport);
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate static int
net_tcp_active(const tcp_t * tcp)1767c478bd9Sstevel@tonic-gate net_tcp_active(const tcp_t *tcp)
1777c478bd9Sstevel@tonic-gate {
1787c478bd9Sstevel@tonic-gate 	return (tcp->tcp_state >= TCPS_ESTABLISHED);
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate static int
net_tcp_ipv4(const tcp_t * tcp)1827c478bd9Sstevel@tonic-gate net_tcp_ipv4(const tcp_t *tcp)
1837c478bd9Sstevel@tonic-gate {
184bd670b35SErik Nordmark 	return ((tcp->tcp_connp->conn_ipversion == IPV4_VERSION) ||
185bd670b35SErik Nordmark 	    (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_connp->conn_laddr_v6) &&
1867c478bd9Sstevel@tonic-gate 	    (tcp->tcp_state <= TCPS_LISTEN)));
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate static int
net_tcp_ipv6(const tcp_t * tcp)1907c478bd9Sstevel@tonic-gate net_tcp_ipv6(const tcp_t *tcp)
1917c478bd9Sstevel@tonic-gate {
192bd670b35SErik Nordmark 	return (tcp->tcp_connp->conn_ipversion == IPV6_VERSION);
1937c478bd9Sstevel@tonic-gate }
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate static int
net_udp_active(const udp_t * udp)1967c478bd9Sstevel@tonic-gate net_udp_active(const udp_t *udp)
1977c478bd9Sstevel@tonic-gate {
198ff550d0eSmasputra 	return ((udp->udp_state == TS_IDLE) ||
199ff550d0eSmasputra 	    (udp->udp_state == TS_DATA_XFER));
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static int
net_udp_ipv4(const udp_t * udp)2037c478bd9Sstevel@tonic-gate net_udp_ipv4(const udp_t *udp)
2047c478bd9Sstevel@tonic-gate {
205bd670b35SErik Nordmark 	return ((udp->udp_connp->conn_ipversion == IPV4_VERSION) ||
206bd670b35SErik Nordmark 	    (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_connp->conn_laddr_v6) &&
2077c478bd9Sstevel@tonic-gate 	    (udp->udp_state <= TS_IDLE)));
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate static int
net_udp_ipv6(const udp_t * udp)2117c478bd9Sstevel@tonic-gate net_udp_ipv6(const udp_t *udp)
2127c478bd9Sstevel@tonic-gate {
213bd670b35SErik Nordmark 	return (udp->udp_connp->conn_ipversion == IPV6_VERSION);
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate int
sonode_walk_init(mdb_walk_state_t * wsp)2177c478bd9Sstevel@tonic-gate sonode_walk_init(mdb_walk_state_t *wsp)
2187c478bd9Sstevel@tonic-gate {
219892ad162SToomas Soome 	if (wsp->walk_addr == 0) {
2207c478bd9Sstevel@tonic-gate 		GElf_Sym sym;
2217c478bd9Sstevel@tonic-gate 		struct socklist *slp;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 		if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) {
2247c478bd9Sstevel@tonic-gate 			mdb_warn("failed to lookup sockfs`socklist");
2257c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
2267c478bd9Sstevel@tonic-gate 		}
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 		slp = (struct socklist *)(uintptr_t)sym.st_value;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 		if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),
2317c478bd9Sstevel@tonic-gate 		    (uintptr_t)&slp->sl_list) == -1) {
2327c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read address of initial sonode "
2337c478bd9Sstevel@tonic-gate 			    "at %p", &slp->sl_list);
2347c478bd9Sstevel@tonic-gate 			return (WALK_ERR);
2357c478bd9Sstevel@tonic-gate 		}
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 
2380f1702c5SYu Xiangning 	wsp->walk_data = mdb_alloc(sizeof (struct sotpi_sonode), UM_SLEEP);
2397c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate int
sonode_walk_step(mdb_walk_state_t * wsp)2437c478bd9Sstevel@tonic-gate sonode_walk_step(mdb_walk_state_t *wsp)
2447c478bd9Sstevel@tonic-gate {
2457c478bd9Sstevel@tonic-gate 	int status;
2460f1702c5SYu Xiangning 	struct sotpi_sonode *stp;
2477c478bd9Sstevel@tonic-gate 
248892ad162SToomas Soome 	if (wsp->walk_addr == 0)
2497c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
2507c478bd9Sstevel@tonic-gate 
2510f1702c5SYu Xiangning 	if (mdb_vread(wsp->walk_data, sizeof (struct sotpi_sonode),
2527c478bd9Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
2537c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read sonode at %p", wsp->walk_addr);
2547c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
2587c478bd9Sstevel@tonic-gate 	    wsp->walk_cbdata);
2597c478bd9Sstevel@tonic-gate 
2600f1702c5SYu Xiangning 	stp = wsp->walk_data;
2617c478bd9Sstevel@tonic-gate 
2620f1702c5SYu Xiangning 	wsp->walk_addr = (uintptr_t)stp->st_info.sti_next_so;
2637c478bd9Sstevel@tonic-gate 	return (status);
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate void
sonode_walk_fini(mdb_walk_state_t * wsp)2677c478bd9Sstevel@tonic-gate sonode_walk_fini(mdb_walk_state_t *wsp)
2687c478bd9Sstevel@tonic-gate {
2690f1702c5SYu Xiangning 	mdb_free(wsp->walk_data, sizeof (struct sotpi_sonode));
2707c478bd9Sstevel@tonic-gate }
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate struct mi_walk_data {
2737c478bd9Sstevel@tonic-gate 	uintptr_t mi_wd_miofirst;
2747c478bd9Sstevel@tonic-gate 	MI_O mi_wd_miodata;
2757c478bd9Sstevel@tonic-gate };
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate int
mi_walk_init(mdb_walk_state_t * wsp)2787c478bd9Sstevel@tonic-gate mi_walk_init(mdb_walk_state_t *wsp)
2797c478bd9Sstevel@tonic-gate {
2807c478bd9Sstevel@tonic-gate 	struct mi_walk_data *wdp;
2817c478bd9Sstevel@tonic-gate 
282892ad162SToomas Soome 	if (wsp->walk_addr == 0) {
2837c478bd9Sstevel@tonic-gate 		mdb_warn("mi doesn't support global walks\n");
2847c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP);
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	/* So that we do not immediately return WALK_DONE below */
290892ad162SToomas Soome 	wdp->mi_wd_miofirst = 0;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	wsp->walk_data = wdp;
2937c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate int
mi_walk_step(mdb_walk_state_t * wsp)2977c478bd9Sstevel@tonic-gate mi_walk_step(mdb_walk_state_t *wsp)
2987c478bd9Sstevel@tonic-gate {
2997c478bd9Sstevel@tonic-gate 	struct mi_walk_data *wdp = wsp->walk_data;
3007c478bd9Sstevel@tonic-gate 	MI_OP miop = &wdp->mi_wd_miodata;
3017c478bd9Sstevel@tonic-gate 	int status;
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	/* Always false in the first iteration */
3047c478bd9Sstevel@tonic-gate 	if ((wsp->walk_addr == (uintptr_t)NULL) ||
3057c478bd9Sstevel@tonic-gate 	    (wsp->walk_addr == wdp->mi_wd_miofirst)) {
3067c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) {
3107c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read MI object at %p", wsp->walk_addr);
3117c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
3127c478bd9Sstevel@tonic-gate 	}
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	/* Only true in the first iteration */
315892ad162SToomas Soome 	if (wdp->mi_wd_miofirst == 0) {
3167c478bd9Sstevel@tonic-gate 		wdp->mi_wd_miofirst = wsp->walk_addr;
317f4b3ec61Sdh155122 		status = WALK_NEXT;
318f4b3ec61Sdh155122 	} else {
319f4b3ec61Sdh155122 		status = wsp->walk_callback(wsp->walk_addr + sizeof (MI_O),
320f4b3ec61Sdh155122 		    &miop[1], wsp->walk_cbdata);
321f4b3ec61Sdh155122 	}
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)miop->mi_o_next;
3247c478bd9Sstevel@tonic-gate 	return (status);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate void
mi_walk_fini(mdb_walk_state_t * wsp)3287c478bd9Sstevel@tonic-gate mi_walk_fini(mdb_walk_state_t *wsp)
3297c478bd9Sstevel@tonic-gate {
3307c478bd9Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct mi_walk_data));
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate typedef struct mi_payload_walk_arg_s {
334f4b3ec61Sdh155122 	const char *mi_pwa_walker;	/* Underlying walker */
335f4b3ec61Sdh155122 	const off_t mi_pwa_head_off;	/* Offset for mi_o_head_t * in stack */
3367c478bd9Sstevel@tonic-gate 	const size_t mi_pwa_size;	/* size of mi payload */
3377c478bd9Sstevel@tonic-gate 	const uint_t mi_pwa_flags;	/* device and/or module */
3387c478bd9Sstevel@tonic-gate } mi_payload_walk_arg_t;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate #define	MI_PAYLOAD_DEVICE	0x1
3417c478bd9Sstevel@tonic-gate #define	MI_PAYLOAD_MODULE	0x2
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate int
mi_payload_walk_init(mdb_walk_state_t * wsp)3447c478bd9Sstevel@tonic-gate mi_payload_walk_init(mdb_walk_state_t *wsp)
3457c478bd9Sstevel@tonic-gate {
3467c478bd9Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
3477c478bd9Sstevel@tonic-gate 
348f4b3ec61Sdh155122 	if (mdb_layered_walk(arg->mi_pwa_walker, wsp) == -1) {
349f4b3ec61Sdh155122 		mdb_warn("can't walk '%s'", arg->mi_pwa_walker);
3507c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
3537c478bd9Sstevel@tonic-gate }
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate int
mi_payload_walk_step(mdb_walk_state_t * wsp)3567c478bd9Sstevel@tonic-gate mi_payload_walk_step(mdb_walk_state_t *wsp)
3577c478bd9Sstevel@tonic-gate {
3587c478bd9Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
359f4b3ec61Sdh155122 	uintptr_t kaddr;
3607c478bd9Sstevel@tonic-gate 
361f4b3ec61Sdh155122 	kaddr = wsp->walk_addr + arg->mi_pwa_head_off;
3627c478bd9Sstevel@tonic-gate 
363f4b3ec61Sdh155122 	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
364f4b3ec61Sdh155122 		mdb_warn("can't read address of mi head at %p for %s",
365f4b3ec61Sdh155122 		    kaddr, arg->mi_pwa_walker);
3667c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 
369f4b3ec61Sdh155122 	if (kaddr == 0) {
370f4b3ec61Sdh155122 		/* Empty list */
371f4b3ec61Sdh155122 		return (WALK_DONE);
3727c478bd9Sstevel@tonic-gate 	}
3737c478bd9Sstevel@tonic-gate 
374f4b3ec61Sdh155122 	if (mdb_pwalk("genunix`mi", wsp->walk_callback,
375f4b3ec61Sdh155122 	    wsp->walk_cbdata, kaddr) == -1) {
376f4b3ec61Sdh155122 		mdb_warn("failed to walk genunix`mi");
377f4b3ec61Sdh155122 		return (WALK_ERR);
378f4b3ec61Sdh155122 	}
379f4b3ec61Sdh155122 	return (WALK_NEXT);
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate const mi_payload_walk_arg_t mi_icmp_arg = {
383f4b3ec61Sdh155122 	"icmp_stacks", OFFSETOF(icmp_stack_t, is_head), sizeof (icmp_t),
3847c478bd9Sstevel@tonic-gate 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
3857c478bd9Sstevel@tonic-gate };
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate int
sonode(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3887c478bd9Sstevel@tonic-gate sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate 	const char *optf = NULL;
3917c478bd9Sstevel@tonic-gate 	const char *optt = NULL;
3927c478bd9Sstevel@tonic-gate 	const char *optp = NULL;
39324537d3eSToomas Soome 	int family = AF_UNSPEC, type = 0, proto = 0;
3947c478bd9Sstevel@tonic-gate 	int filter = 0;
3957c478bd9Sstevel@tonic-gate 	struct sonode so;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
3987c478bd9Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`sonode", "genunix`sonode", argc,
3997c478bd9Sstevel@tonic-gate 		    argv) == -1) {
4007c478bd9Sstevel@tonic-gate 			mdb_warn("failed to walk sonode");
4017c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
4027c478bd9Sstevel@tonic-gate 		}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
4087c478bd9Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &optf,
4097c478bd9Sstevel@tonic-gate 	    't', MDB_OPT_STR, &optt,
4107c478bd9Sstevel@tonic-gate 	    'p', MDB_OPT_STR, &optp,
4117c478bd9Sstevel@tonic-gate 	    NULL) != argc)
4127c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	if (optf != NULL) {
4157c478bd9Sstevel@tonic-gate 		if (strcmp("inet", optf) == 0)
4167c478bd9Sstevel@tonic-gate 			family = AF_INET;
4177c478bd9Sstevel@tonic-gate 		else if (strcmp("inet6", optf) == 0)
4187c478bd9Sstevel@tonic-gate 			family = AF_INET6;
4197c478bd9Sstevel@tonic-gate 		else if (strcmp("unix", optf) == 0)
4207c478bd9Sstevel@tonic-gate 			family = AF_UNIX;
4217c478bd9Sstevel@tonic-gate 		else
4227c478bd9Sstevel@tonic-gate 			family = mdb_strtoull(optf);
4237c478bd9Sstevel@tonic-gate 		filter = 1;
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	if (optt != NULL) {
4277c478bd9Sstevel@tonic-gate 		if (strcmp("stream", optt) == 0)
4287c478bd9Sstevel@tonic-gate 			type = SOCK_STREAM;
4297c478bd9Sstevel@tonic-gate 		else if (strcmp("dgram", optt) == 0)
4307c478bd9Sstevel@tonic-gate 			type = SOCK_DGRAM;
4317c478bd9Sstevel@tonic-gate 		else if (strcmp("raw", optt) == 0)
4327c478bd9Sstevel@tonic-gate 			type = SOCK_RAW;
4337c478bd9Sstevel@tonic-gate 		else
4347c478bd9Sstevel@tonic-gate 			type = mdb_strtoull(optt);
4357c478bd9Sstevel@tonic-gate 		filter = 1;
4367c478bd9Sstevel@tonic-gate 	}
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	if (optp != NULL) {
4397c478bd9Sstevel@tonic-gate 		proto = mdb_strtoull(optp);
4407c478bd9Sstevel@tonic-gate 		filter = 1;
4417c478bd9Sstevel@tonic-gate 	}
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !filter) {
4447c478bd9Sstevel@tonic-gate 		mdb_printf("%<u>%-?s Family Type Proto State Mode Flag "
4457c478bd9Sstevel@tonic-gate 		    "AccessVP%</u>\n", "Sonode:");
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	if (mdb_vread(&so, sizeof (so), addr) == -1) {
4497c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read sonode at %p", addr);
4507c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	if ((optf != NULL) && (so.so_family != family))
4547c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	if ((optt != NULL) && (so.so_type != type))
4577c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	if ((optp != NULL) && (so.so_protocol != proto))
4607c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	if (filter) {
4637c478bd9Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
4647c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
4657c478bd9Sstevel@tonic-gate 	}
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	mdb_printf("%0?p ", addr);
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	switch (so.so_family) {
4707c478bd9Sstevel@tonic-gate 	case AF_UNIX:
4717c478bd9Sstevel@tonic-gate 		mdb_printf("unix  ");
4727c478bd9Sstevel@tonic-gate 		break;
4737c478bd9Sstevel@tonic-gate 	case AF_INET:
4747c478bd9Sstevel@tonic-gate 		mdb_printf("inet  ");
4757c478bd9Sstevel@tonic-gate 		break;
4767c478bd9Sstevel@tonic-gate 	case AF_INET6:
4777c478bd9Sstevel@tonic-gate 		mdb_printf("inet6 ");
4787c478bd9Sstevel@tonic-gate 		break;
4797c478bd9Sstevel@tonic-gate 	default:
4807c478bd9Sstevel@tonic-gate 		mdb_printf("%6hi", so.so_family);
4817c478bd9Sstevel@tonic-gate 	}
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	switch (so.so_type) {
4847c478bd9Sstevel@tonic-gate 	case SOCK_STREAM:
4857c478bd9Sstevel@tonic-gate 		mdb_printf(" strm");
4867c478bd9Sstevel@tonic-gate 		break;
4877c478bd9Sstevel@tonic-gate 	case SOCK_DGRAM:
4887c478bd9Sstevel@tonic-gate 		mdb_printf(" dgrm");
4897c478bd9Sstevel@tonic-gate 		break;
4907c478bd9Sstevel@tonic-gate 	case SOCK_RAW:
4917c478bd9Sstevel@tonic-gate 		mdb_printf(" raw ");
4927c478bd9Sstevel@tonic-gate 		break;
4937c478bd9Sstevel@tonic-gate 	default:
4947c478bd9Sstevel@tonic-gate 		mdb_printf(" %4hi", so.so_type);
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4970f1702c5SYu Xiangning 	mdb_printf(" %5hi %05x %04x %04hx\n",
4987c478bd9Sstevel@tonic-gate 	    so.so_protocol, so.so_state, so.so_mode,
4990f1702c5SYu Xiangning 	    so.so_flag);
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate #define	MI_PAYLOAD	0x1
5057c478bd9Sstevel@tonic-gate #define	MI_DEVICE	0x2
5067c478bd9Sstevel@tonic-gate #define	MI_MODULE	0x4
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate int
mi(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)5097c478bd9Sstevel@tonic-gate mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5107c478bd9Sstevel@tonic-gate {
5117c478bd9Sstevel@tonic-gate 	uint_t opts = 0;
5127c478bd9Sstevel@tonic-gate 	MI_O	mio;
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
5157c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
5187c478bd9Sstevel@tonic-gate 	    'p', MDB_OPT_SETBITS, MI_PAYLOAD, &opts,
5197c478bd9Sstevel@tonic-gate 	    'd', MDB_OPT_SETBITS, MI_DEVICE, &opts,
5207c478bd9Sstevel@tonic-gate 	    'm', MDB_OPT_SETBITS, MI_MODULE, &opts,
5217c478bd9Sstevel@tonic-gate 	    NULL) != argc)
5227c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	if ((opts & (MI_DEVICE | MI_MODULE)) == (MI_DEVICE | MI_MODULE)) {
5257c478bd9Sstevel@tonic-gate 		mdb_warn("at most one filter, d for devices or m "
5267c478bd9Sstevel@tonic-gate 		    "for modules, may be specified\n");
5277c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	if ((opts == 0) && (DCMD_HDRSPEC(flags))) {
5317c478bd9Sstevel@tonic-gate 		mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n",
5327c478bd9Sstevel@tonic-gate 		    "MI_O", "Next", "Prev");
5337c478bd9Sstevel@tonic-gate 	}
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	if (mdb_vread(&mio, sizeof (mio), addr) == -1) {
5367c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read mi object MI_O at %p", addr);
5377c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	if (opts != 0) {
5417c478bd9Sstevel@tonic-gate 		if (mio.mi_o_isdev == B_FALSE) {
5427c478bd9Sstevel@tonic-gate 			/* mio is a module */
5437c478bd9Sstevel@tonic-gate 			if (!(opts & MI_MODULE) && (opts & MI_DEVICE))
5447c478bd9Sstevel@tonic-gate 				return (DCMD_OK);
5457c478bd9Sstevel@tonic-gate 		} else {
5467c478bd9Sstevel@tonic-gate 			/* mio is a device */
5477c478bd9Sstevel@tonic-gate 			if (!(opts & MI_DEVICE) && (opts & MI_MODULE))
5487c478bd9Sstevel@tonic-gate 				return (DCMD_OK);
5497c478bd9Sstevel@tonic-gate 		}
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 		if (opts & MI_PAYLOAD)
5527c478bd9Sstevel@tonic-gate 			mdb_printf("%p\n", addr + sizeof (MI_O));
5537c478bd9Sstevel@tonic-gate 		else
5547c478bd9Sstevel@tonic-gate 			mdb_printf("%p\n", addr);
5557c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
5567c478bd9Sstevel@tonic-gate 	}
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev);
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	if (mio.mi_o_isdev == B_FALSE)
5617c478bd9Sstevel@tonic-gate 		mdb_printf("FALSE");
5627c478bd9Sstevel@tonic-gate 	else
5637c478bd9Sstevel@tonic-gate 		mdb_printf("TRUE ");
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	mdb_printf(" %0?p\n", mio.mi_o_dev);
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate 
570f4b3ec61Sdh155122 static int
ns_to_stackid(uintptr_t kaddr)571f4b3ec61Sdh155122 ns_to_stackid(uintptr_t kaddr)
572f4b3ec61Sdh155122 {
573f4b3ec61Sdh155122 	netstack_t nss;
574f4b3ec61Sdh155122 
575f4b3ec61Sdh155122 	if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
576f4b3ec61Sdh155122 		mdb_warn("failed to read netstack_t %p", kaddr);
577f4b3ec61Sdh155122 		return (0);
578f4b3ec61Sdh155122 	}
579f4b3ec61Sdh155122 	return (nss.netstack_stackid);
580f4b3ec61Sdh155122 }
581f4b3ec61Sdh155122 
582f4b3ec61Sdh155122 
583f4b3ec61Sdh155122 
5847c478bd9Sstevel@tonic-gate static void
netstat_tcp_verbose_pr(const tcp_t * tcp)5857c478bd9Sstevel@tonic-gate netstat_tcp_verbose_pr(const tcp_t *tcp)
5867c478bd9Sstevel@tonic-gate {
5877c478bd9Sstevel@tonic-gate 	mdb_printf("       %5i %08x %08x %5i %08x %08x %5li %5i\n",
5887c478bd9Sstevel@tonic-gate 	    tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
5897c478bd9Sstevel@tonic-gate 	    tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate static int
netstat_tcp_cb(uintptr_t kaddr,const void * walk_data __unused,void * cb_data)593*50dd0783SToomas Soome netstat_tcp_cb(uintptr_t kaddr, const void *walk_data __unused, void *cb_data)
5947c478bd9Sstevel@tonic-gate {
595d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	netstat_cb_data_t *ncb = cb_data;
596d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	uint_t opts = ncb->opts;
597d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	int af = ncb->af;
5987c478bd9Sstevel@tonic-gate 	uintptr_t tcp_kaddr;
599d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	conn_t *connp = &ncb->conn;
600*50dd0783SToomas Soome 	tcp_t *tcp = &ncb->cb_proto.tcp;
6017c478bd9Sstevel@tonic-gate 
602d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
60340947d28Snordmark 		mdb_warn("failed to read conn_t at %p", kaddr);
6047c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	tcp_kaddr = (uintptr_t)connp->conn_tcp;
608*50dd0783SToomas Soome 	if (mdb_vread(tcp, sizeof (tcp_t), tcp_kaddr) == -1) {
609bd670b35SErik Nordmark 		mdb_warn("failed to read tcp_t at %p", tcp_kaddr);
61040947d28Snordmark 		return (WALK_ERR);
6117c478bd9Sstevel@tonic-gate 	}
61240947d28Snordmark 
6137c478bd9Sstevel@tonic-gate 	connp->conn_tcp = tcp;
6147c478bd9Sstevel@tonic-gate 	tcp->tcp_connp = connp;
6157c478bd9Sstevel@tonic-gate 
616ff550d0eSmasputra 	if (!((opts & NETSTAT_ALL) || net_tcp_active(tcp)) ||
6177c478bd9Sstevel@tonic-gate 	    (af == AF_INET && !net_tcp_ipv4(tcp)) ||
6187c478bd9Sstevel@tonic-gate 	    (af == AF_INET6 && !net_tcp_ipv6(tcp))) {
6197c478bd9Sstevel@tonic-gate 		return (WALK_NEXT);
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state);
6237c478bd9Sstevel@tonic-gate 	if (af == AF_INET) {
624bd670b35SErik Nordmark 		net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
6257c478bd9Sstevel@tonic-gate 		mdb_printf(" ");
626bd670b35SErik Nordmark 		net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
6277c478bd9Sstevel@tonic-gate 	} else if (af == AF_INET6) {
628bd670b35SErik Nordmark 		net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
6297c478bd9Sstevel@tonic-gate 		mdb_printf(" ");
630bd670b35SErik Nordmark 		net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
6317c478bd9Sstevel@tonic-gate 	}
632d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
6337c478bd9Sstevel@tonic-gate 	mdb_printf(" %4i\n", connp->conn_zoneid);
6347c478bd9Sstevel@tonic-gate 	if (opts & NETSTAT_VERBOSE)
6357c478bd9Sstevel@tonic-gate 		netstat_tcp_verbose_pr(tcp);
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate static int
netstat_udp_cb(uintptr_t kaddr,const void * walk_data __unused,void * cb_data)641*50dd0783SToomas Soome netstat_udp_cb(uintptr_t kaddr, const void *walk_data __unused, void *cb_data)
6427c478bd9Sstevel@tonic-gate {
643d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	netstat_cb_data_t *ncb = cb_data;
644d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	uint_t opts = ncb->opts;
645d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	int af = ncb->af;
646*50dd0783SToomas Soome 	udp_t *udp = &ncb->cb_proto.udp;
647d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	conn_t *connp = &ncb->conn;
648d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	char *state;
649e40108ffSDan McDonald 	uintptr_t udp_kaddr;
6507c478bd9Sstevel@tonic-gate 
651d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
65240947d28Snordmark 		mdb_warn("failed to read conn_t at %p", kaddr);
653ff550d0eSmasputra 		return (WALK_ERR);
654ff550d0eSmasputra 	}
655ff550d0eSmasputra 
656e40108ffSDan McDonald 	udp_kaddr = (uintptr_t)connp->conn_udp;
657*50dd0783SToomas Soome 	if (mdb_vread(udp, sizeof (udp_t), udp_kaddr) == -1) {
658e40108ffSDan McDonald 		mdb_warn("failed to read conn_udp at %p", udp_kaddr);
659ff550d0eSmasputra 		return (WALK_ERR);
660ff550d0eSmasputra 	}
661ff550d0eSmasputra 
662e40108ffSDan McDonald 	/* Need to do these reassignments for the net_udp_*() routines below. */
663*50dd0783SToomas Soome 	connp->conn_udp = udp;
664*50dd0783SToomas Soome 	udp->udp_connp = connp;
665bd670b35SErik Nordmark 
666*50dd0783SToomas Soome 	if (!((opts & NETSTAT_ALL) || net_udp_active(udp)) ||
667*50dd0783SToomas Soome 	    (af == AF_INET && !net_udp_ipv4(udp)) ||
668*50dd0783SToomas Soome 	    (af == AF_INET6 && !net_udp_ipv6(udp))) {
6697c478bd9Sstevel@tonic-gate 		return (WALK_NEXT);
670ff550d0eSmasputra 	}
6717c478bd9Sstevel@tonic-gate 
672*50dd0783SToomas Soome 	if (udp->udp_state == TS_UNBND)
673d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		state = "UNBOUND";
674*50dd0783SToomas Soome 	else if (udp->udp_state == TS_IDLE)
675d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		state = "IDLE";
676*50dd0783SToomas Soome 	else if (udp->udp_state == TS_DATA_XFER)
677d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		state = "CONNECTED";
678d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	else
679d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		state = "UNKNOWN";
680d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
681e40108ffSDan McDonald 	mdb_printf("%0?p %10s ", udp_kaddr, state);
682ff550d0eSmasputra 	if (af == AF_INET) {
683bd670b35SErik Nordmark 		net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
6847c478bd9Sstevel@tonic-gate 		mdb_printf(" ");
685bd670b35SErik Nordmark 		net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
686ff550d0eSmasputra 	} else if (af == AF_INET6) {
687bd670b35SErik Nordmark 		net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
688ff550d0eSmasputra 		mdb_printf(" ");
689bd670b35SErik Nordmark 		net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
690ff550d0eSmasputra 	}
691d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
692d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	mdb_printf(" %4i\n", connp->conn_zoneid);
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate static int
netstat_icmp_cb(uintptr_t kaddr,const void * walk_data __unused,void * cb_data)698*50dd0783SToomas Soome netstat_icmp_cb(uintptr_t kaddr, const void *walk_data __unused, void *cb_data)
699ff550d0eSmasputra {
700d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	netstat_cb_data_t *ncb = cb_data;
701d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	int af = ncb->af;
702*50dd0783SToomas Soome 	icmp_t *icmp = &ncb->cb_proto.icmp;
703d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	conn_t *connp = &ncb->conn;
704d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	char *state;
705d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
706d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
707d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		mdb_warn("failed to read conn_t at %p", kaddr);
708d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		return (WALK_ERR);
709ff550d0eSmasputra 	}
710ff550d0eSmasputra 
711*50dd0783SToomas Soome 	if (mdb_vread(icmp, sizeof (icmp_t),
712d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	    (uintptr_t)connp->conn_icmp) == -1) {
713d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		mdb_warn("failed to read conn_icmp at %p",
714d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		    (uintptr_t)connp->conn_icmp);
715d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		return (WALK_ERR);
716d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	}
717d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
718*50dd0783SToomas Soome 	connp->conn_icmp = icmp;
719*50dd0783SToomas Soome 	icmp->icmp_connp = connp;
720bd670b35SErik Nordmark 
721bd670b35SErik Nordmark 	if ((af == AF_INET && connp->conn_ipversion != IPV4_VERSION) ||
722bd670b35SErik Nordmark 	    (af == AF_INET6 && connp->conn_ipversion != IPV6_VERSION)) {
723d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		return (WALK_NEXT);
724d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	}
725d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
726*50dd0783SToomas Soome 	if (icmp->icmp_state == TS_UNBND)
727d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		state = "UNBOUND";
728*50dd0783SToomas Soome 	else if (icmp->icmp_state == TS_IDLE)
729d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		state = "IDLE";
730*50dd0783SToomas Soome 	else if (icmp->icmp_state == TS_DATA_XFER)
731d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		state = "CONNECTED";
732d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	else
733d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		state = "UNKNOWN";
734d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
735d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_icmp, state);
736d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if (af == AF_INET) {
737bd670b35SErik Nordmark 		net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
738bd670b35SErik Nordmark 		mdb_printf(" ");
739bd670b35SErik Nordmark 		net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
740d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	} else if (af == AF_INET6) {
741bd670b35SErik Nordmark 		net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
742bd670b35SErik Nordmark 		mdb_printf(" ");
743bd670b35SErik Nordmark 		net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
744d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	}
745d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
746bd670b35SErik Nordmark 	mdb_printf(" %4i\n", connp->conn_zoneid);
747d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
748d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	return (WALK_NEXT);
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate /*
7527c478bd9Sstevel@tonic-gate  * print the address of a unix domain socket
7537c478bd9Sstevel@tonic-gate  *
7547c478bd9Sstevel@tonic-gate  * so is the address of a AF_UNIX struct sonode in mdb's address space
7557c478bd9Sstevel@tonic-gate  * soa is the address of the struct soaddr to print
7567c478bd9Sstevel@tonic-gate  *
7577c478bd9Sstevel@tonic-gate  * returns 0 on success, -1 otherwise
7587c478bd9Sstevel@tonic-gate  */
7597c478bd9Sstevel@tonic-gate static int
netstat_unix_name_pr(const struct sotpi_sonode * st,const struct soaddr * soa)7600f1702c5SYu Xiangning netstat_unix_name_pr(const struct sotpi_sonode *st, const struct soaddr *soa)
7617c478bd9Sstevel@tonic-gate {
7620f1702c5SYu Xiangning 	const struct sonode *so = &st->st_sonode;
7637c478bd9Sstevel@tonic-gate 	const char none[] = " (none)";
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) {
7660f1702c5SYu Xiangning 		if (st->st_info.sti_faddr_noxlate) {
7677c478bd9Sstevel@tonic-gate 			mdb_printf("%-14s ", " (socketpair)");
7687c478bd9Sstevel@tonic-gate 		} else {
7697c478bd9Sstevel@tonic-gate 			if (soa->soa_len > sizeof (sa_family_t)) {
7707c478bd9Sstevel@tonic-gate 				char addr[MAXPATHLEN + 1];
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 				if (mdb_readstr(addr, sizeof (addr),
7737c478bd9Sstevel@tonic-gate 				    (uintptr_t)&soa->soa_sa->sa_data) == -1) {
7747c478bd9Sstevel@tonic-gate 					mdb_warn("failed to read unix address "
7757c478bd9Sstevel@tonic-gate 					    "at %p", &soa->soa_sa->sa_data);
7767c478bd9Sstevel@tonic-gate 					return (-1);
7777c478bd9Sstevel@tonic-gate 				}
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 				mdb_printf("%-14s ", addr);
7807c478bd9Sstevel@tonic-gate 			} else {
7817c478bd9Sstevel@tonic-gate 				mdb_printf("%-14s ", none);
7827c478bd9Sstevel@tonic-gate 			}
7837c478bd9Sstevel@tonic-gate 		}
7847c478bd9Sstevel@tonic-gate 	} else {
7857c478bd9Sstevel@tonic-gate 		mdb_printf("%-14s ", none);
7867c478bd9Sstevel@tonic-gate 	}
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	return (0);
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate /* based on sockfs_snapshot */
7927c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7937c478bd9Sstevel@tonic-gate static int
netstat_unix_cb(uintptr_t kaddr,const void * walk_data,void * cb_data)7947c478bd9Sstevel@tonic-gate netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
7957c478bd9Sstevel@tonic-gate {
7960f1702c5SYu Xiangning 	const struct sotpi_sonode *st = walk_data;
7970f1702c5SYu Xiangning 	const struct sonode *so = &st->st_sonode;
7980f1702c5SYu Xiangning 	const struct sotpi_info *sti = &st->st_info;
7997c478bd9Sstevel@tonic-gate 
8000f1702c5SYu Xiangning 	if (so->so_count == 0)
8017c478bd9Sstevel@tonic-gate 		return (WALK_NEXT);
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	if (so->so_family != AF_UNIX) {
8047c478bd9Sstevel@tonic-gate 		mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr);
8057c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	mdb_printf("%-?p ", kaddr);
8097c478bd9Sstevel@tonic-gate 
8100f1702c5SYu Xiangning 	switch (sti->sti_serv_type) {
8117c478bd9Sstevel@tonic-gate 	case T_CLTS:
8127c478bd9Sstevel@tonic-gate 		mdb_printf("%-10s ", "dgram");
8137c478bd9Sstevel@tonic-gate 		break;
8147c478bd9Sstevel@tonic-gate 	case T_COTS:
8157c478bd9Sstevel@tonic-gate 		mdb_printf("%-10s ", "stream");
8167c478bd9Sstevel@tonic-gate 		break;
8177c478bd9Sstevel@tonic-gate 	case T_COTS_ORD:
8187c478bd9Sstevel@tonic-gate 		mdb_printf("%-10s ", "stream-ord");
8197c478bd9Sstevel@tonic-gate 		break;
8207c478bd9Sstevel@tonic-gate 	default:
8210f1702c5SYu Xiangning 		mdb_printf("%-10i ", sti->sti_serv_type);
8227c478bd9Sstevel@tonic-gate 	}
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	if ((so->so_state & SS_ISBOUND) &&
8250f1702c5SYu Xiangning 	    (sti->sti_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
8260f1702c5SYu Xiangning 		mdb_printf("%0?p ", sti->sti_ux_laddr.soua_vp);
8277c478bd9Sstevel@tonic-gate 	} else {
8287c478bd9Sstevel@tonic-gate 		mdb_printf("%0?p ", NULL);
8297c478bd9Sstevel@tonic-gate 	}
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	if ((so->so_state & SS_ISCONNECTED) &&
8320f1702c5SYu Xiangning 	    (sti->sti_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
8330f1702c5SYu Xiangning 		mdb_printf("%0?p ", sti->sti_ux_faddr.soua_vp);
8347c478bd9Sstevel@tonic-gate 	} else {
8357c478bd9Sstevel@tonic-gate 		mdb_printf("%0?p ", NULL);
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 
8380f1702c5SYu Xiangning 	if (netstat_unix_name_pr(st, &sti->sti_laddr) == -1)
8397c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
8407c478bd9Sstevel@tonic-gate 
8410f1702c5SYu Xiangning 	if (netstat_unix_name_pr(st, &sti->sti_faddr) == -1)
8427c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	mdb_printf("%4i\n", so->so_zoneid);
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate static void
netstat_tcp_verbose_header_pr(void)8507c478bd9Sstevel@tonic-gate netstat_tcp_verbose_header_pr(void)
8517c478bd9Sstevel@tonic-gate {
8527c478bd9Sstevel@tonic-gate 	mdb_printf("       %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n",
8537c478bd9Sstevel@tonic-gate 	    "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss");
8547c478bd9Sstevel@tonic-gate }
8557c478bd9Sstevel@tonic-gate 
85645916cd2Sjpk static void
get_ifname(const ire_t * ire,char * intf)85745916cd2Sjpk get_ifname(const ire_t *ire, char *intf)
85845916cd2Sjpk {
85945916cd2Sjpk 	ill_t ill;
86045916cd2Sjpk 
86145916cd2Sjpk 	*intf = '\0';
862bd670b35SErik Nordmark 	if (ire->ire_ill != NULL) {
863bd670b35SErik Nordmark 		if (mdb_vread(&ill, sizeof (ill),
864bd670b35SErik Nordmark 		    (uintptr_t)ire->ire_ill) == -1)
86545916cd2Sjpk 			return;
86645916cd2Sjpk 		(void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
86745916cd2Sjpk 		    (uintptr_t)ill.ill_name);
868bd670b35SErik Nordmark 	}
869bd670b35SErik Nordmark }
87045916cd2Sjpk 
871bd670b35SErik Nordmark const in6_addr_t ipv6_all_ones =
872bd670b35SErik Nordmark 	{ 0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU };
87345916cd2Sjpk 
87445916cd2Sjpk static void
get_ireflags(const ire_t * ire,char * flags)875bd670b35SErik Nordmark get_ireflags(const ire_t *ire, char *flags)
87645916cd2Sjpk {
87745916cd2Sjpk 	(void) strcpy(flags, "U");
878bd670b35SErik Nordmark 	/* RTF_INDIRECT wins over RTF_GATEWAY - don't display both */
879bd670b35SErik Nordmark 	if (ire->ire_flags & RTF_INDIRECT)
880bd670b35SErik Nordmark 		(void) strcat(flags, "I");
881bd670b35SErik Nordmark 	else if (ire->ire_type & IRE_OFFLINK)
88245916cd2Sjpk 		(void) strcat(flags, "G");
883bd670b35SErik Nordmark 
884bd670b35SErik Nordmark 	/* IRE_IF_CLONE wins over RTF_HOST - don't display both */
885bd670b35SErik Nordmark 	if (ire->ire_type & IRE_IF_CLONE)
886bd670b35SErik Nordmark 		(void) strcat(flags, "C");
887bd670b35SErik Nordmark 	else if (ire->ire_ipversion == IPV4_VERSION) {
88845916cd2Sjpk 		if (ire->ire_mask == IP_HOST_MASK)
88945916cd2Sjpk 			(void) strcat(flags, "H");
890bd670b35SErik Nordmark 	} else {
891bd670b35SErik Nordmark 		if (IN6_ARE_ADDR_EQUAL(&ire->ire_mask_v6, &ipv6_all_ones))
892bd670b35SErik Nordmark 			(void) strcat(flags, "H");
893bd670b35SErik Nordmark 	}
894bd670b35SErik Nordmark 
895bd670b35SErik Nordmark 	if (ire->ire_flags & RTF_DYNAMIC)
89645916cd2Sjpk 		(void) strcat(flags, "D");
89745916cd2Sjpk 	if (ire->ire_type == IRE_BROADCAST)
898bd670b35SErik Nordmark 		(void) strcat(flags, "b");
899bd670b35SErik Nordmark 	if (ire->ire_type == IRE_MULTICAST)
900bd670b35SErik Nordmark 		(void) strcat(flags, "m");
90145916cd2Sjpk 	if (ire->ire_type == IRE_LOCAL)
90245916cd2Sjpk 		(void) strcat(flags, "L");
903bd670b35SErik Nordmark 	if (ire->ire_type == IRE_NOROUTE)
904bd670b35SErik Nordmark 		(void) strcat(flags, "N");
90545916cd2Sjpk 	if (ire->ire_flags & RTF_MULTIRT)
90645916cd2Sjpk 		(void) strcat(flags, "M");
90745916cd2Sjpk 	if (ire->ire_flags & RTF_SETSRC)
90845916cd2Sjpk 		(void) strcat(flags, "S");
909bd670b35SErik Nordmark 	if (ire->ire_flags & RTF_REJECT)
910bd670b35SErik Nordmark 		(void) strcat(flags, "R");
911bd670b35SErik Nordmark 	if (ire->ire_flags & RTF_BLACKHOLE)
912bd670b35SErik Nordmark 		(void) strcat(flags, "B");
91345916cd2Sjpk }
91445916cd2Sjpk 
91545916cd2Sjpk static int
netstat_irev4_cb(uintptr_t kaddr,const void * walk_data,void * cb_data)91645916cd2Sjpk netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
91745916cd2Sjpk {
91845916cd2Sjpk 	const ire_t *ire = walk_data;
91945916cd2Sjpk 	uint_t *opts = cb_data;
92045916cd2Sjpk 	ipaddr_t gate;
92145916cd2Sjpk 	char flags[10], intf[LIFNAMSIZ + 1];
92245916cd2Sjpk 
9235c0b7edeSseb 	if (ire->ire_ipversion != IPV4_VERSION)
92445916cd2Sjpk 		return (WALK_NEXT);
92545916cd2Sjpk 
926bd670b35SErik Nordmark 	/* Skip certain IREs by default */
927bd670b35SErik Nordmark 	if (!(*opts & NETSTAT_ALL) &&
928bd670b35SErik Nordmark 	    (ire->ire_type &
929bd670b35SErik Nordmark 	    (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE)))
93045916cd2Sjpk 		return (WALK_NEXT);
93145916cd2Sjpk 
93245916cd2Sjpk 	if (*opts & NETSTAT_FIRST) {
93345916cd2Sjpk 		*opts &= ~NETSTAT_FIRST;
93445916cd2Sjpk 		mdb_printf("%<u>%s Table: IPv4%</u>\n",
93545916cd2Sjpk 		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
93645916cd2Sjpk 		if (*opts & NETSTAT_VERBOSE) {
93745916cd2Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt  "
93845916cd2Sjpk 			    " Ref Flg Out   In/Fwd%</u>\n",
93945916cd2Sjpk 			    "Address", ADDR_V4_WIDTH, "Destination",
94045916cd2Sjpk 			    ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway");
94145916cd2Sjpk 		} else {
94245916cd2Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref  Use   "
94345916cd2Sjpk 			    "Interface%</u>\n",
94445916cd2Sjpk 			    "Address", ADDR_V4_WIDTH, "Destination",
94545916cd2Sjpk 			    ADDR_V4_WIDTH, "Gateway");
94645916cd2Sjpk 		}
94745916cd2Sjpk 	}
94845916cd2Sjpk 
949bd670b35SErik Nordmark 	gate = ire->ire_gateway_addr;
95045916cd2Sjpk 
951bd670b35SErik Nordmark 	get_ireflags(ire, flags);
95245916cd2Sjpk 
95345916cd2Sjpk 	get_ifname(ire, intf);
95445916cd2Sjpk 
95545916cd2Sjpk 	if (*opts & NETSTAT_VERBOSE) {
95645916cd2Sjpk 		mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u "
95745916cd2Sjpk 		    "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH,
95845916cd2Sjpk 		    ire->ire_mask, ADDR_V4_WIDTH, gate, intf,
959bd670b35SErik Nordmark 		    0, ' ',
960bd670b35SErik Nordmark 		    ire->ire_metrics.iulp_rtt, ire->ire_refcnt, flags,
96145916cd2Sjpk 		    ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
96245916cd2Sjpk 	} else {
96345916cd2Sjpk 		mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr,
96445916cd2Sjpk 		    ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags,
96545916cd2Sjpk 		    ire->ire_refcnt,
96645916cd2Sjpk 		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
96745916cd2Sjpk 	}
96845916cd2Sjpk 
96945916cd2Sjpk 	return (WALK_NEXT);
97045916cd2Sjpk }
97145916cd2Sjpk 
97245916cd2Sjpk int
ip_mask_to_plen_v6(const in6_addr_t * v6mask)97345916cd2Sjpk ip_mask_to_plen_v6(const in6_addr_t *v6mask)
97445916cd2Sjpk {
97545916cd2Sjpk 	int plen;
97645916cd2Sjpk 	int i;
97745916cd2Sjpk 	uint32_t val;
97845916cd2Sjpk 
97945916cd2Sjpk 	for (i = 3; i >= 0; i--)
98045916cd2Sjpk 		if (v6mask->s6_addr32[i] != 0)
98145916cd2Sjpk 			break;
98245916cd2Sjpk 	if (i < 0)
98345916cd2Sjpk 		return (0);
98445916cd2Sjpk 	plen = 32 + 32 * i;
98545916cd2Sjpk 	val = v6mask->s6_addr32[i];
98645916cd2Sjpk 	while (!(val & 1)) {
98745916cd2Sjpk 		val >>= 1;
98845916cd2Sjpk 		plen--;
98945916cd2Sjpk 	}
99045916cd2Sjpk 
99145916cd2Sjpk 	return (plen);
99245916cd2Sjpk }
99345916cd2Sjpk 
99445916cd2Sjpk static int
netstat_irev6_cb(uintptr_t kaddr,const void * walk_data,void * cb_data)99545916cd2Sjpk netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
99645916cd2Sjpk {
99745916cd2Sjpk 	const ire_t *ire = walk_data;
99845916cd2Sjpk 	uint_t *opts = cb_data;
99945916cd2Sjpk 	const in6_addr_t *gatep;
100045916cd2Sjpk 	char deststr[ADDR_V6_WIDTH + 5];
100145916cd2Sjpk 	char flags[10], intf[LIFNAMSIZ + 1];
100245916cd2Sjpk 	int masklen;
100345916cd2Sjpk 
100445916cd2Sjpk 	if (ire->ire_ipversion != IPV6_VERSION)
100545916cd2Sjpk 		return (WALK_NEXT);
100645916cd2Sjpk 
1007bd670b35SErik Nordmark 	/* Skip certain IREs by default */
1008bd670b35SErik Nordmark 	if (!(*opts & NETSTAT_ALL) &&
1009bd670b35SErik Nordmark 	    (ire->ire_type &
1010bd670b35SErik Nordmark 	    (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE)))
101145916cd2Sjpk 		return (WALK_NEXT);
101245916cd2Sjpk 
101345916cd2Sjpk 	if (*opts & NETSTAT_FIRST) {
101445916cd2Sjpk 		*opts &= ~NETSTAT_FIRST;
101545916cd2Sjpk 		mdb_printf("\n%<u>%s Table: IPv6%</u>\n",
101645916cd2Sjpk 		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
101745916cd2Sjpk 		if (*opts & NETSTAT_VERBOSE) {
101845916cd2Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s If    PMTU   Rtt   Ref "
101945916cd2Sjpk 			    "Flags Out    In/Fwd%</u>\n",
102045916cd2Sjpk 			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
102145916cd2Sjpk 			    ADDR_V6_WIDTH, "Gateway");
102245916cd2Sjpk 		} else {
102345916cd2Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use    If"
102445916cd2Sjpk 			    "%</u>\n",
102545916cd2Sjpk 			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
102645916cd2Sjpk 			    ADDR_V6_WIDTH, "Gateway");
102745916cd2Sjpk 		}
102845916cd2Sjpk 	}
102945916cd2Sjpk 
1030bd670b35SErik Nordmark 	gatep = &ire->ire_gateway_addr_v6;
103145916cd2Sjpk 
103245916cd2Sjpk 	masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6);
103345916cd2Sjpk 	(void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d",
103445916cd2Sjpk 	    &ire->ire_addr_v6, masklen);
103545916cd2Sjpk 
1036bd670b35SErik Nordmark 	get_ireflags(ire, flags);
103745916cd2Sjpk 
103845916cd2Sjpk 	get_ifname(ire, intf);
103945916cd2Sjpk 
104045916cd2Sjpk 	if (*opts & NETSTAT_VERBOSE) {
104145916cd2Sjpk 		mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n",
104245916cd2Sjpk 		    kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep,
1043bd670b35SErik Nordmark 		    intf, 0, ' ',
1044bd670b35SErik Nordmark 		    ire->ire_metrics.iulp_rtt, ire->ire_refcnt,
104545916cd2Sjpk 		    flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
104645916cd2Sjpk 	} else {
104745916cd2Sjpk 		mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr,
104845916cd2Sjpk 		    ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags,
104945916cd2Sjpk 		    ire->ire_refcnt,
105045916cd2Sjpk 		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
105145916cd2Sjpk 	}
105245916cd2Sjpk 
105345916cd2Sjpk 	return (WALK_NEXT);
105445916cd2Sjpk }
105545916cd2Sjpk 
1056d5b6ed4bSVasumathi Sundaram - Sun Microsystems static void
netstat_header_v4(int proto)1057d5b6ed4bSVasumathi Sundaram - Sun Microsystems netstat_header_v4(int proto)
1058d5b6ed4bSVasumathi Sundaram - Sun Microsystems {
1059d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if (proto == IPPROTO_TCP)
1060d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		mdb_printf("%<u>%-?s ", "TCPv4");
1061d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	else if (proto == IPPROTO_UDP)
1062d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		mdb_printf("%<u>%-?s ", "UDPv4");
1063d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	else if (proto == IPPROTO_ICMP)
1064d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		mdb_printf("%<u>%-?s ", "ICMPv4");
1065d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
1066d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	    "", ADDR_V4_WIDTH, "Local Address",
1067d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	    "", ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone");
1068d5b6ed4bSVasumathi Sundaram - Sun Microsystems }
1069d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
1070d5b6ed4bSVasumathi Sundaram - Sun Microsystems static void
netstat_header_v6(int proto)1071d5b6ed4bSVasumathi Sundaram - Sun Microsystems netstat_header_v6(int proto)
1072d5b6ed4bSVasumathi Sundaram - Sun Microsystems {
1073d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if (proto == IPPROTO_TCP)
1074d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		mdb_printf("%<u>%-?s ", "TCPv6");
1075d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	else if (proto == IPPROTO_UDP)
1076d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		mdb_printf("%<u>%-?s ", "UDPv6");
1077d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	else if (proto == IPPROTO_ICMP)
1078d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		mdb_printf("%<u>%-?s ", "ICMPv6");
1079d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
1080d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	    "", ADDR_V6_WIDTH, "Local Address",
1081d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	    "", ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone");
1082d5b6ed4bSVasumathi Sundaram - Sun Microsystems }
1083d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
1084d5b6ed4bSVasumathi Sundaram - Sun Microsystems static int
netstat_print_conn(const char * cache,int proto,mdb_walk_cb_t cbfunc,void * cbdata)1085d5b6ed4bSVasumathi Sundaram - Sun Microsystems netstat_print_conn(const char *cache, int proto, mdb_walk_cb_t cbfunc,
1086d5b6ed4bSVasumathi Sundaram - Sun Microsystems     void *cbdata)
1087d5b6ed4bSVasumathi Sundaram - Sun Microsystems {
1088d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	netstat_cb_data_t *ncb = cbdata;
1089d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
1090d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if ((ncb->opts & NETSTAT_VERBOSE) && proto == IPPROTO_TCP)
1091d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		netstat_tcp_verbose_header_pr();
1092d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if (mdb_walk(cache, cbfunc, cbdata) == -1) {
1093d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		mdb_warn("failed to walk %s", cache);
1094d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		return (DCMD_ERR);
1095d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	}
1096d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	return (DCMD_OK);
1097d5b6ed4bSVasumathi Sundaram - Sun Microsystems }
1098d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
1099d5b6ed4bSVasumathi Sundaram - Sun Microsystems static int
netstat_print_common(const char * cache,int proto,mdb_walk_cb_t cbfunc,void * cbdata)1100d5b6ed4bSVasumathi Sundaram - Sun Microsystems netstat_print_common(const char *cache, int proto, mdb_walk_cb_t cbfunc,
1101d5b6ed4bSVasumathi Sundaram - Sun Microsystems     void *cbdata)
1102d5b6ed4bSVasumathi Sundaram - Sun Microsystems {
1103d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	netstat_cb_data_t *ncb = cbdata;
1104d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	int af = ncb->af;
1105d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	int status = DCMD_OK;
1106d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
1107d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if (af != AF_INET6) {
1108d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		ncb->af = AF_INET;
1109d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		netstat_header_v4(proto);
1110d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		status = netstat_print_conn(cache, proto, cbfunc, cbdata);
1111d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	}
1112d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if (status == DCMD_OK && af != AF_INET) {
1113d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		ncb->af = AF_INET6;
1114d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		netstat_header_v6(proto);
1115d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		status = netstat_print_conn(cache, proto, cbfunc, cbdata);
1116d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	}
1117d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	ncb->af = af;
1118d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	return (status);
1119d5b6ed4bSVasumathi Sundaram - Sun Microsystems }
1120d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
11217c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11227c478bd9Sstevel@tonic-gate int
netstat(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)11237c478bd9Sstevel@tonic-gate netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
11247c478bd9Sstevel@tonic-gate {
11257c478bd9Sstevel@tonic-gate 	uint_t opts = 0;
11267c478bd9Sstevel@tonic-gate 	const char *optf = NULL;
11277c478bd9Sstevel@tonic-gate 	const char *optP = NULL;
1128d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	netstat_cb_data_t *cbdata;
1129d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	int status;
1130d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	int af = 0;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
11337c478bd9Sstevel@tonic-gate 	    'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts,
11347c478bd9Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &optf,
11357c478bd9Sstevel@tonic-gate 	    'P', MDB_OPT_STR, &optP,
113645916cd2Sjpk 	    'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts,
113745916cd2Sjpk 	    'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts,
11387c478bd9Sstevel@tonic-gate 	    NULL) != argc)
11397c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 	if (optP != NULL) {
1142d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0) &&
1143d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		    (strcmp("icmp", optP) != 0))
11447c478bd9Sstevel@tonic-gate 			return (DCMD_USAGE);
114545916cd2Sjpk 		if (opts & NETSTAT_ROUTE)
114645916cd2Sjpk 			return (DCMD_USAGE);
11477c478bd9Sstevel@tonic-gate 	}
11487c478bd9Sstevel@tonic-gate 
114945916cd2Sjpk 	if (optf == NULL)
115045916cd2Sjpk 		opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX;
115145916cd2Sjpk 	else if (strcmp("inet", optf) == 0)
115245916cd2Sjpk 		opts |= NETSTAT_V4;
115345916cd2Sjpk 	else if (strcmp("inet6", optf) == 0)
115445916cd2Sjpk 		opts |= NETSTAT_V6;
115545916cd2Sjpk 	else if (strcmp("unix", optf) == 0)
115645916cd2Sjpk 		opts |= NETSTAT_UNIX;
115745916cd2Sjpk 	else
11587c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
115945916cd2Sjpk 
116045916cd2Sjpk 	if (opts & NETSTAT_ROUTE) {
116145916cd2Sjpk 		if (!(opts & (NETSTAT_V4|NETSTAT_V6)))
116245916cd2Sjpk 			return (DCMD_USAGE);
116345916cd2Sjpk 		if (opts & NETSTAT_V4) {
116445916cd2Sjpk 			opts |= NETSTAT_FIRST;
116545916cd2Sjpk 			if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) {
116645916cd2Sjpk 				mdb_warn("failed to walk ip`ire");
116745916cd2Sjpk 				return (DCMD_ERR);
116845916cd2Sjpk 			}
116945916cd2Sjpk 		}
117045916cd2Sjpk 		if (opts & NETSTAT_V6) {
117145916cd2Sjpk 			opts |= NETSTAT_FIRST;
117245916cd2Sjpk 			if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) {
117345916cd2Sjpk 				mdb_warn("failed to walk ip`ire");
117445916cd2Sjpk 				return (DCMD_ERR);
117545916cd2Sjpk 			}
117645916cd2Sjpk 		}
117745916cd2Sjpk 		return (DCMD_OK);
11787c478bd9Sstevel@tonic-gate 	}
11797c478bd9Sstevel@tonic-gate 
1180d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if ((opts & NETSTAT_UNIX) && (optP == NULL)) {
11817c478bd9Sstevel@tonic-gate 		/* Print Unix Domain Sockets */
11827c478bd9Sstevel@tonic-gate 		mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n",
11837c478bd9Sstevel@tonic-gate 		    "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr",
11847c478bd9Sstevel@tonic-gate 		    "Remote Addr", "Zone");
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 		if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) {
11877c478bd9Sstevel@tonic-gate 			mdb_warn("failed to walk genunix`sonode");
11887c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
11897c478bd9Sstevel@tonic-gate 		}
1190d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		if (!(opts & (NETSTAT_V4 | NETSTAT_V6)))
1191d5b6ed4bSVasumathi Sundaram - Sun Microsystems 			return (DCMD_OK);
11927c478bd9Sstevel@tonic-gate 	}
11937c478bd9Sstevel@tonic-gate 
1194d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	cbdata = mdb_alloc(sizeof (netstat_cb_data_t), UM_SLEEP);
1195d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	cbdata->opts = opts;
1196d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if ((optf != NULL) && (opts & NETSTAT_V4))
1197d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		af = AF_INET;
1198d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	else if ((optf != NULL) && (opts & NETSTAT_V6))
1199d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		af = AF_INET6;
1200d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
1201d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	cbdata->af = af;
1202d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
1203d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		status = netstat_print_common("tcp_conn_cache", IPPROTO_TCP,
1204d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		    netstat_tcp_cb, cbdata);
1205d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		if (status != DCMD_OK)
1206d5b6ed4bSVasumathi Sundaram - Sun Microsystems 			goto out;
1207d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	}
1208d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
1209d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
1210d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		status = netstat_print_common("udp_conn_cache", IPPROTO_UDP,
1211d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		    netstat_udp_cb, cbdata);
1212d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		if (status != DCMD_OK)
1213d5b6ed4bSVasumathi Sundaram - Sun Microsystems 			goto out;
1214d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	}
1215d5b6ed4bSVasumathi Sundaram - Sun Microsystems 
1216d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	if ((optP == NULL) || (strcmp("icmp", optP) == 0)) {
1217d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		status = netstat_print_common("rawip_conn_cache", IPPROTO_ICMP,
1218d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		    netstat_icmp_cb, cbdata);
1219d5b6ed4bSVasumathi Sundaram - Sun Microsystems 		if (status != DCMD_OK)
1220d5b6ed4bSVasumathi Sundaram - Sun Microsystems 			goto out;
1221d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	}
1222d5b6ed4bSVasumathi Sundaram - Sun Microsystems out:
1223d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	mdb_free(cbdata, sizeof (netstat_cb_data_t));
1224d5b6ed4bSVasumathi Sundaram - Sun Microsystems 	return (status);
12257c478bd9Sstevel@tonic-gate }
12264eaa4710SRishi Srivatsavai 
12274eaa4710SRishi Srivatsavai /*
12284eaa4710SRishi Srivatsavai  * "::dladm show-bridge" support
12294eaa4710SRishi Srivatsavai  */
12304eaa4710SRishi Srivatsavai typedef struct {
12314eaa4710SRishi Srivatsavai 	uint_t opt_l;
12324eaa4710SRishi Srivatsavai 	uint_t opt_f;
12334eaa4710SRishi Srivatsavai 	uint_t opt_t;
12344eaa4710SRishi Srivatsavai 	const char *name;
12354eaa4710SRishi Srivatsavai 	clock_t lbolt;
12364eaa4710SRishi Srivatsavai 	boolean_t found;
12374eaa4710SRishi Srivatsavai 	uint_t nlinks;
12384eaa4710SRishi Srivatsavai 	uint_t nfwd;
12394eaa4710SRishi Srivatsavai 
12404eaa4710SRishi Srivatsavai 	/*
12414eaa4710SRishi Srivatsavai 	 * These structures are kept inside the 'args' for allocation reasons.
12424eaa4710SRishi Srivatsavai 	 * They're all large data structures (over 1K), and may cause the stack
12434eaa4710SRishi Srivatsavai 	 * to explode.  mdb and kmdb will fail in these cases, and thus we
12444eaa4710SRishi Srivatsavai 	 * allocate them from the heap.
12454eaa4710SRishi Srivatsavai 	 */
12464eaa4710SRishi Srivatsavai 	trill_inst_t ti;
12474eaa4710SRishi Srivatsavai 	bridge_link_t bl;
12484eaa4710SRishi Srivatsavai 	mac_impl_t mi;
12494eaa4710SRishi Srivatsavai } show_bridge_args_t;
12504eaa4710SRishi Srivatsavai 
12514eaa4710SRishi Srivatsavai static void
show_vlans(const uint8_t * vlans)12524eaa4710SRishi Srivatsavai show_vlans(const uint8_t *vlans)
12534eaa4710SRishi Srivatsavai {
12544eaa4710SRishi Srivatsavai 	int i, bit;
12554eaa4710SRishi Srivatsavai 	uint8_t val;
12564eaa4710SRishi Srivatsavai 	int rstart = -1, rnext = -1;
12574eaa4710SRishi Srivatsavai 
12584eaa4710SRishi Srivatsavai 	for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) {
12594eaa4710SRishi Srivatsavai 		val = vlans[i];
12604eaa4710SRishi Srivatsavai 		if (i == 0)
12614eaa4710SRishi Srivatsavai 			val &= ~1;
12624eaa4710SRishi Srivatsavai 		while ((bit = mdb_ffs(val)) != 0) {
12634eaa4710SRishi Srivatsavai 			bit--;
12644eaa4710SRishi Srivatsavai 			val &= ~(1 << bit);
12654eaa4710SRishi Srivatsavai 			bit += i * sizeof (*vlans) * NBBY;
12664eaa4710SRishi Srivatsavai 			if (bit != rnext) {
12674eaa4710SRishi Srivatsavai 				if (rnext != -1 && rstart + 1 != rnext)
12684eaa4710SRishi Srivatsavai 					mdb_printf("-%d", rnext - 1);
12694eaa4710SRishi Srivatsavai 				if (rstart != -1)
12704eaa4710SRishi Srivatsavai 					mdb_printf(",");
12714eaa4710SRishi Srivatsavai 				mdb_printf("%d", bit);
12724eaa4710SRishi Srivatsavai 				rstart = bit;
12734eaa4710SRishi Srivatsavai 			}
12744eaa4710SRishi Srivatsavai 			rnext = bit + 1;
12754eaa4710SRishi Srivatsavai 		}
12764eaa4710SRishi Srivatsavai 	}
12774eaa4710SRishi Srivatsavai 	if (rnext != -1 && rstart + 1 != rnext)
12784eaa4710SRishi Srivatsavai 		mdb_printf("-%d", rnext - 1);
12794eaa4710SRishi Srivatsavai 	mdb_printf("\n");
12804eaa4710SRishi Srivatsavai }
12814eaa4710SRishi Srivatsavai 
12824eaa4710SRishi Srivatsavai /*
12834eaa4710SRishi Srivatsavai  * This callback is invoked by a walk of the links attached to a bridge.  If
12844eaa4710SRishi Srivatsavai  * we're showing link details, then they're printed here.  If not, then we just
12854eaa4710SRishi Srivatsavai  * count up the links for the bridge summary.
12864eaa4710SRishi Srivatsavai  */
12874eaa4710SRishi Srivatsavai static int
do_bridge_links(uintptr_t addr,const void * data,void * ptr)12884eaa4710SRishi Srivatsavai do_bridge_links(uintptr_t addr, const void *data, void *ptr)
12894eaa4710SRishi Srivatsavai {
12904eaa4710SRishi Srivatsavai 	show_bridge_args_t *args = ptr;
12914eaa4710SRishi Srivatsavai 	const bridge_link_t *blp = data;
12924eaa4710SRishi Srivatsavai 	char macaddr[ETHERADDRL * 3];
12934eaa4710SRishi Srivatsavai 	const char *name;
12944eaa4710SRishi Srivatsavai 
12954eaa4710SRishi Srivatsavai 	args->nlinks++;
12964eaa4710SRishi Srivatsavai 
12974eaa4710SRishi Srivatsavai 	if (!args->opt_l)
12984eaa4710SRishi Srivatsavai 		return (WALK_NEXT);
12994eaa4710SRishi Srivatsavai 
13004eaa4710SRishi Srivatsavai 	if (mdb_vread(&args->mi, sizeof (args->mi),
13014eaa4710SRishi Srivatsavai 	    (uintptr_t)blp->bl_mh) == -1) {
13024eaa4710SRishi Srivatsavai 		mdb_warn("cannot read mac data at %p", blp->bl_mh);
13034eaa4710SRishi Srivatsavai 		name = "?";
13044eaa4710SRishi Srivatsavai 	} else  {
13054eaa4710SRishi Srivatsavai 		name = args->mi.mi_name;
13064eaa4710SRishi Srivatsavai 	}
13074eaa4710SRishi Srivatsavai 
13084eaa4710SRishi Srivatsavai 	mdb_mac_addr(blp->bl_local_mac, ETHERADDRL, macaddr,
13094eaa4710SRishi Srivatsavai 	    sizeof (macaddr));
13104eaa4710SRishi Srivatsavai 
13114eaa4710SRishi Srivatsavai 	mdb_printf("%-?p %-16s %-17s %03X %-4d ", addr, name, macaddr,
13124eaa4710SRishi Srivatsavai 	    blp->bl_flags, blp->bl_pvid);
13134eaa4710SRishi Srivatsavai 
13144eaa4710SRishi Srivatsavai 	if (blp->bl_trilldata == NULL) {
13154eaa4710SRishi Srivatsavai 		switch (blp->bl_state) {
13164eaa4710SRishi Srivatsavai 		case BLS_BLOCKLISTEN:
13174eaa4710SRishi Srivatsavai 			name = "BLOCK";
13184eaa4710SRishi Srivatsavai 			break;
13194eaa4710SRishi Srivatsavai 		case BLS_LEARNING:
13204eaa4710SRishi Srivatsavai 			name = "LEARN";
13214eaa4710SRishi Srivatsavai 			break;
13224eaa4710SRishi Srivatsavai 		case BLS_FORWARDING:
13234eaa4710SRishi Srivatsavai 			name = "FWD";
13244eaa4710SRishi Srivatsavai 			break;
13254eaa4710SRishi Srivatsavai 		default:
13264eaa4710SRishi Srivatsavai 			name = "?";
13274eaa4710SRishi Srivatsavai 		}
13284eaa4710SRishi Srivatsavai 		mdb_printf("%-5s ", name);
13294eaa4710SRishi Srivatsavai 		show_vlans(blp->bl_vlans);
13304eaa4710SRishi Srivatsavai 	} else {
13314eaa4710SRishi Srivatsavai 		show_vlans(blp->bl_afs);
13324eaa4710SRishi Srivatsavai 	}
13334eaa4710SRishi Srivatsavai 
13344eaa4710SRishi Srivatsavai 	return (WALK_NEXT);
13354eaa4710SRishi Srivatsavai }
13364eaa4710SRishi Srivatsavai 
13374eaa4710SRishi Srivatsavai /*
13384eaa4710SRishi Srivatsavai  * It seems a shame to duplicate this code, but merging it with the link
13394eaa4710SRishi Srivatsavai  * printing code above is more trouble than it would be worth.
13404eaa4710SRishi Srivatsavai  */
13414eaa4710SRishi Srivatsavai static void
print_link_name(show_bridge_args_t * args,uintptr_t addr,char sep)13424eaa4710SRishi Srivatsavai print_link_name(show_bridge_args_t *args, uintptr_t addr, char sep)
13434eaa4710SRishi Srivatsavai {
13444eaa4710SRishi Srivatsavai 	const char *name;
13454eaa4710SRishi Srivatsavai 
13464eaa4710SRishi Srivatsavai 	if (mdb_vread(&args->bl, sizeof (args->bl), addr) == -1) {
13474eaa4710SRishi Srivatsavai 		mdb_warn("cannot read bridge link at %p", addr);
13484eaa4710SRishi Srivatsavai 		return;
13494eaa4710SRishi Srivatsavai 	}
13504eaa4710SRishi Srivatsavai 
13514eaa4710SRishi Srivatsavai 	if (mdb_vread(&args->mi, sizeof (args->mi),
13524eaa4710SRishi Srivatsavai 	    (uintptr_t)args->bl.bl_mh) == -1) {
13534eaa4710SRishi Srivatsavai 		name = "?";
13544eaa4710SRishi Srivatsavai 	} else  {
13554eaa4710SRishi Srivatsavai 		name = args->mi.mi_name;
13564eaa4710SRishi Srivatsavai 	}
13574eaa4710SRishi Srivatsavai 
13584eaa4710SRishi Srivatsavai 	mdb_printf("%s%c", name, sep);
13594eaa4710SRishi Srivatsavai }
13604eaa4710SRishi Srivatsavai 
13614eaa4710SRishi Srivatsavai static int
do_bridge_fwd(uintptr_t addr,const void * data,void * ptr)13624eaa4710SRishi Srivatsavai do_bridge_fwd(uintptr_t addr, const void *data, void *ptr)
13634eaa4710SRishi Srivatsavai {
13644eaa4710SRishi Srivatsavai 	show_bridge_args_t *args = ptr;
13654eaa4710SRishi Srivatsavai 	const bridge_fwd_t *bfp = data;
13664eaa4710SRishi Srivatsavai 	char macaddr[ETHERADDRL * 3];
13674eaa4710SRishi Srivatsavai 	int i;
13684eaa4710SRishi Srivatsavai #define	MAX_FWD_LINKS	16
13694eaa4710SRishi Srivatsavai 	bridge_link_t *links[MAX_FWD_LINKS];
13704eaa4710SRishi Srivatsavai 	uint_t nlinks;
13714eaa4710SRishi Srivatsavai 
13724eaa4710SRishi Srivatsavai 	args->nfwd++;
13734eaa4710SRishi Srivatsavai 
13744eaa4710SRishi Srivatsavai 	if (!args->opt_f)
13754eaa4710SRishi Srivatsavai 		return (WALK_NEXT);
13764eaa4710SRishi Srivatsavai 
13774eaa4710SRishi Srivatsavai 	if ((nlinks = bfp->bf_nlinks) > MAX_FWD_LINKS)
13784eaa4710SRishi Srivatsavai 		nlinks = MAX_FWD_LINKS;
13794eaa4710SRishi Srivatsavai 
13804eaa4710SRishi Srivatsavai 	if (mdb_vread(links, sizeof (links[0]) * nlinks,
13814eaa4710SRishi Srivatsavai 	    (uintptr_t)bfp->bf_links) == -1) {
13824eaa4710SRishi Srivatsavai 		mdb_warn("cannot read bridge forwarding links at %p",
13834eaa4710SRishi Srivatsavai 		    bfp->bf_links);
13844eaa4710SRishi Srivatsavai 		return (WALK_ERR);
13854eaa4710SRishi Srivatsavai 	}
13864eaa4710SRishi Srivatsavai 
13874eaa4710SRishi Srivatsavai 	mdb_mac_addr(bfp->bf_dest, ETHERADDRL, macaddr, sizeof (macaddr));
13884eaa4710SRishi Srivatsavai 
13894eaa4710SRishi Srivatsavai 	mdb_printf("%-?p %-17s ", addr, macaddr);
13904eaa4710SRishi Srivatsavai 	if (bfp->bf_flags & BFF_LOCALADDR)
13914eaa4710SRishi Srivatsavai 		mdb_printf("%-7s", "[self]");
13924eaa4710SRishi Srivatsavai 	else
13934eaa4710SRishi Srivatsavai 		mdb_printf("t-%-5d", args->lbolt - bfp->bf_lastheard);
13944eaa4710SRishi Srivatsavai 	mdb_printf(" %-7u ", bfp->bf_refs);
13954eaa4710SRishi Srivatsavai 
13964eaa4710SRishi Srivatsavai 	if (bfp->bf_trill_nick != 0) {
13974eaa4710SRishi Srivatsavai 		mdb_printf("%d\n", bfp->bf_trill_nick);
13984eaa4710SRishi Srivatsavai 	} else {
13994eaa4710SRishi Srivatsavai 		for (i = 0; i < bfp->bf_nlinks; i++) {
14004eaa4710SRishi Srivatsavai 			print_link_name(args, (uintptr_t)links[i],
14014eaa4710SRishi Srivatsavai 			    i == bfp->bf_nlinks - 1 ? '\n' : ' ');
14024eaa4710SRishi Srivatsavai 		}
14034eaa4710SRishi Srivatsavai 	}
14044eaa4710SRishi Srivatsavai 
14054eaa4710SRishi Srivatsavai 	return (WALK_NEXT);
14064eaa4710SRishi Srivatsavai }
14074eaa4710SRishi Srivatsavai 
14084eaa4710SRishi Srivatsavai static int
do_show_bridge(uintptr_t addr,const void * data,void * ptr)14094eaa4710SRishi Srivatsavai do_show_bridge(uintptr_t addr, const void *data, void *ptr)
14104eaa4710SRishi Srivatsavai {
14114eaa4710SRishi Srivatsavai 	show_bridge_args_t *args = ptr;
14124eaa4710SRishi Srivatsavai 	bridge_inst_t bi;
14134eaa4710SRishi Srivatsavai 	const bridge_inst_t *bip;
14144eaa4710SRishi Srivatsavai 	trill_node_t tn;
14154eaa4710SRishi Srivatsavai 	trill_sock_t tsp;
14164eaa4710SRishi Srivatsavai 	trill_nickinfo_t tni;
14174eaa4710SRishi Srivatsavai 	char bname[MAXLINKNAMELEN];
14184eaa4710SRishi Srivatsavai 	char macaddr[ETHERADDRL * 3];
14194eaa4710SRishi Srivatsavai 	uint_t nnicks;
14204eaa4710SRishi Srivatsavai 	int i;
14214eaa4710SRishi Srivatsavai 
14224eaa4710SRishi Srivatsavai 	if (data != NULL) {
14234eaa4710SRishi Srivatsavai 		bip = data;
14244eaa4710SRishi Srivatsavai 	} else {
14254eaa4710SRishi Srivatsavai 		if (mdb_vread(&bi, sizeof (bi), addr) == -1) {
14264eaa4710SRishi Srivatsavai 			mdb_warn("cannot read bridge instance at %p", addr);
14274eaa4710SRishi Srivatsavai 			return (WALK_ERR);
14284eaa4710SRishi Srivatsavai 		}
14294eaa4710SRishi Srivatsavai 		bip = &bi;
14304eaa4710SRishi Srivatsavai 	}
14314eaa4710SRishi Srivatsavai 
14324eaa4710SRishi Srivatsavai 	(void) strncpy(bname, bip->bi_name, sizeof (bname) - 1);
14334eaa4710SRishi Srivatsavai 	bname[MAXLINKNAMELEN - 1] = '\0';
143424537d3eSToomas Soome 	i = strlen(bname);
143524537d3eSToomas Soome 	if (i > 1 && bname[i - 1] == '0')
143624537d3eSToomas Soome 		bname[i - 1] = '\0';
14374eaa4710SRishi Srivatsavai 
14384eaa4710SRishi Srivatsavai 	if (args->name != NULL && strcmp(args->name, bname) != 0)
14394eaa4710SRishi Srivatsavai 		return (WALK_NEXT);
14404eaa4710SRishi Srivatsavai 
14414eaa4710SRishi Srivatsavai 	args->found = B_TRUE;
14424eaa4710SRishi Srivatsavai 	args->nlinks = args->nfwd = 0;
14434eaa4710SRishi Srivatsavai 
14444eaa4710SRishi Srivatsavai 	if (args->opt_l) {
14454eaa4710SRishi Srivatsavai 		mdb_printf("%-?s %-16s %-17s %3s %-4s ", "ADDR", "LINK",
14464eaa4710SRishi Srivatsavai 		    "MAC-ADDR", "FLG", "PVID");
14474eaa4710SRishi Srivatsavai 		if (bip->bi_trilldata == NULL)
14484eaa4710SRishi Srivatsavai 			mdb_printf("%-5s %s\n", "STATE", "VLANS");
14494eaa4710SRishi Srivatsavai 		else
14504eaa4710SRishi Srivatsavai 			mdb_printf("%s\n", "FWD-VLANS");
14514eaa4710SRishi Srivatsavai 	}
14524eaa4710SRishi Srivatsavai 
14534eaa4710SRishi Srivatsavai 	if (!args->opt_f && !args->opt_t &&
14544eaa4710SRishi Srivatsavai 	    mdb_pwalk("list", do_bridge_links, args,
14554eaa4710SRishi Srivatsavai 	    addr + offsetof(bridge_inst_t, bi_links)) != DCMD_OK)
14564eaa4710SRishi Srivatsavai 		return (WALK_ERR);
14574eaa4710SRishi Srivatsavai 
14584eaa4710SRishi Srivatsavai 	if (args->opt_f)
14594eaa4710SRishi Srivatsavai 		mdb_printf("%-?s %-17s %-7s %-7s %s\n", "ADDR", "DEST", "TIME",
14604eaa4710SRishi Srivatsavai 		    "REFS", "OUTPUT");
14614eaa4710SRishi Srivatsavai 
14624eaa4710SRishi Srivatsavai 	if (!args->opt_l && !args->opt_t &&
14634eaa4710SRishi Srivatsavai 	    mdb_pwalk("avl", do_bridge_fwd, args,
14644eaa4710SRishi Srivatsavai 	    addr + offsetof(bridge_inst_t, bi_fwd)) != DCMD_OK)
14654eaa4710SRishi Srivatsavai 		return (WALK_ERR);
14664eaa4710SRishi Srivatsavai 
14674eaa4710SRishi Srivatsavai 	nnicks = 0;
14684eaa4710SRishi Srivatsavai 	if (bip->bi_trilldata != NULL && !args->opt_l && !args->opt_f) {
14694eaa4710SRishi Srivatsavai 		if (mdb_vread(&args->ti, sizeof (args->ti),
14704eaa4710SRishi Srivatsavai 		    (uintptr_t)bip->bi_trilldata) == -1) {
14714eaa4710SRishi Srivatsavai 			mdb_warn("cannot read trill instance at %p",
14724eaa4710SRishi Srivatsavai 			    bip->bi_trilldata);
14734eaa4710SRishi Srivatsavai 			return (WALK_ERR);
14744eaa4710SRishi Srivatsavai 		}
14754eaa4710SRishi Srivatsavai 		if (args->opt_t)
14764eaa4710SRishi Srivatsavai 			mdb_printf("%-?s %-5s %-17s %s\n", "ADDR",
14774eaa4710SRishi Srivatsavai 			    "NICK", "NEXT-HOP", "LINK");
14784eaa4710SRishi Srivatsavai 		for (i = 0; i < RBRIDGE_NICKNAME_MAX; i++) {
14794eaa4710SRishi Srivatsavai 			if (args->ti.ti_nodes[i] == NULL)
14804eaa4710SRishi Srivatsavai 				continue;
14814eaa4710SRishi Srivatsavai 			if (args->opt_t) {
14824eaa4710SRishi Srivatsavai 				if (mdb_vread(&tn, sizeof (tn),
14834eaa4710SRishi Srivatsavai 				    (uintptr_t)args->ti.ti_nodes[i]) == -1) {
14844eaa4710SRishi Srivatsavai 					mdb_warn("cannot read trill node %d at "
14854eaa4710SRishi Srivatsavai 					    "%p", i, args->ti.ti_nodes[i]);
14864eaa4710SRishi Srivatsavai 					return (WALK_ERR);
14874eaa4710SRishi Srivatsavai 				}
14884eaa4710SRishi Srivatsavai 				if (mdb_vread(&tni, sizeof (tni),
14894eaa4710SRishi Srivatsavai 				    (uintptr_t)tn.tn_ni) == -1) {
14904eaa4710SRishi Srivatsavai 					mdb_warn("cannot read trill node info "
14914eaa4710SRishi Srivatsavai 					    "%d at %p", i, tn.tn_ni);
14924eaa4710SRishi Srivatsavai 					return (WALK_ERR);
14934eaa4710SRishi Srivatsavai 				}
14944eaa4710SRishi Srivatsavai 				mdb_mac_addr(tni.tni_adjsnpa, ETHERADDRL,
14954eaa4710SRishi Srivatsavai 				    macaddr, sizeof (macaddr));
14964eaa4710SRishi Srivatsavai 				if (tni.tni_nick == args->ti.ti_nick) {
14974eaa4710SRishi Srivatsavai 					(void) strcpy(macaddr, "[self]");
14984eaa4710SRishi Srivatsavai 				}
14994eaa4710SRishi Srivatsavai 				mdb_printf("%-?p %-5u %-17s ",
15004eaa4710SRishi Srivatsavai 				    args->ti.ti_nodes[i], tni.tni_nick,
15014eaa4710SRishi Srivatsavai 				    macaddr);
15024eaa4710SRishi Srivatsavai 				if (tn.tn_tsp != NULL) {
15034eaa4710SRishi Srivatsavai 					if (mdb_vread(&tsp, sizeof (tsp),
15044eaa4710SRishi Srivatsavai 					    (uintptr_t)tn.tn_tsp) == -1) {
15054eaa4710SRishi Srivatsavai 						mdb_warn("cannot read trill "
15064eaa4710SRishi Srivatsavai 						    "socket info at %p",
15074eaa4710SRishi Srivatsavai 						    tn.tn_tsp);
15084eaa4710SRishi Srivatsavai 						return (WALK_ERR);
15094eaa4710SRishi Srivatsavai 					}
15104eaa4710SRishi Srivatsavai 					if (tsp.ts_link != NULL) {
15114eaa4710SRishi Srivatsavai 						print_link_name(args,
15124eaa4710SRishi Srivatsavai 						    (uintptr_t)tsp.ts_link,
15134eaa4710SRishi Srivatsavai 						    '\n');
15144eaa4710SRishi Srivatsavai 						continue;
15154eaa4710SRishi Srivatsavai 					}
15164eaa4710SRishi Srivatsavai 				}
15174eaa4710SRishi Srivatsavai 				mdb_printf("--\n");
15184eaa4710SRishi Srivatsavai 			} else {
15194eaa4710SRishi Srivatsavai 				nnicks++;
15204eaa4710SRishi Srivatsavai 			}
15214eaa4710SRishi Srivatsavai 		}
15224eaa4710SRishi Srivatsavai 	} else {
15234eaa4710SRishi Srivatsavai 		if (args->opt_t)
15244eaa4710SRishi Srivatsavai 			mdb_printf("bridge is not running TRILL\n");
15254eaa4710SRishi Srivatsavai 	}
15264eaa4710SRishi Srivatsavai 
15274eaa4710SRishi Srivatsavai 	if (!args->opt_l && !args->opt_f && !args->opt_t) {
15284eaa4710SRishi Srivatsavai 		mdb_printf("%-?p %-7s %-16s %-7u %-7u", addr,
15294eaa4710SRishi Srivatsavai 		    bip->bi_trilldata == NULL ? "stp" : "trill", bname,
15304eaa4710SRishi Srivatsavai 		    args->nlinks, args->nfwd);
15314eaa4710SRishi Srivatsavai 		if (bip->bi_trilldata != NULL)
15324eaa4710SRishi Srivatsavai 			mdb_printf(" %-7u %u\n", nnicks, args->ti.ti_nick);
15334eaa4710SRishi Srivatsavai 		else
15344eaa4710SRishi Srivatsavai 			mdb_printf(" %-7s %s\n", "--", "--");
15354eaa4710SRishi Srivatsavai 	}
15364eaa4710SRishi Srivatsavai 	return (WALK_NEXT);
15374eaa4710SRishi Srivatsavai }
15384eaa4710SRishi Srivatsavai 
15394eaa4710SRishi Srivatsavai static int
dladm_show_bridge(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)15404eaa4710SRishi Srivatsavai dladm_show_bridge(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
15414eaa4710SRishi Srivatsavai {
15424eaa4710SRishi Srivatsavai 	show_bridge_args_t *args;
15434eaa4710SRishi Srivatsavai 	GElf_Sym sym;
15444eaa4710SRishi Srivatsavai 	int i;
15454eaa4710SRishi Srivatsavai 
15464eaa4710SRishi Srivatsavai 	args = mdb_zalloc(sizeof (*args), UM_SLEEP);
15474eaa4710SRishi Srivatsavai 
15484eaa4710SRishi Srivatsavai 	i = mdb_getopts(argc, argv,
15494eaa4710SRishi Srivatsavai 	    'l', MDB_OPT_SETBITS, 1, &args->opt_l,
15504eaa4710SRishi Srivatsavai 	    'f', MDB_OPT_SETBITS, 1, &args->opt_f,
15514eaa4710SRishi Srivatsavai 	    't', MDB_OPT_SETBITS, 1, &args->opt_t,
15524eaa4710SRishi Srivatsavai 	    NULL);
15534eaa4710SRishi Srivatsavai 
15544eaa4710SRishi Srivatsavai 	argc -= i;
15554eaa4710SRishi Srivatsavai 	argv += i;
15564eaa4710SRishi Srivatsavai 
15574eaa4710SRishi Srivatsavai 	if (argc > 1 || (argc == 1 && argv[0].a_type != MDB_TYPE_STRING)) {
15584eaa4710SRishi Srivatsavai 		mdb_free(args, sizeof (*args));
15594eaa4710SRishi Srivatsavai 		return (DCMD_USAGE);
15604eaa4710SRishi Srivatsavai 	}
15614eaa4710SRishi Srivatsavai 	if (argc == 1)
15624eaa4710SRishi Srivatsavai 		args->name = argv[0].a_un.a_str;
15634eaa4710SRishi Srivatsavai 
1564d3d50737SRafael Vanoni 	if ((args->lbolt = mdb_get_lbolt()) == -1) {
15654eaa4710SRishi Srivatsavai 		mdb_warn("failed to read lbolt");
15664eaa4710SRishi Srivatsavai 		goto err;
15674eaa4710SRishi Srivatsavai 	}
15684eaa4710SRishi Srivatsavai 
15694eaa4710SRishi Srivatsavai 	if (flags & DCMD_ADDRSPEC) {
15704eaa4710SRishi Srivatsavai 		if (args->name != NULL) {
15714eaa4710SRishi Srivatsavai 			mdb_printf("bridge name and address are mutually "
15724eaa4710SRishi Srivatsavai 			    "exclusive\n");
15734eaa4710SRishi Srivatsavai 			goto err;
15744eaa4710SRishi Srivatsavai 		}
15754eaa4710SRishi Srivatsavai 		if (!args->opt_l && !args->opt_f && !args->opt_t)
15764eaa4710SRishi Srivatsavai 			mdb_printf("%-?s %-7s %-16s %-7s %-7s\n", "ADDR",
15774eaa4710SRishi Srivatsavai 			    "PROTECT", "NAME", "NLINKS", "NFWD");
15784eaa4710SRishi Srivatsavai 		if (do_show_bridge(addr, NULL, args) != WALK_NEXT)
15794eaa4710SRishi Srivatsavai 			goto err;
15804eaa4710SRishi Srivatsavai 		mdb_free(args, sizeof (*args));
15814eaa4710SRishi Srivatsavai 		return (DCMD_OK);
15824eaa4710SRishi Srivatsavai 	} else {
15834eaa4710SRishi Srivatsavai 		if ((args->opt_l || args->opt_f || args->opt_t) &&
15844eaa4710SRishi Srivatsavai 		    args->name == NULL) {
15854eaa4710SRishi Srivatsavai 			mdb_printf("need bridge name or address with -[lft]\n");
15864eaa4710SRishi Srivatsavai 			goto err;
15874eaa4710SRishi Srivatsavai 		}
15884eaa4710SRishi Srivatsavai 		if (mdb_lookup_by_obj("bridge", "inst_list", &sym) == -1) {
15894eaa4710SRishi Srivatsavai 			mdb_warn("failed to find 'bridge`inst_list'");
15904eaa4710SRishi Srivatsavai 			goto err;
15914eaa4710SRishi Srivatsavai 		}
15924eaa4710SRishi Srivatsavai 		if (!args->opt_l && !args->opt_f && !args->opt_t)
15934eaa4710SRishi Srivatsavai 			mdb_printf("%-?s %-7s %-16s %-7s %-7s %-7s %s\n",
15944eaa4710SRishi Srivatsavai 			    "ADDR", "PROTECT", "NAME", "NLINKS", "NFWD",
15954eaa4710SRishi Srivatsavai 			    "NNICKS", "NICK");
15964eaa4710SRishi Srivatsavai 		if (mdb_pwalk("list", do_show_bridge, args,
15974eaa4710SRishi Srivatsavai 		    (uintptr_t)sym.st_value) != DCMD_OK)
15984eaa4710SRishi Srivatsavai 			goto err;
15994eaa4710SRishi Srivatsavai 		if (!args->found && args->name != NULL) {
16004eaa4710SRishi Srivatsavai 			mdb_printf("bridge instance %s not found\n",
16014eaa4710SRishi Srivatsavai 			    args->name);
16024eaa4710SRishi Srivatsavai 			goto err;
16034eaa4710SRishi Srivatsavai 		}
16044eaa4710SRishi Srivatsavai 		mdb_free(args, sizeof (*args));
16054eaa4710SRishi Srivatsavai 		return (DCMD_OK);
16064eaa4710SRishi Srivatsavai 	}
16074eaa4710SRishi Srivatsavai 
16084eaa4710SRishi Srivatsavai err:
16094eaa4710SRishi Srivatsavai 	mdb_free(args, sizeof (*args));
16104eaa4710SRishi Srivatsavai 	return (DCMD_ERR);
16114eaa4710SRishi Srivatsavai }
16124eaa4710SRishi Srivatsavai 
16134eaa4710SRishi Srivatsavai /*
16144eaa4710SRishi Srivatsavai  * Support for the "::dladm" dcmd
16154eaa4710SRishi Srivatsavai  */
16164eaa4710SRishi Srivatsavai int
dladm(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)16174eaa4710SRishi Srivatsavai dladm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
16184eaa4710SRishi Srivatsavai {
16194eaa4710SRishi Srivatsavai 	if (argc < 1 || argv[0].a_type != MDB_TYPE_STRING)
16204eaa4710SRishi Srivatsavai 		return (DCMD_USAGE);
16214eaa4710SRishi Srivatsavai 
16224eaa4710SRishi Srivatsavai 	/*
16234eaa4710SRishi Srivatsavai 	 * This could be a bit more elaborate, once we support more of the
16244eaa4710SRishi Srivatsavai 	 * dladm show-* subcommands.
16254eaa4710SRishi Srivatsavai 	 */
16264eaa4710SRishi Srivatsavai 	argc--;
16274eaa4710SRishi Srivatsavai 	argv++;
16284eaa4710SRishi Srivatsavai 	if (strcmp(argv[-1].a_un.a_str, "show-bridge") == 0)
16294eaa4710SRishi Srivatsavai 		return (dladm_show_bridge(addr, flags, argc, argv));
16304eaa4710SRishi Srivatsavai 
16314eaa4710SRishi Srivatsavai 	return (DCMD_USAGE);
16324eaa4710SRishi Srivatsavai }
16334eaa4710SRishi Srivatsavai 
16344eaa4710SRishi Srivatsavai void
dladm_help(void)16354eaa4710SRishi Srivatsavai dladm_help(void)
16364eaa4710SRishi Srivatsavai {
16374eaa4710SRishi Srivatsavai 	mdb_printf("Subcommands:\n"
16384eaa4710SRishi Srivatsavai 	    "  show-bridge [-flt] [<name>]\n"
16394eaa4710SRishi Srivatsavai 	    "\t     Show bridge information; -l for links and -f for "
16404eaa4710SRishi Srivatsavai 	    "forwarding\n"
16414eaa4710SRishi Srivatsavai 	    "\t     entries, and -t for TRILL nicknames.  Address is required "
16424eaa4710SRishi Srivatsavai 	    "if name\n"
16434eaa4710SRishi Srivatsavai 	    "\t     is not specified.\n");
16444eaa4710SRishi Srivatsavai }
1645