xref: /onnv-gate/usr/src/cmd/mdb/common/modules/genunix/net.c (revision 11066:cebb50cbe4f9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
229089SVasumathi.Sundaram@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
270Sstevel@tonic-gate #include <mdb/mdb_ks.h>
280Sstevel@tonic-gate #include <mdb/mdb_ctf.h>
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/tihdr.h>
310Sstevel@tonic-gate #include <inet/led.h>
320Sstevel@tonic-gate #include <inet/common.h>
330Sstevel@tonic-gate #include <netinet/in.h>
340Sstevel@tonic-gate #include <netinet/ip6.h>
350Sstevel@tonic-gate #include <netinet/icmp6.h>
360Sstevel@tonic-gate #include <inet/ip.h>
370Sstevel@tonic-gate #include <inet/ip6.h>
380Sstevel@tonic-gate #include <inet/ipclassifier.h>
390Sstevel@tonic-gate #include <inet/tcp.h>
400Sstevel@tonic-gate #include <sys/stream.h>
410Sstevel@tonic-gate #include <sys/vfs.h>
420Sstevel@tonic-gate #include <sys/stropts.h>
430Sstevel@tonic-gate #include <sys/tpicommon.h>
440Sstevel@tonic-gate #include <sys/socket.h>
450Sstevel@tonic-gate #include <sys/socketvar.h>
460Sstevel@tonic-gate #include <sys/cred_impl.h>
470Sstevel@tonic-gate #include <inet/udp_impl.h>
480Sstevel@tonic-gate #include <inet/rawip_impl.h>
490Sstevel@tonic-gate #include <inet/mi.h>
508348SEric.Yu@Sun.COM #include <fs/sockfs/socktpi_impl.h>
5110491SRishi.Srivatsavai@Sun.COM #include <net/bridge_impl.h>
5210491SRishi.Srivatsavai@Sun.COM #include <io/trill_impl.h>
5310491SRishi.Srivatsavai@Sun.COM #include <sys/mac_impl.h>
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #define	ADDR_V6_WIDTH	23
560Sstevel@tonic-gate #define	ADDR_V4_WIDTH	15
570Sstevel@tonic-gate 
581676Sjpk #define	NETSTAT_ALL	0x01
591676Sjpk #define	NETSTAT_VERBOSE	0x02
601676Sjpk #define	NETSTAT_ROUTE	0x04
611676Sjpk #define	NETSTAT_V4	0x08
621676Sjpk #define	NETSTAT_V6	0x10
631676Sjpk #define	NETSTAT_UNIX	0x20
641676Sjpk 
651676Sjpk #define	NETSTAT_FIRST	0x80000000u
660Sstevel@tonic-gate 
679089SVasumathi.Sundaram@Sun.COM typedef struct netstat_cb_data_s {
689089SVasumathi.Sundaram@Sun.COM 	uint_t	opts;
699089SVasumathi.Sundaram@Sun.COM 	conn_t	conn;
709089SVasumathi.Sundaram@Sun.COM 	int	af;
719089SVasumathi.Sundaram@Sun.COM } netstat_cb_data_t;
723448Sdh155122 
733448Sdh155122 int
icmp_stacks_walk_init(mdb_walk_state_t * wsp)743448Sdh155122 icmp_stacks_walk_init(mdb_walk_state_t *wsp)
753448Sdh155122 {
763448Sdh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
773448Sdh155122 		mdb_warn("can't walk 'netstack'");
783448Sdh155122 		return (WALK_ERR);
793448Sdh155122 	}
803448Sdh155122 	return (WALK_NEXT);
813448Sdh155122 }
823448Sdh155122 
833448Sdh155122 int
icmp_stacks_walk_step(mdb_walk_state_t * wsp)843448Sdh155122 icmp_stacks_walk_step(mdb_walk_state_t *wsp)
853448Sdh155122 {
863448Sdh155122 	uintptr_t kaddr;
873448Sdh155122 	netstack_t nss;
883448Sdh155122 
893448Sdh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
903448Sdh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
913448Sdh155122 		return (WALK_ERR);
923448Sdh155122 	}
933448Sdh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_ICMP];
943448Sdh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
953448Sdh155122 }
963448Sdh155122 
973448Sdh155122 int
tcp_stacks_walk_init(mdb_walk_state_t * wsp)983448Sdh155122 tcp_stacks_walk_init(mdb_walk_state_t *wsp)
993448Sdh155122 {
1003448Sdh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
1013448Sdh155122 		mdb_warn("can't walk 'netstack'");
1023448Sdh155122 		return (WALK_ERR);
1033448Sdh155122 	}
1043448Sdh155122 	return (WALK_NEXT);
1053448Sdh155122 }
1063448Sdh155122 
1073448Sdh155122 int
tcp_stacks_walk_step(mdb_walk_state_t * wsp)1083448Sdh155122 tcp_stacks_walk_step(mdb_walk_state_t *wsp)
1093448Sdh155122 {
1103448Sdh155122 	uintptr_t kaddr;
1113448Sdh155122 	netstack_t nss;
1123448Sdh155122 
1133448Sdh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
1143448Sdh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
1153448Sdh155122 		return (WALK_ERR);
1163448Sdh155122 	}
1173448Sdh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_TCP];
1183448Sdh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
1193448Sdh155122 }
1203448Sdh155122 
1213448Sdh155122 int
udp_stacks_walk_init(mdb_walk_state_t * wsp)1223448Sdh155122 udp_stacks_walk_init(mdb_walk_state_t *wsp)
1233448Sdh155122 {
1243448Sdh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
1253448Sdh155122 		mdb_warn("can't walk 'netstack'");
1263448Sdh155122 		return (WALK_ERR);
1273448Sdh155122 	}
1283448Sdh155122 	return (WALK_NEXT);
1293448Sdh155122 }
1303448Sdh155122 
1313448Sdh155122 int
udp_stacks_walk_step(mdb_walk_state_t * wsp)1323448Sdh155122 udp_stacks_walk_step(mdb_walk_state_t *wsp)
1333448Sdh155122 {
1343448Sdh155122 	uintptr_t kaddr;
1353448Sdh155122 	netstack_t nss;
1363448Sdh155122 
1373448Sdh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
1383448Sdh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
1393448Sdh155122 		return (WALK_ERR);
1403448Sdh155122 	}
1413448Sdh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_UDP];
1423448Sdh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
1433448Sdh155122 }
1443448Sdh155122 
1450Sstevel@tonic-gate /*
1460Sstevel@tonic-gate  * Print an IPv4 address and port number in a compact and easy to read format
1470Sstevel@tonic-gate  * The arguments are in network byte order
1480Sstevel@tonic-gate  */
1490Sstevel@tonic-gate static void
net_ipv4addrport_pr(const in6_addr_t * nipv6addr,in_port_t nport)1500Sstevel@tonic-gate net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport)
1510Sstevel@tonic-gate {
1520Sstevel@tonic-gate 	uint32_t naddr = V4_PART_OF_V6((*nipv6addr));
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	mdb_nhconvert(&nport, &nport, sizeof (nport));
1550Sstevel@tonic-gate 	mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate /*
1590Sstevel@tonic-gate  * Print an IPv6 address and port number in a compact and easy to read format
1600Sstevel@tonic-gate  * The arguments are in network byte order
1610Sstevel@tonic-gate  */
1620Sstevel@tonic-gate static void
net_ipv6addrport_pr(const in6_addr_t * naddr,in_port_t nport)1630Sstevel@tonic-gate net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport)
1640Sstevel@tonic-gate {
1650Sstevel@tonic-gate 	mdb_nhconvert(&nport, &nport, sizeof (nport));
1660Sstevel@tonic-gate 	mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate static int
net_tcp_active(const tcp_t * tcp)1700Sstevel@tonic-gate net_tcp_active(const tcp_t *tcp)
1710Sstevel@tonic-gate {
1720Sstevel@tonic-gate 	return (tcp->tcp_state >= TCPS_ESTABLISHED);
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate static int
net_tcp_ipv4(const tcp_t * tcp)1760Sstevel@tonic-gate net_tcp_ipv4(const tcp_t *tcp)
1770Sstevel@tonic-gate {
17811042SErik.Nordmark@Sun.COM 	return ((tcp->tcp_connp->conn_ipversion == IPV4_VERSION) ||
17911042SErik.Nordmark@Sun.COM 	    (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_connp->conn_laddr_v6) &&
1800Sstevel@tonic-gate 	    (tcp->tcp_state <= TCPS_LISTEN)));
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate static int
net_tcp_ipv6(const tcp_t * tcp)1840Sstevel@tonic-gate net_tcp_ipv6(const tcp_t *tcp)
1850Sstevel@tonic-gate {
18611042SErik.Nordmark@Sun.COM 	return (tcp->tcp_connp->conn_ipversion == IPV6_VERSION);
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate static int
net_udp_active(const udp_t * udp)1900Sstevel@tonic-gate net_udp_active(const udp_t *udp)
1910Sstevel@tonic-gate {
192741Smasputra 	return ((udp->udp_state == TS_IDLE) ||
193741Smasputra 	    (udp->udp_state == TS_DATA_XFER));
1940Sstevel@tonic-gate }
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate static int
net_udp_ipv4(const udp_t * udp)1970Sstevel@tonic-gate net_udp_ipv4(const udp_t *udp)
1980Sstevel@tonic-gate {
19911042SErik.Nordmark@Sun.COM 	return ((udp->udp_connp->conn_ipversion == IPV4_VERSION) ||
20011042SErik.Nordmark@Sun.COM 	    (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_connp->conn_laddr_v6) &&
2010Sstevel@tonic-gate 	    (udp->udp_state <= TS_IDLE)));
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate static int
net_udp_ipv6(const udp_t * udp)2050Sstevel@tonic-gate net_udp_ipv6(const udp_t *udp)
2060Sstevel@tonic-gate {
20711042SErik.Nordmark@Sun.COM 	return (udp->udp_connp->conn_ipversion == IPV6_VERSION);
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate int
sonode_walk_init(mdb_walk_state_t * wsp)2110Sstevel@tonic-gate sonode_walk_init(mdb_walk_state_t *wsp)
2120Sstevel@tonic-gate {
2130Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
2140Sstevel@tonic-gate 		GElf_Sym sym;
2150Sstevel@tonic-gate 		struct socklist *slp;
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 		if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) {
2180Sstevel@tonic-gate 			mdb_warn("failed to lookup sockfs`socklist");
2190Sstevel@tonic-gate 			return (WALK_ERR);
2200Sstevel@tonic-gate 		}
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 		slp = (struct socklist *)(uintptr_t)sym.st_value;
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 		if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),
2250Sstevel@tonic-gate 		    (uintptr_t)&slp->sl_list) == -1) {
2260Sstevel@tonic-gate 			mdb_warn("failed to read address of initial sonode "
2270Sstevel@tonic-gate 			    "at %p", &slp->sl_list);
2280Sstevel@tonic-gate 			return (WALK_ERR);
2290Sstevel@tonic-gate 		}
2300Sstevel@tonic-gate 	}
2310Sstevel@tonic-gate 
2328348SEric.Yu@Sun.COM 	wsp->walk_data = mdb_alloc(sizeof (struct sotpi_sonode), UM_SLEEP);
2330Sstevel@tonic-gate 	return (WALK_NEXT);
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate int
sonode_walk_step(mdb_walk_state_t * wsp)2370Sstevel@tonic-gate sonode_walk_step(mdb_walk_state_t *wsp)
2380Sstevel@tonic-gate {
2390Sstevel@tonic-gate 	int status;
2408348SEric.Yu@Sun.COM 	struct sotpi_sonode *stp;
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
2430Sstevel@tonic-gate 		return (WALK_DONE);
2440Sstevel@tonic-gate 
2458348SEric.Yu@Sun.COM 	if (mdb_vread(wsp->walk_data, sizeof (struct sotpi_sonode),
2460Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
2470Sstevel@tonic-gate 		mdb_warn("failed to read sonode at %p", wsp->walk_addr);
2480Sstevel@tonic-gate 		return (WALK_ERR);
2490Sstevel@tonic-gate 	}
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
2520Sstevel@tonic-gate 	    wsp->walk_cbdata);
2530Sstevel@tonic-gate 
2548348SEric.Yu@Sun.COM 	stp = wsp->walk_data;
2550Sstevel@tonic-gate 
2568348SEric.Yu@Sun.COM 	wsp->walk_addr = (uintptr_t)stp->st_info.sti_next_so;
2570Sstevel@tonic-gate 	return (status);
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate void
sonode_walk_fini(mdb_walk_state_t * wsp)2610Sstevel@tonic-gate sonode_walk_fini(mdb_walk_state_t *wsp)
2620Sstevel@tonic-gate {
2638348SEric.Yu@Sun.COM 	mdb_free(wsp->walk_data, sizeof (struct sotpi_sonode));
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate struct mi_walk_data {
2670Sstevel@tonic-gate 	uintptr_t mi_wd_miofirst;
2680Sstevel@tonic-gate 	MI_O mi_wd_miodata;
2690Sstevel@tonic-gate };
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate int
mi_walk_init(mdb_walk_state_t * wsp)2720Sstevel@tonic-gate mi_walk_init(mdb_walk_state_t *wsp)
2730Sstevel@tonic-gate {
2740Sstevel@tonic-gate 	struct mi_walk_data *wdp;
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
2770Sstevel@tonic-gate 		mdb_warn("mi doesn't support global walks\n");
2780Sstevel@tonic-gate 		return (WALK_ERR);
2790Sstevel@tonic-gate 	}
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP);
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	/* So that we do not immediately return WALK_DONE below */
2840Sstevel@tonic-gate 	wdp->mi_wd_miofirst = NULL;
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	wsp->walk_data = wdp;
2870Sstevel@tonic-gate 	return (WALK_NEXT);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate int
mi_walk_step(mdb_walk_state_t * wsp)2910Sstevel@tonic-gate mi_walk_step(mdb_walk_state_t *wsp)
2920Sstevel@tonic-gate {
2930Sstevel@tonic-gate 	struct mi_walk_data *wdp = wsp->walk_data;
2940Sstevel@tonic-gate 	MI_OP miop = &wdp->mi_wd_miodata;
2950Sstevel@tonic-gate 	int status;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	/* Always false in the first iteration */
2980Sstevel@tonic-gate 	if ((wsp->walk_addr == (uintptr_t)NULL) ||
2990Sstevel@tonic-gate 	    (wsp->walk_addr == wdp->mi_wd_miofirst)) {
3000Sstevel@tonic-gate 		return (WALK_DONE);
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) {
3040Sstevel@tonic-gate 		mdb_warn("failed to read MI object at %p", wsp->walk_addr);
3050Sstevel@tonic-gate 		return (WALK_ERR);
3060Sstevel@tonic-gate 	}
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	/* Only true in the first iteration */
3093448Sdh155122 	if (wdp->mi_wd_miofirst == NULL) {
3100Sstevel@tonic-gate 		wdp->mi_wd_miofirst = wsp->walk_addr;
3113448Sdh155122 		status = WALK_NEXT;
3123448Sdh155122 	} else {
3133448Sdh155122 		status = wsp->walk_callback(wsp->walk_addr + sizeof (MI_O),
3143448Sdh155122 		    &miop[1], wsp->walk_cbdata);
3153448Sdh155122 	}
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)miop->mi_o_next;
3180Sstevel@tonic-gate 	return (status);
3190Sstevel@tonic-gate }
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate void
mi_walk_fini(mdb_walk_state_t * wsp)3220Sstevel@tonic-gate mi_walk_fini(mdb_walk_state_t *wsp)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct mi_walk_data));
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate typedef struct mi_payload_walk_arg_s {
3283448Sdh155122 	const char *mi_pwa_walker;	/* Underlying walker */
3293448Sdh155122 	const off_t mi_pwa_head_off;	/* Offset for mi_o_head_t * in stack */
3300Sstevel@tonic-gate 	const size_t mi_pwa_size;	/* size of mi payload */
3310Sstevel@tonic-gate 	const uint_t mi_pwa_flags;	/* device and/or module */
3320Sstevel@tonic-gate } mi_payload_walk_arg_t;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate #define	MI_PAYLOAD_DEVICE	0x1
3350Sstevel@tonic-gate #define	MI_PAYLOAD_MODULE	0x2
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate int
mi_payload_walk_init(mdb_walk_state_t * wsp)3380Sstevel@tonic-gate mi_payload_walk_init(mdb_walk_state_t *wsp)
3390Sstevel@tonic-gate {
3400Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
3410Sstevel@tonic-gate 
3423448Sdh155122 	if (mdb_layered_walk(arg->mi_pwa_walker, wsp) == -1) {
3433448Sdh155122 		mdb_warn("can't walk '%s'", arg->mi_pwa_walker);
3440Sstevel@tonic-gate 		return (WALK_ERR);
3450Sstevel@tonic-gate 	}
3460Sstevel@tonic-gate 	return (WALK_NEXT);
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate int
mi_payload_walk_step(mdb_walk_state_t * wsp)3500Sstevel@tonic-gate mi_payload_walk_step(mdb_walk_state_t *wsp)
3510Sstevel@tonic-gate {
3520Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
3533448Sdh155122 	uintptr_t kaddr;
3540Sstevel@tonic-gate 
3553448Sdh155122 	kaddr = wsp->walk_addr + arg->mi_pwa_head_off;
3560Sstevel@tonic-gate 
3573448Sdh155122 	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
3583448Sdh155122 		mdb_warn("can't read address of mi head at %p for %s",
3593448Sdh155122 		    kaddr, arg->mi_pwa_walker);
3600Sstevel@tonic-gate 		return (WALK_ERR);
3610Sstevel@tonic-gate 	}
3620Sstevel@tonic-gate 
3633448Sdh155122 	if (kaddr == 0) {
3643448Sdh155122 		/* Empty list */
3653448Sdh155122 		return (WALK_DONE);
3663448Sdh155122 	}
3670Sstevel@tonic-gate 
3683448Sdh155122 	if (mdb_pwalk("genunix`mi", wsp->walk_callback,
3693448Sdh155122 	    wsp->walk_cbdata, kaddr) == -1) {
3703448Sdh155122 		mdb_warn("failed to walk genunix`mi");
3713448Sdh155122 		return (WALK_ERR);
3723448Sdh155122 	}
3733448Sdh155122 	return (WALK_NEXT);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate const mi_payload_walk_arg_t mi_icmp_arg = {
3773448Sdh155122 	"icmp_stacks", OFFSETOF(icmp_stack_t, is_head), sizeof (icmp_t),
3780Sstevel@tonic-gate 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
3790Sstevel@tonic-gate };
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate int
sonode(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)3820Sstevel@tonic-gate sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3830Sstevel@tonic-gate {
3840Sstevel@tonic-gate 	const char *optf = NULL;
3850Sstevel@tonic-gate 	const char *optt = NULL;
3860Sstevel@tonic-gate 	const char *optp = NULL;
3870Sstevel@tonic-gate 	int family, type, proto;
3880Sstevel@tonic-gate 	int filter = 0;
3890Sstevel@tonic-gate 	struct sonode so;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
3920Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`sonode", "genunix`sonode", argc,
3930Sstevel@tonic-gate 		    argv) == -1) {
3940Sstevel@tonic-gate 			mdb_warn("failed to walk sonode");
3950Sstevel@tonic-gate 			return (DCMD_ERR);
3960Sstevel@tonic-gate 		}
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 		return (DCMD_OK);
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
4020Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &optf,
4030Sstevel@tonic-gate 	    't', MDB_OPT_STR, &optt,
4040Sstevel@tonic-gate 	    'p', MDB_OPT_STR, &optp,
4050Sstevel@tonic-gate 	    NULL) != argc)
4060Sstevel@tonic-gate 		return (DCMD_USAGE);
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	if (optf != NULL) {
4090Sstevel@tonic-gate 		if (strcmp("inet", optf) == 0)
4100Sstevel@tonic-gate 			family = AF_INET;
4110Sstevel@tonic-gate 		else if (strcmp("inet6", optf) == 0)
4120Sstevel@tonic-gate 			family = AF_INET6;
4130Sstevel@tonic-gate 		else if (strcmp("unix", optf) == 0)
4140Sstevel@tonic-gate 			family = AF_UNIX;
4150Sstevel@tonic-gate 		else
4160Sstevel@tonic-gate 			family = mdb_strtoull(optf);
4170Sstevel@tonic-gate 		filter = 1;
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	if (optt != NULL) {
4210Sstevel@tonic-gate 		if (strcmp("stream", optt) == 0)
4220Sstevel@tonic-gate 			type = SOCK_STREAM;
4230Sstevel@tonic-gate 		else if (strcmp("dgram", optt) == 0)
4240Sstevel@tonic-gate 			type = SOCK_DGRAM;
4250Sstevel@tonic-gate 		else if (strcmp("raw", optt) == 0)
4260Sstevel@tonic-gate 			type = SOCK_RAW;
4270Sstevel@tonic-gate 		else
4280Sstevel@tonic-gate 			type = mdb_strtoull(optt);
4290Sstevel@tonic-gate 		filter = 1;
4300Sstevel@tonic-gate 	}
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	if (optp != NULL) {
4330Sstevel@tonic-gate 		proto = mdb_strtoull(optp);
4340Sstevel@tonic-gate 		filter = 1;
4350Sstevel@tonic-gate 	}
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !filter) {
4380Sstevel@tonic-gate 		mdb_printf("%<u>%-?s Family Type Proto State Mode Flag "
4390Sstevel@tonic-gate 		    "AccessVP%</u>\n", "Sonode:");
4400Sstevel@tonic-gate 	}
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	if (mdb_vread(&so, sizeof (so), addr) == -1) {
4430Sstevel@tonic-gate 		mdb_warn("failed to read sonode at %p", addr);
4440Sstevel@tonic-gate 		return (DCMD_ERR);
4450Sstevel@tonic-gate 	}
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	if ((optf != NULL) && (so.so_family != family))
4480Sstevel@tonic-gate 		return (DCMD_OK);
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	if ((optt != NULL) && (so.so_type != type))
4510Sstevel@tonic-gate 		return (DCMD_OK);
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	if ((optp != NULL) && (so.so_protocol != proto))
4540Sstevel@tonic-gate 		return (DCMD_OK);
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	if (filter) {
4570Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
4580Sstevel@tonic-gate 		return (DCMD_OK);
4590Sstevel@tonic-gate 	}
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	mdb_printf("%0?p ", addr);
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	switch (so.so_family) {
4645563Snordmark 	case AF_UNIX:
4650Sstevel@tonic-gate 		mdb_printf("unix  ");
4660Sstevel@tonic-gate 		break;
4675563Snordmark 	case AF_INET:
4680Sstevel@tonic-gate 		mdb_printf("inet  ");
4690Sstevel@tonic-gate 		break;
4705563Snordmark 	case AF_INET6:
4710Sstevel@tonic-gate 		mdb_printf("inet6 ");
4720Sstevel@tonic-gate 		break;
4735563Snordmark 	default:
4740Sstevel@tonic-gate 		mdb_printf("%6hi", so.so_family);
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 	switch (so.so_type) {
4785563Snordmark 	case SOCK_STREAM:
4790Sstevel@tonic-gate 		mdb_printf(" strm");
4800Sstevel@tonic-gate 		break;
4815563Snordmark 	case SOCK_DGRAM:
4820Sstevel@tonic-gate 		mdb_printf(" dgrm");
4830Sstevel@tonic-gate 		break;
4845563Snordmark 	case SOCK_RAW:
4850Sstevel@tonic-gate 		mdb_printf(" raw ");
4860Sstevel@tonic-gate 		break;
4875563Snordmark 	default:
4880Sstevel@tonic-gate 		mdb_printf(" %4hi", so.so_type);
4890Sstevel@tonic-gate 	}
4900Sstevel@tonic-gate 
4918348SEric.Yu@Sun.COM 	mdb_printf(" %5hi %05x %04x %04hx\n",
4920Sstevel@tonic-gate 	    so.so_protocol, so.so_state, so.so_mode,
4938348SEric.Yu@Sun.COM 	    so.so_flag);
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	return (DCMD_OK);
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate #define	MI_PAYLOAD	0x1
4990Sstevel@tonic-gate #define	MI_DEVICE	0x2
5000Sstevel@tonic-gate #define	MI_MODULE	0x4
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate int
mi(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)5030Sstevel@tonic-gate mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5040Sstevel@tonic-gate {
5050Sstevel@tonic-gate 	uint_t opts = 0;
5060Sstevel@tonic-gate 	MI_O	mio;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
5090Sstevel@tonic-gate 		return (DCMD_USAGE);
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
5120Sstevel@tonic-gate 	    'p', MDB_OPT_SETBITS, MI_PAYLOAD, &opts,
5130Sstevel@tonic-gate 	    'd', MDB_OPT_SETBITS, MI_DEVICE, &opts,
5140Sstevel@tonic-gate 	    'm', MDB_OPT_SETBITS, MI_MODULE, &opts,
5150Sstevel@tonic-gate 	    NULL) != argc)
5160Sstevel@tonic-gate 		return (DCMD_USAGE);
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	if ((opts & (MI_DEVICE | MI_MODULE)) == (MI_DEVICE | MI_MODULE)) {
5190Sstevel@tonic-gate 		mdb_warn("at most one filter, d for devices or m "
5200Sstevel@tonic-gate 		    "for modules, may be specified\n");
5210Sstevel@tonic-gate 		return (DCMD_USAGE);
5220Sstevel@tonic-gate 	}
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	if ((opts == 0) && (DCMD_HDRSPEC(flags))) {
5250Sstevel@tonic-gate 		mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n",
5260Sstevel@tonic-gate 		    "MI_O", "Next", "Prev");
5270Sstevel@tonic-gate 	}
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	if (mdb_vread(&mio, sizeof (mio), addr) == -1) {
5300Sstevel@tonic-gate 		mdb_warn("failed to read mi object MI_O at %p", addr);
5310Sstevel@tonic-gate 		return (DCMD_ERR);
5320Sstevel@tonic-gate 	}
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	if (opts != 0) {
5350Sstevel@tonic-gate 		if (mio.mi_o_isdev == B_FALSE) {
5360Sstevel@tonic-gate 			/* mio is a module */
5370Sstevel@tonic-gate 			if (!(opts & MI_MODULE) && (opts & MI_DEVICE))
5380Sstevel@tonic-gate 				return (DCMD_OK);
5390Sstevel@tonic-gate 		} else {
5400Sstevel@tonic-gate 			/* mio is a device */
5410Sstevel@tonic-gate 			if (!(opts & MI_DEVICE) && (opts & MI_MODULE))
5420Sstevel@tonic-gate 				return (DCMD_OK);
5430Sstevel@tonic-gate 		}
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 		if (opts & MI_PAYLOAD)
5460Sstevel@tonic-gate 			mdb_printf("%p\n", addr + sizeof (MI_O));
5470Sstevel@tonic-gate 		else
5480Sstevel@tonic-gate 			mdb_printf("%p\n", addr);
5490Sstevel@tonic-gate 		return (DCMD_OK);
5500Sstevel@tonic-gate 	}
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev);
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	if (mio.mi_o_isdev == B_FALSE)
5550Sstevel@tonic-gate 		mdb_printf("FALSE");
5560Sstevel@tonic-gate 	else
5570Sstevel@tonic-gate 		mdb_printf("TRUE ");
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	mdb_printf(" %0?p\n", mio.mi_o_dev);
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	return (DCMD_OK);
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate 
5643448Sdh155122 static int
ns_to_stackid(uintptr_t kaddr)5653448Sdh155122 ns_to_stackid(uintptr_t kaddr)
5663448Sdh155122 {
5673448Sdh155122 	netstack_t nss;
5683448Sdh155122 
5693448Sdh155122 	if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
5703448Sdh155122 		mdb_warn("failed to read netstack_t %p", kaddr);
5713448Sdh155122 		return (0);
5723448Sdh155122 	}
5733448Sdh155122 	return (nss.netstack_stackid);
5743448Sdh155122 }
5753448Sdh155122 
5763448Sdh155122 
5773448Sdh155122 
5780Sstevel@tonic-gate static void
netstat_tcp_verbose_pr(const tcp_t * tcp)5790Sstevel@tonic-gate netstat_tcp_verbose_pr(const tcp_t *tcp)
5800Sstevel@tonic-gate {
5810Sstevel@tonic-gate 	mdb_printf("       %5i %08x %08x %5i %08x %08x %5li %5i\n",
5820Sstevel@tonic-gate 	    tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
5830Sstevel@tonic-gate 	    tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate /*ARGSUSED*/
5870Sstevel@tonic-gate static int
netstat_tcp_cb(uintptr_t kaddr,const void * walk_data,void * cb_data)5889089SVasumathi.Sundaram@Sun.COM netstat_tcp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
5890Sstevel@tonic-gate {
5909089SVasumathi.Sundaram@Sun.COM 	netstat_cb_data_t *ncb = cb_data;
5919089SVasumathi.Sundaram@Sun.COM 	uint_t opts = ncb->opts;
5929089SVasumathi.Sundaram@Sun.COM 	int af = ncb->af;
5930Sstevel@tonic-gate 	uintptr_t tcp_kaddr;
5949089SVasumathi.Sundaram@Sun.COM 	conn_t *connp = &ncb->conn;
5955563Snordmark 	tcp_t tcps, *tcp;
5960Sstevel@tonic-gate 
5979089SVasumathi.Sundaram@Sun.COM 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
5985563Snordmark 		mdb_warn("failed to read conn_t at %p", kaddr);
5995563Snordmark 		return (WALK_ERR);
6000Sstevel@tonic-gate 	}
6010Sstevel@tonic-gate 
6025563Snordmark 	tcp_kaddr = (uintptr_t)connp->conn_tcp;
6035563Snordmark 	if (mdb_vread(&tcps, sizeof (tcp_t), tcp_kaddr) == -1) {
60411042SErik.Nordmark@Sun.COM 		mdb_warn("failed to read tcp_t at %p", tcp_kaddr);
6050Sstevel@tonic-gate 		return (WALK_ERR);
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6085563Snordmark 	tcp = &tcps;
6090Sstevel@tonic-gate 	connp->conn_tcp = tcp;
6100Sstevel@tonic-gate 	tcp->tcp_connp = connp;
6110Sstevel@tonic-gate 
612741Smasputra 	if (!((opts & NETSTAT_ALL) || net_tcp_active(tcp)) ||
6130Sstevel@tonic-gate 	    (af == AF_INET && !net_tcp_ipv4(tcp)) ||
6140Sstevel@tonic-gate 	    (af == AF_INET6 && !net_tcp_ipv6(tcp))) {
6150Sstevel@tonic-gate 		return (WALK_NEXT);
6160Sstevel@tonic-gate 	}
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state);
6190Sstevel@tonic-gate 	if (af == AF_INET) {
62011042SErik.Nordmark@Sun.COM 		net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
6210Sstevel@tonic-gate 		mdb_printf(" ");
62211042SErik.Nordmark@Sun.COM 		net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
6230Sstevel@tonic-gate 	} else if (af == AF_INET6) {
62411042SErik.Nordmark@Sun.COM 		net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
6250Sstevel@tonic-gate 		mdb_printf(" ");
62611042SErik.Nordmark@Sun.COM 		net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
6270Sstevel@tonic-gate 	}
6289089SVasumathi.Sundaram@Sun.COM 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
6290Sstevel@tonic-gate 	mdb_printf(" %4i\n", connp->conn_zoneid);
6300Sstevel@tonic-gate 	if (opts & NETSTAT_VERBOSE)
6310Sstevel@tonic-gate 		netstat_tcp_verbose_pr(tcp);
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	return (WALK_NEXT);
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate 
636741Smasputra /*ARGSUSED*/
6370Sstevel@tonic-gate static int
netstat_udp_cb(uintptr_t kaddr,const void * walk_data,void * cb_data)6389089SVasumathi.Sundaram@Sun.COM netstat_udp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
6390Sstevel@tonic-gate {
6409089SVasumathi.Sundaram@Sun.COM 	netstat_cb_data_t *ncb = cb_data;
6419089SVasumathi.Sundaram@Sun.COM 	uint_t opts = ncb->opts;
6429089SVasumathi.Sundaram@Sun.COM 	int af = ncb->af;
643741Smasputra 	udp_t udp;
6449089SVasumathi.Sundaram@Sun.COM 	conn_t *connp = &ncb->conn;
6459089SVasumathi.Sundaram@Sun.COM 	char *state;
646741Smasputra 
6479089SVasumathi.Sundaram@Sun.COM 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
6485563Snordmark 		mdb_warn("failed to read conn_t at %p", kaddr);
649741Smasputra 		return (WALK_ERR);
650741Smasputra 	}
6510Sstevel@tonic-gate 
6525563Snordmark 	if (mdb_vread(&udp, sizeof (udp_t),
6539089SVasumathi.Sundaram@Sun.COM 	    (uintptr_t)connp->conn_udp) == -1) {
6545563Snordmark 		mdb_warn("failed to read conn_udp at %p",
6559089SVasumathi.Sundaram@Sun.COM 		    (uintptr_t)connp->conn_udp);
656741Smasputra 		return (WALK_ERR);
657741Smasputra 	}
6580Sstevel@tonic-gate 
65911042SErik.Nordmark@Sun.COM 	connp->conn_udp = &udp;
66011042SErik.Nordmark@Sun.COM 	udp.udp_connp = connp;
66111042SErik.Nordmark@Sun.COM 
662741Smasputra 	if (!((opts & NETSTAT_ALL) || net_udp_active(&udp)) ||
663741Smasputra 	    (af == AF_INET && !net_udp_ipv4(&udp)) ||
664741Smasputra 	    (af == AF_INET6 && !net_udp_ipv6(&udp))) {
665741Smasputra 		return (WALK_NEXT);
666741Smasputra 	}
667741Smasputra 
6689089SVasumathi.Sundaram@Sun.COM 	if (udp.udp_state == TS_UNBND)
6699089SVasumathi.Sundaram@Sun.COM 		state = "UNBOUND";
6709089SVasumathi.Sundaram@Sun.COM 	else if (udp.udp_state == TS_IDLE)
6719089SVasumathi.Sundaram@Sun.COM 		state = "IDLE";
6729089SVasumathi.Sundaram@Sun.COM 	else if (udp.udp_state == TS_DATA_XFER)
6739089SVasumathi.Sundaram@Sun.COM 		state = "CONNECTED";
6749089SVasumathi.Sundaram@Sun.COM 	else
6759089SVasumathi.Sundaram@Sun.COM 		state = "UNKNOWN";
6769089SVasumathi.Sundaram@Sun.COM 
6779089SVasumathi.Sundaram@Sun.COM 	mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_udp, state);
678741Smasputra 	if (af == AF_INET) {
67911042SErik.Nordmark@Sun.COM 		net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
680741Smasputra 		mdb_printf(" ");
68111042SErik.Nordmark@Sun.COM 		net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
682741Smasputra 	} else if (af == AF_INET6) {
68311042SErik.Nordmark@Sun.COM 		net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
684741Smasputra 		mdb_printf(" ");
68511042SErik.Nordmark@Sun.COM 		net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
686741Smasputra 	}
6879089SVasumathi.Sundaram@Sun.COM 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
6889089SVasumathi.Sundaram@Sun.COM 	mdb_printf(" %4i\n", connp->conn_zoneid);
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	return (WALK_NEXT);
6910Sstevel@tonic-gate }
6920Sstevel@tonic-gate 
6939089SVasumathi.Sundaram@Sun.COM /*ARGSUSED*/
6940Sstevel@tonic-gate static int
netstat_icmp_cb(uintptr_t kaddr,const void * walk_data,void * cb_data)6959089SVasumathi.Sundaram@Sun.COM netstat_icmp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
696741Smasputra {
6979089SVasumathi.Sundaram@Sun.COM 	netstat_cb_data_t *ncb = cb_data;
6989089SVasumathi.Sundaram@Sun.COM 	int af = ncb->af;
6999089SVasumathi.Sundaram@Sun.COM 	icmp_t icmp;
7009089SVasumathi.Sundaram@Sun.COM 	conn_t *connp = &ncb->conn;
7019089SVasumathi.Sundaram@Sun.COM 	char *state;
7029089SVasumathi.Sundaram@Sun.COM 
7039089SVasumathi.Sundaram@Sun.COM 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
7049089SVasumathi.Sundaram@Sun.COM 		mdb_warn("failed to read conn_t at %p", kaddr);
7059089SVasumathi.Sundaram@Sun.COM 		return (WALK_ERR);
7069089SVasumathi.Sundaram@Sun.COM 	}
7079089SVasumathi.Sundaram@Sun.COM 
7089089SVasumathi.Sundaram@Sun.COM 	if (mdb_vread(&icmp, sizeof (icmp_t),
7099089SVasumathi.Sundaram@Sun.COM 	    (uintptr_t)connp->conn_icmp) == -1) {
7109089SVasumathi.Sundaram@Sun.COM 		mdb_warn("failed to read conn_icmp at %p",
7119089SVasumathi.Sundaram@Sun.COM 		    (uintptr_t)connp->conn_icmp);
7129089SVasumathi.Sundaram@Sun.COM 		return (WALK_ERR);
7139089SVasumathi.Sundaram@Sun.COM 	}
7149089SVasumathi.Sundaram@Sun.COM 
71511042SErik.Nordmark@Sun.COM 	connp->conn_icmp = &icmp;
71611042SErik.Nordmark@Sun.COM 	icmp.icmp_connp = connp;
71711042SErik.Nordmark@Sun.COM 
71811042SErik.Nordmark@Sun.COM 	if ((af == AF_INET && connp->conn_ipversion != IPV4_VERSION) ||
71911042SErik.Nordmark@Sun.COM 	    (af == AF_INET6 && connp->conn_ipversion != IPV6_VERSION)) {
7209089SVasumathi.Sundaram@Sun.COM 		return (WALK_NEXT);
7219089SVasumathi.Sundaram@Sun.COM 	}
722741Smasputra 
7239089SVasumathi.Sundaram@Sun.COM 	if (icmp.icmp_state == TS_UNBND)
7249089SVasumathi.Sundaram@Sun.COM 		state = "UNBOUND";
7259089SVasumathi.Sundaram@Sun.COM 	else if (icmp.icmp_state == TS_IDLE)
7269089SVasumathi.Sundaram@Sun.COM 		state = "IDLE";
7279089SVasumathi.Sundaram@Sun.COM 	else if (icmp.icmp_state == TS_DATA_XFER)
7289089SVasumathi.Sundaram@Sun.COM 		state = "CONNECTED";
7299089SVasumathi.Sundaram@Sun.COM 	else
7309089SVasumathi.Sundaram@Sun.COM 		state = "UNKNOWN";
7319089SVasumathi.Sundaram@Sun.COM 
7329089SVasumathi.Sundaram@Sun.COM 	mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_icmp, state);
7339089SVasumathi.Sundaram@Sun.COM 	if (af == AF_INET) {
73411042SErik.Nordmark@Sun.COM 		net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
73511042SErik.Nordmark@Sun.COM 		mdb_printf(" ");
73611042SErik.Nordmark@Sun.COM 		net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
7379089SVasumathi.Sundaram@Sun.COM 	} else if (af == AF_INET6) {
73811042SErik.Nordmark@Sun.COM 		net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
73911042SErik.Nordmark@Sun.COM 		mdb_printf(" ");
74011042SErik.Nordmark@Sun.COM 		net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
7419089SVasumathi.Sundaram@Sun.COM 	}
7429089SVasumathi.Sundaram@Sun.COM 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
74311042SErik.Nordmark@Sun.COM 	mdb_printf(" %4i\n", connp->conn_zoneid);
7449089SVasumathi.Sundaram@Sun.COM 
7459089SVasumathi.Sundaram@Sun.COM 	return (WALK_NEXT);
7460Sstevel@tonic-gate }
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate /*
7490Sstevel@tonic-gate  * print the address of a unix domain socket
7500Sstevel@tonic-gate  *
7510Sstevel@tonic-gate  * so is the address of a AF_UNIX struct sonode in mdb's address space
7520Sstevel@tonic-gate  * soa is the address of the struct soaddr to print
7530Sstevel@tonic-gate  *
7540Sstevel@tonic-gate  * returns 0 on success, -1 otherwise
7550Sstevel@tonic-gate  */
7560Sstevel@tonic-gate static int
netstat_unix_name_pr(const struct sotpi_sonode * st,const struct soaddr * soa)7578348SEric.Yu@Sun.COM netstat_unix_name_pr(const struct sotpi_sonode *st, const struct soaddr *soa)
7580Sstevel@tonic-gate {
7598348SEric.Yu@Sun.COM 	const struct sonode *so = &st->st_sonode;
7600Sstevel@tonic-gate 	const char none[] = " (none)";
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) {
7638348SEric.Yu@Sun.COM 		if (st->st_info.sti_faddr_noxlate) {
7640Sstevel@tonic-gate 			mdb_printf("%-14s ", " (socketpair)");
7650Sstevel@tonic-gate 		} else {
7660Sstevel@tonic-gate 			if (soa->soa_len > sizeof (sa_family_t)) {
7670Sstevel@tonic-gate 				char addr[MAXPATHLEN + 1];
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 				if (mdb_readstr(addr, sizeof (addr),
7700Sstevel@tonic-gate 				    (uintptr_t)&soa->soa_sa->sa_data) == -1) {
7710Sstevel@tonic-gate 					mdb_warn("failed to read unix address "
7720Sstevel@tonic-gate 					    "at %p", &soa->soa_sa->sa_data);
7730Sstevel@tonic-gate 					return (-1);
7740Sstevel@tonic-gate 				}
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 				mdb_printf("%-14s ", addr);
7770Sstevel@tonic-gate 			} else {
7780Sstevel@tonic-gate 				mdb_printf("%-14s ", none);
7790Sstevel@tonic-gate 			}
7800Sstevel@tonic-gate 		}
7810Sstevel@tonic-gate 	} else {
7820Sstevel@tonic-gate 		mdb_printf("%-14s ", none);
7830Sstevel@tonic-gate 	}
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	return (0);
7860Sstevel@tonic-gate }
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate /* based on sockfs_snapshot */
7890Sstevel@tonic-gate /*ARGSUSED*/
7900Sstevel@tonic-gate static int
netstat_unix_cb(uintptr_t kaddr,const void * walk_data,void * cb_data)7910Sstevel@tonic-gate netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
7920Sstevel@tonic-gate {
7938348SEric.Yu@Sun.COM 	const struct sotpi_sonode *st = walk_data;
7948348SEric.Yu@Sun.COM 	const struct sonode *so = &st->st_sonode;
7958348SEric.Yu@Sun.COM 	const struct sotpi_info *sti = &st->st_info;
7960Sstevel@tonic-gate 
7978348SEric.Yu@Sun.COM 	if (so->so_count == 0)
7980Sstevel@tonic-gate 		return (WALK_NEXT);
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	if (so->so_family != AF_UNIX) {
8010Sstevel@tonic-gate 		mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr);
8020Sstevel@tonic-gate 		return (WALK_ERR);
8030Sstevel@tonic-gate 	}
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	mdb_printf("%-?p ", kaddr);
8060Sstevel@tonic-gate 
8078348SEric.Yu@Sun.COM 	switch (sti->sti_serv_type) {
8085563Snordmark 	case T_CLTS:
8090Sstevel@tonic-gate 		mdb_printf("%-10s ", "dgram");
8100Sstevel@tonic-gate 		break;
8115563Snordmark 	case T_COTS:
8120Sstevel@tonic-gate 		mdb_printf("%-10s ", "stream");
8130Sstevel@tonic-gate 		break;
8145563Snordmark 	case T_COTS_ORD:
8150Sstevel@tonic-gate 		mdb_printf("%-10s ", "stream-ord");
8160Sstevel@tonic-gate 		break;
8175563Snordmark 	default:
8188348SEric.Yu@Sun.COM 		mdb_printf("%-10i ", sti->sti_serv_type);
8190Sstevel@tonic-gate 	}
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	if ((so->so_state & SS_ISBOUND) &&
8228348SEric.Yu@Sun.COM 	    (sti->sti_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
8238348SEric.Yu@Sun.COM 		mdb_printf("%0?p ", sti->sti_ux_laddr.soua_vp);
8240Sstevel@tonic-gate 	} else {
8250Sstevel@tonic-gate 		mdb_printf("%0?p ", NULL);
8260Sstevel@tonic-gate 	}
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	if ((so->so_state & SS_ISCONNECTED) &&
8298348SEric.Yu@Sun.COM 	    (sti->sti_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
8308348SEric.Yu@Sun.COM 		mdb_printf("%0?p ", sti->sti_ux_faddr.soua_vp);
8310Sstevel@tonic-gate 	} else {
8320Sstevel@tonic-gate 		mdb_printf("%0?p ", NULL);
8330Sstevel@tonic-gate 	}
8340Sstevel@tonic-gate 
8358348SEric.Yu@Sun.COM 	if (netstat_unix_name_pr(st, &sti->sti_laddr) == -1)
8360Sstevel@tonic-gate 		return (WALK_ERR);
8370Sstevel@tonic-gate 
8388348SEric.Yu@Sun.COM 	if (netstat_unix_name_pr(st, &sti->sti_faddr) == -1)
8390Sstevel@tonic-gate 		return (WALK_ERR);
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	mdb_printf("%4i\n", so->so_zoneid);
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	return (WALK_NEXT);
8440Sstevel@tonic-gate }
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate static void
netstat_tcp_verbose_header_pr(void)8470Sstevel@tonic-gate netstat_tcp_verbose_header_pr(void)
8480Sstevel@tonic-gate {
8490Sstevel@tonic-gate 	mdb_printf("       %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n",
8500Sstevel@tonic-gate 	    "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss");
8510Sstevel@tonic-gate }
8520Sstevel@tonic-gate 
8531676Sjpk static void
get_ifname(const ire_t * ire,char * intf)8541676Sjpk get_ifname(const ire_t *ire, char *intf)
8551676Sjpk {
8561676Sjpk 	ill_t ill;
8571676Sjpk 
8581676Sjpk 	*intf = '\0';
85911042SErik.Nordmark@Sun.COM 	if (ire->ire_ill != NULL) {
86011042SErik.Nordmark@Sun.COM 		if (mdb_vread(&ill, sizeof (ill),
86111042SErik.Nordmark@Sun.COM 		    (uintptr_t)ire->ire_ill) == -1)
8621676Sjpk 			return;
8631676Sjpk 		(void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
8641676Sjpk 		    (uintptr_t)ill.ill_name);
8651676Sjpk 	}
8661676Sjpk }
8671676Sjpk 
86811042SErik.Nordmark@Sun.COM const in6_addr_t ipv6_all_ones =
86911042SErik.Nordmark@Sun.COM 	{ 0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU };
87011042SErik.Nordmark@Sun.COM 
8711676Sjpk static void
get_ireflags(const ire_t * ire,char * flags)87211042SErik.Nordmark@Sun.COM get_ireflags(const ire_t *ire, char *flags)
8731676Sjpk {
8741676Sjpk 	(void) strcpy(flags, "U");
87511042SErik.Nordmark@Sun.COM 	/* RTF_INDIRECT wins over RTF_GATEWAY - don't display both */
87611042SErik.Nordmark@Sun.COM 	if (ire->ire_flags & RTF_INDIRECT)
87711042SErik.Nordmark@Sun.COM 		(void) strcat(flags, "I");
87811042SErik.Nordmark@Sun.COM 	else if (ire->ire_type & IRE_OFFLINK)
8791676Sjpk 		(void) strcat(flags, "G");
88011042SErik.Nordmark@Sun.COM 
88111042SErik.Nordmark@Sun.COM 	/* IRE_IF_CLONE wins over RTF_HOST - don't display both */
88211042SErik.Nordmark@Sun.COM 	if (ire->ire_type & IRE_IF_CLONE)
88311042SErik.Nordmark@Sun.COM 		(void) strcat(flags, "C");
88411042SErik.Nordmark@Sun.COM 	else if (ire->ire_ipversion == IPV4_VERSION) {
88511042SErik.Nordmark@Sun.COM 		if (ire->ire_mask == IP_HOST_MASK)
88611042SErik.Nordmark@Sun.COM 			(void) strcat(flags, "H");
88711042SErik.Nordmark@Sun.COM 	} else {
88811042SErik.Nordmark@Sun.COM 		if (IN6_ARE_ADDR_EQUAL(&ire->ire_mask_v6, &ipv6_all_ones))
88911042SErik.Nordmark@Sun.COM 			(void) strcat(flags, "H");
89011042SErik.Nordmark@Sun.COM 	}
89111042SErik.Nordmark@Sun.COM 
89211042SErik.Nordmark@Sun.COM 	if (ire->ire_flags & RTF_DYNAMIC)
8931676Sjpk 		(void) strcat(flags, "D");
8941676Sjpk 	if (ire->ire_type == IRE_BROADCAST)
89511042SErik.Nordmark@Sun.COM 		(void) strcat(flags, "b");
89611042SErik.Nordmark@Sun.COM 	if (ire->ire_type == IRE_MULTICAST)
89711042SErik.Nordmark@Sun.COM 		(void) strcat(flags, "m");
8981676Sjpk 	if (ire->ire_type == IRE_LOCAL)
8991676Sjpk 		(void) strcat(flags, "L");
90011042SErik.Nordmark@Sun.COM 	if (ire->ire_type == IRE_NOROUTE)
90111042SErik.Nordmark@Sun.COM 		(void) strcat(flags, "N");
9021676Sjpk 	if (ire->ire_flags & RTF_MULTIRT)
9031676Sjpk 		(void) strcat(flags, "M");
9041676Sjpk 	if (ire->ire_flags & RTF_SETSRC)
9051676Sjpk 		(void) strcat(flags, "S");
90611042SErik.Nordmark@Sun.COM 	if (ire->ire_flags & RTF_REJECT)
90711042SErik.Nordmark@Sun.COM 		(void) strcat(flags, "R");
90811042SErik.Nordmark@Sun.COM 	if (ire->ire_flags & RTF_BLACKHOLE)
90911042SErik.Nordmark@Sun.COM 		(void) strcat(flags, "B");
9101676Sjpk }
9111676Sjpk 
9121676Sjpk static int
netstat_irev4_cb(uintptr_t kaddr,const void * walk_data,void * cb_data)9131676Sjpk netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
9141676Sjpk {
9151676Sjpk 	const ire_t *ire = walk_data;
9161676Sjpk 	uint_t *opts = cb_data;
9171676Sjpk 	ipaddr_t gate;
9181676Sjpk 	char flags[10], intf[LIFNAMSIZ + 1];
9191676Sjpk 
9204823Sseb 	if (ire->ire_ipversion != IPV4_VERSION)
9211676Sjpk 		return (WALK_NEXT);
9221676Sjpk 
92311042SErik.Nordmark@Sun.COM 	/* Skip certain IREs by default */
92411042SErik.Nordmark@Sun.COM 	if (!(*opts & NETSTAT_ALL) &&
92511042SErik.Nordmark@Sun.COM 	    (ire->ire_type &
92611042SErik.Nordmark@Sun.COM 	    (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE)))
9271676Sjpk 		return (WALK_NEXT);
9281676Sjpk 
9291676Sjpk 	if (*opts & NETSTAT_FIRST) {
9301676Sjpk 		*opts &= ~NETSTAT_FIRST;
9311676Sjpk 		mdb_printf("%<u>%s Table: IPv4%</u>\n",
9321676Sjpk 		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
9331676Sjpk 		if (*opts & NETSTAT_VERBOSE) {
9341676Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt  "
9351676Sjpk 			    " Ref Flg Out   In/Fwd%</u>\n",
9361676Sjpk 			    "Address", ADDR_V4_WIDTH, "Destination",
9371676Sjpk 			    ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway");
9381676Sjpk 		} else {
9391676Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref  Use   "
9401676Sjpk 			    "Interface%</u>\n",
9411676Sjpk 			    "Address", ADDR_V4_WIDTH, "Destination",
9421676Sjpk 			    ADDR_V4_WIDTH, "Gateway");
9431676Sjpk 		}
9441676Sjpk 	}
9451676Sjpk 
94611042SErik.Nordmark@Sun.COM 	gate = ire->ire_gateway_addr;
9471676Sjpk 
94811042SErik.Nordmark@Sun.COM 	get_ireflags(ire, flags);
9491676Sjpk 
9501676Sjpk 	get_ifname(ire, intf);
9511676Sjpk 
9521676Sjpk 	if (*opts & NETSTAT_VERBOSE) {
9531676Sjpk 		mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u "
9541676Sjpk 		    "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH,
9551676Sjpk 		    ire->ire_mask, ADDR_V4_WIDTH, gate, intf,
95611042SErik.Nordmark@Sun.COM 		    0, ' ',
95711042SErik.Nordmark@Sun.COM 		    ire->ire_metrics.iulp_rtt, ire->ire_refcnt, flags,
9581676Sjpk 		    ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
9591676Sjpk 	} else {
9601676Sjpk 		mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr,
9611676Sjpk 		    ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags,
9621676Sjpk 		    ire->ire_refcnt,
9631676Sjpk 		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
9641676Sjpk 	}
9651676Sjpk 
9661676Sjpk 	return (WALK_NEXT);
9671676Sjpk }
9681676Sjpk 
9691676Sjpk int
ip_mask_to_plen_v6(const in6_addr_t * v6mask)9701676Sjpk ip_mask_to_plen_v6(const in6_addr_t *v6mask)
9711676Sjpk {
9721676Sjpk 	int plen;
9731676Sjpk 	int i;
9741676Sjpk 	uint32_t val;
9751676Sjpk 
9761676Sjpk 	for (i = 3; i >= 0; i--)
9771676Sjpk 		if (v6mask->s6_addr32[i] != 0)
9781676Sjpk 			break;
9791676Sjpk 	if (i < 0)
9801676Sjpk 		return (0);
9811676Sjpk 	plen = 32 + 32 * i;
9821676Sjpk 	val = v6mask->s6_addr32[i];
9831676Sjpk 	while (!(val & 1)) {
9841676Sjpk 		val >>= 1;
9851676Sjpk 		plen--;
9861676Sjpk 	}
9871676Sjpk 
9881676Sjpk 	return (plen);
9891676Sjpk }
9901676Sjpk 
9911676Sjpk static int
netstat_irev6_cb(uintptr_t kaddr,const void * walk_data,void * cb_data)9921676Sjpk netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
9931676Sjpk {
9941676Sjpk 	const ire_t *ire = walk_data;
9951676Sjpk 	uint_t *opts = cb_data;
9961676Sjpk 	const in6_addr_t *gatep;
9971676Sjpk 	char deststr[ADDR_V6_WIDTH + 5];
9981676Sjpk 	char flags[10], intf[LIFNAMSIZ + 1];
9991676Sjpk 	int masklen;
10001676Sjpk 
10011676Sjpk 	if (ire->ire_ipversion != IPV6_VERSION)
10021676Sjpk 		return (WALK_NEXT);
10031676Sjpk 
100411042SErik.Nordmark@Sun.COM 	/* Skip certain IREs by default */
100511042SErik.Nordmark@Sun.COM 	if (!(*opts & NETSTAT_ALL) &&
100611042SErik.Nordmark@Sun.COM 	    (ire->ire_type &
100711042SErik.Nordmark@Sun.COM 	    (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE)))
10081676Sjpk 		return (WALK_NEXT);
10091676Sjpk 
10101676Sjpk 	if (*opts & NETSTAT_FIRST) {
10111676Sjpk 		*opts &= ~NETSTAT_FIRST;
10121676Sjpk 		mdb_printf("\n%<u>%s Table: IPv6%</u>\n",
10131676Sjpk 		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
10141676Sjpk 		if (*opts & NETSTAT_VERBOSE) {
10151676Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s If    PMTU   Rtt   Ref "
10161676Sjpk 			    "Flags Out    In/Fwd%</u>\n",
10171676Sjpk 			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
10181676Sjpk 			    ADDR_V6_WIDTH, "Gateway");
10191676Sjpk 		} else {
10201676Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use    If"
10211676Sjpk 			    "%</u>\n",
10221676Sjpk 			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
10231676Sjpk 			    ADDR_V6_WIDTH, "Gateway");
10241676Sjpk 		}
10251676Sjpk 	}
10261676Sjpk 
102711042SErik.Nordmark@Sun.COM 	gatep = &ire->ire_gateway_addr_v6;
10281676Sjpk 
10291676Sjpk 	masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6);
10301676Sjpk 	(void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d",
10311676Sjpk 	    &ire->ire_addr_v6, masklen);
10321676Sjpk 
103311042SErik.Nordmark@Sun.COM 	get_ireflags(ire, flags);
10341676Sjpk 
10351676Sjpk 	get_ifname(ire, intf);
10361676Sjpk 
10371676Sjpk 	if (*opts & NETSTAT_VERBOSE) {
10381676Sjpk 		mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n",
10391676Sjpk 		    kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep,
104011042SErik.Nordmark@Sun.COM 		    intf, 0, ' ',
104111042SErik.Nordmark@Sun.COM 		    ire->ire_metrics.iulp_rtt, ire->ire_refcnt,
10421676Sjpk 		    flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
10431676Sjpk 	} else {
10441676Sjpk 		mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr,
10451676Sjpk 		    ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags,
10461676Sjpk 		    ire->ire_refcnt,
10471676Sjpk 		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
10481676Sjpk 	}
10491676Sjpk 
10501676Sjpk 	return (WALK_NEXT);
10511676Sjpk }
10521676Sjpk 
10539089SVasumathi.Sundaram@Sun.COM static void
netstat_header_v4(int proto)10549089SVasumathi.Sundaram@Sun.COM netstat_header_v4(int proto)
10559089SVasumathi.Sundaram@Sun.COM {
10569089SVasumathi.Sundaram@Sun.COM 	if (proto == IPPROTO_TCP)
10579089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%<u>%-?s ", "TCPv4");
10589089SVasumathi.Sundaram@Sun.COM 	else if (proto == IPPROTO_UDP)
10599089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%<u>%-?s ", "UDPv4");
10609089SVasumathi.Sundaram@Sun.COM 	else if (proto == IPPROTO_ICMP)
10619089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%<u>%-?s ", "ICMPv4");
10629089SVasumathi.Sundaram@Sun.COM 	mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
10639089SVasumathi.Sundaram@Sun.COM 	    "", ADDR_V4_WIDTH, "Local Address",
10649089SVasumathi.Sundaram@Sun.COM 	    "", ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone");
10659089SVasumathi.Sundaram@Sun.COM }
10669089SVasumathi.Sundaram@Sun.COM 
10679089SVasumathi.Sundaram@Sun.COM static void
netstat_header_v6(int proto)10689089SVasumathi.Sundaram@Sun.COM netstat_header_v6(int proto)
10699089SVasumathi.Sundaram@Sun.COM {
10709089SVasumathi.Sundaram@Sun.COM 	if (proto == IPPROTO_TCP)
10719089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%<u>%-?s ", "TCPv6");
10729089SVasumathi.Sundaram@Sun.COM 	else if (proto == IPPROTO_UDP)
10739089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%<u>%-?s ", "UDPv6");
10749089SVasumathi.Sundaram@Sun.COM 	else if (proto == IPPROTO_ICMP)
10759089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%<u>%-?s ", "ICMPv6");
10769089SVasumathi.Sundaram@Sun.COM 	mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
10779089SVasumathi.Sundaram@Sun.COM 	    "", ADDR_V6_WIDTH, "Local Address",
10789089SVasumathi.Sundaram@Sun.COM 	    "", ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone");
10799089SVasumathi.Sundaram@Sun.COM }
10809089SVasumathi.Sundaram@Sun.COM 
10819089SVasumathi.Sundaram@Sun.COM static int
netstat_print_conn(const char * cache,int proto,mdb_walk_cb_t cbfunc,void * cbdata)10829089SVasumathi.Sundaram@Sun.COM netstat_print_conn(const char *cache, int proto, mdb_walk_cb_t cbfunc,
10839089SVasumathi.Sundaram@Sun.COM     void *cbdata)
10849089SVasumathi.Sundaram@Sun.COM {
10859089SVasumathi.Sundaram@Sun.COM 	netstat_cb_data_t *ncb = cbdata;
10869089SVasumathi.Sundaram@Sun.COM 
10879089SVasumathi.Sundaram@Sun.COM 	if ((ncb->opts & NETSTAT_VERBOSE) && proto == IPPROTO_TCP)
10889089SVasumathi.Sundaram@Sun.COM 		netstat_tcp_verbose_header_pr();
10899089SVasumathi.Sundaram@Sun.COM 	if (mdb_walk(cache, cbfunc, cbdata) == -1) {
10909089SVasumathi.Sundaram@Sun.COM 		mdb_warn("failed to walk %s", cache);
10919089SVasumathi.Sundaram@Sun.COM 		return (DCMD_ERR);
10929089SVasumathi.Sundaram@Sun.COM 	}
10939089SVasumathi.Sundaram@Sun.COM 	return (DCMD_OK);
10949089SVasumathi.Sundaram@Sun.COM }
10959089SVasumathi.Sundaram@Sun.COM 
10969089SVasumathi.Sundaram@Sun.COM static int
netstat_print_common(const char * cache,int proto,mdb_walk_cb_t cbfunc,void * cbdata)10979089SVasumathi.Sundaram@Sun.COM netstat_print_common(const char *cache, int proto, mdb_walk_cb_t cbfunc,
10989089SVasumathi.Sundaram@Sun.COM     void *cbdata)
10999089SVasumathi.Sundaram@Sun.COM {
11009089SVasumathi.Sundaram@Sun.COM 	netstat_cb_data_t *ncb = cbdata;
11019089SVasumathi.Sundaram@Sun.COM 	int af = ncb->af;
11029089SVasumathi.Sundaram@Sun.COM 	int status = DCMD_OK;
11039089SVasumathi.Sundaram@Sun.COM 
11049089SVasumathi.Sundaram@Sun.COM 	if (af != AF_INET6) {
11059089SVasumathi.Sundaram@Sun.COM 		ncb->af = AF_INET;
11069089SVasumathi.Sundaram@Sun.COM 		netstat_header_v4(proto);
11079089SVasumathi.Sundaram@Sun.COM 		status = netstat_print_conn(cache, proto, cbfunc, cbdata);
11089089SVasumathi.Sundaram@Sun.COM 	}
11099089SVasumathi.Sundaram@Sun.COM 	if (status == DCMD_OK && af != AF_INET) {
11109089SVasumathi.Sundaram@Sun.COM 		ncb->af = AF_INET6;
11119089SVasumathi.Sundaram@Sun.COM 		netstat_header_v6(proto);
11129089SVasumathi.Sundaram@Sun.COM 		status = netstat_print_conn(cache, proto, cbfunc, cbdata);
11139089SVasumathi.Sundaram@Sun.COM 	}
11149089SVasumathi.Sundaram@Sun.COM 	ncb->af = af;
11159089SVasumathi.Sundaram@Sun.COM 	return (status);
11169089SVasumathi.Sundaram@Sun.COM }
11179089SVasumathi.Sundaram@Sun.COM 
11180Sstevel@tonic-gate /*ARGSUSED*/
11190Sstevel@tonic-gate int
netstat(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)11200Sstevel@tonic-gate netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
11210Sstevel@tonic-gate {
11220Sstevel@tonic-gate 	uint_t opts = 0;
11230Sstevel@tonic-gate 	const char *optf = NULL;
11240Sstevel@tonic-gate 	const char *optP = NULL;
11259089SVasumathi.Sundaram@Sun.COM 	netstat_cb_data_t *cbdata;
11269089SVasumathi.Sundaram@Sun.COM 	int status;
11279089SVasumathi.Sundaram@Sun.COM 	int af = 0;
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
11300Sstevel@tonic-gate 	    'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts,
11310Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &optf,
11320Sstevel@tonic-gate 	    'P', MDB_OPT_STR, &optP,
11331676Sjpk 	    'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts,
11341676Sjpk 	    'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts,
11350Sstevel@tonic-gate 	    NULL) != argc)
11360Sstevel@tonic-gate 		return (DCMD_USAGE);
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 	if (optP != NULL) {
11399089SVasumathi.Sundaram@Sun.COM 		if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0) &&
11409089SVasumathi.Sundaram@Sun.COM 		    (strcmp("icmp", optP) != 0))
11410Sstevel@tonic-gate 			return (DCMD_USAGE);
11421676Sjpk 		if (opts & NETSTAT_ROUTE)
11431676Sjpk 			return (DCMD_USAGE);
11440Sstevel@tonic-gate 	}
11450Sstevel@tonic-gate 
11461676Sjpk 	if (optf == NULL)
11471676Sjpk 		opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX;
11481676Sjpk 	else if (strcmp("inet", optf) == 0)
11491676Sjpk 		opts |= NETSTAT_V4;
11501676Sjpk 	else if (strcmp("inet6", optf) == 0)
11511676Sjpk 		opts |= NETSTAT_V6;
11521676Sjpk 	else if (strcmp("unix", optf) == 0)
11531676Sjpk 		opts |= NETSTAT_UNIX;
11541676Sjpk 	else
11551676Sjpk 		return (DCMD_USAGE);
11561676Sjpk 
11571676Sjpk 	if (opts & NETSTAT_ROUTE) {
11581676Sjpk 		if (!(opts & (NETSTAT_V4|NETSTAT_V6)))
11590Sstevel@tonic-gate 			return (DCMD_USAGE);
11601676Sjpk 		if (opts & NETSTAT_V4) {
11611676Sjpk 			opts |= NETSTAT_FIRST;
11621676Sjpk 			if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) {
11631676Sjpk 				mdb_warn("failed to walk ip`ire");
11641676Sjpk 				return (DCMD_ERR);
11651676Sjpk 			}
11661676Sjpk 		}
11671676Sjpk 		if (opts & NETSTAT_V6) {
11681676Sjpk 			opts |= NETSTAT_FIRST;
11691676Sjpk 			if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) {
11701676Sjpk 				mdb_warn("failed to walk ip`ire");
11711676Sjpk 				return (DCMD_ERR);
11721676Sjpk 			}
11731676Sjpk 		}
11741676Sjpk 		return (DCMD_OK);
11750Sstevel@tonic-gate 	}
11760Sstevel@tonic-gate 
11779089SVasumathi.Sundaram@Sun.COM 	if ((opts & NETSTAT_UNIX) && (optP == NULL)) {
11780Sstevel@tonic-gate 		/* Print Unix Domain Sockets */
11790Sstevel@tonic-gate 		mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n",
11800Sstevel@tonic-gate 		    "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr",
11810Sstevel@tonic-gate 		    "Remote Addr", "Zone");
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 		if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) {
11840Sstevel@tonic-gate 			mdb_warn("failed to walk genunix`sonode");
11850Sstevel@tonic-gate 			return (DCMD_ERR);
11860Sstevel@tonic-gate 		}
11879089SVasumathi.Sundaram@Sun.COM 		if (!(opts & (NETSTAT_V4 | NETSTAT_V6)))
11889089SVasumathi.Sundaram@Sun.COM 			return (DCMD_OK);
11890Sstevel@tonic-gate 	}
11900Sstevel@tonic-gate 
11919089SVasumathi.Sundaram@Sun.COM 	cbdata = mdb_alloc(sizeof (netstat_cb_data_t), UM_SLEEP);
11929089SVasumathi.Sundaram@Sun.COM 	cbdata->opts = opts;
11939089SVasumathi.Sundaram@Sun.COM 	if ((optf != NULL) && (opts & NETSTAT_V4))
11949089SVasumathi.Sundaram@Sun.COM 		af = AF_INET;
11959089SVasumathi.Sundaram@Sun.COM 	else if ((optf != NULL) && (opts & NETSTAT_V6))
11969089SVasumathi.Sundaram@Sun.COM 		af = AF_INET6;
11979089SVasumathi.Sundaram@Sun.COM 
11989089SVasumathi.Sundaram@Sun.COM 	cbdata->af = af;
11999089SVasumathi.Sundaram@Sun.COM 	if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
12009089SVasumathi.Sundaram@Sun.COM 		status = netstat_print_common("tcp_conn_cache", IPPROTO_TCP,
12019089SVasumathi.Sundaram@Sun.COM 		    netstat_tcp_cb, cbdata);
12029089SVasumathi.Sundaram@Sun.COM 		if (status != DCMD_OK)
12039089SVasumathi.Sundaram@Sun.COM 			goto out;
12049089SVasumathi.Sundaram@Sun.COM 	}
12059089SVasumathi.Sundaram@Sun.COM 
12069089SVasumathi.Sundaram@Sun.COM 	if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
12079089SVasumathi.Sundaram@Sun.COM 		status = netstat_print_common("udp_conn_cache", IPPROTO_UDP,
12089089SVasumathi.Sundaram@Sun.COM 		    netstat_udp_cb, cbdata);
12099089SVasumathi.Sundaram@Sun.COM 		if (status != DCMD_OK)
12109089SVasumathi.Sundaram@Sun.COM 			goto out;
12119089SVasumathi.Sundaram@Sun.COM 	}
12129089SVasumathi.Sundaram@Sun.COM 
12139089SVasumathi.Sundaram@Sun.COM 	if ((optP == NULL) || (strcmp("icmp", optP) == 0)) {
12149089SVasumathi.Sundaram@Sun.COM 		status = netstat_print_common("rawip_conn_cache", IPPROTO_ICMP,
12159089SVasumathi.Sundaram@Sun.COM 		    netstat_icmp_cb, cbdata);
12169089SVasumathi.Sundaram@Sun.COM 		if (status != DCMD_OK)
12179089SVasumathi.Sundaram@Sun.COM 			goto out;
12189089SVasumathi.Sundaram@Sun.COM 	}
12199089SVasumathi.Sundaram@Sun.COM out:
12209089SVasumathi.Sundaram@Sun.COM 	mdb_free(cbdata, sizeof (netstat_cb_data_t));
12219089SVasumathi.Sundaram@Sun.COM 	return (status);
12220Sstevel@tonic-gate }
122310491SRishi.Srivatsavai@Sun.COM 
122410491SRishi.Srivatsavai@Sun.COM /*
122510491SRishi.Srivatsavai@Sun.COM  * "::dladm show-bridge" support
122610491SRishi.Srivatsavai@Sun.COM  */
122710491SRishi.Srivatsavai@Sun.COM typedef struct {
122810491SRishi.Srivatsavai@Sun.COM 	uint_t opt_l;
122910491SRishi.Srivatsavai@Sun.COM 	uint_t opt_f;
123010491SRishi.Srivatsavai@Sun.COM 	uint_t opt_t;
123110491SRishi.Srivatsavai@Sun.COM 	const char *name;
123210491SRishi.Srivatsavai@Sun.COM 	clock_t lbolt;
123310491SRishi.Srivatsavai@Sun.COM 	boolean_t found;
123410491SRishi.Srivatsavai@Sun.COM 	uint_t nlinks;
123510491SRishi.Srivatsavai@Sun.COM 	uint_t nfwd;
123610491SRishi.Srivatsavai@Sun.COM 
123710491SRishi.Srivatsavai@Sun.COM 	/*
123810491SRishi.Srivatsavai@Sun.COM 	 * These structures are kept inside the 'args' for allocation reasons.
123910491SRishi.Srivatsavai@Sun.COM 	 * They're all large data structures (over 1K), and may cause the stack
124010491SRishi.Srivatsavai@Sun.COM 	 * to explode.  mdb and kmdb will fail in these cases, and thus we
124110491SRishi.Srivatsavai@Sun.COM 	 * allocate them from the heap.
124210491SRishi.Srivatsavai@Sun.COM 	 */
124310491SRishi.Srivatsavai@Sun.COM 	trill_inst_t ti;
124410491SRishi.Srivatsavai@Sun.COM 	bridge_link_t bl;
124510491SRishi.Srivatsavai@Sun.COM 	mac_impl_t mi;
124610491SRishi.Srivatsavai@Sun.COM } show_bridge_args_t;
124710491SRishi.Srivatsavai@Sun.COM 
124810491SRishi.Srivatsavai@Sun.COM static void
show_vlans(const uint8_t * vlans)124910491SRishi.Srivatsavai@Sun.COM show_vlans(const uint8_t *vlans)
125010491SRishi.Srivatsavai@Sun.COM {
125110491SRishi.Srivatsavai@Sun.COM 	int i, bit;
125210491SRishi.Srivatsavai@Sun.COM 	uint8_t val;
125310491SRishi.Srivatsavai@Sun.COM 	int rstart = -1, rnext = -1;
125410491SRishi.Srivatsavai@Sun.COM 
125510491SRishi.Srivatsavai@Sun.COM 	for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) {
125610491SRishi.Srivatsavai@Sun.COM 		val = vlans[i];
125710491SRishi.Srivatsavai@Sun.COM 		if (i == 0)
125810491SRishi.Srivatsavai@Sun.COM 			val &= ~1;
125910491SRishi.Srivatsavai@Sun.COM 		while ((bit = mdb_ffs(val)) != 0) {
126010491SRishi.Srivatsavai@Sun.COM 			bit--;
126110491SRishi.Srivatsavai@Sun.COM 			val &= ~(1 << bit);
126210491SRishi.Srivatsavai@Sun.COM 			bit += i * sizeof (*vlans) * NBBY;
126310491SRishi.Srivatsavai@Sun.COM 			if (bit != rnext) {
126410491SRishi.Srivatsavai@Sun.COM 				if (rnext != -1 && rstart + 1 != rnext)
126510491SRishi.Srivatsavai@Sun.COM 					mdb_printf("-%d", rnext - 1);
126610491SRishi.Srivatsavai@Sun.COM 				if (rstart != -1)
126710491SRishi.Srivatsavai@Sun.COM 					mdb_printf(",");
126810491SRishi.Srivatsavai@Sun.COM 				mdb_printf("%d", bit);
126910491SRishi.Srivatsavai@Sun.COM 				rstart = bit;
127010491SRishi.Srivatsavai@Sun.COM 			}
127110491SRishi.Srivatsavai@Sun.COM 			rnext = bit + 1;
127210491SRishi.Srivatsavai@Sun.COM 		}
127310491SRishi.Srivatsavai@Sun.COM 	}
127410491SRishi.Srivatsavai@Sun.COM 	if (rnext != -1 && rstart + 1 != rnext)
127510491SRishi.Srivatsavai@Sun.COM 		mdb_printf("-%d", rnext - 1);
127610491SRishi.Srivatsavai@Sun.COM 	mdb_printf("\n");
127710491SRishi.Srivatsavai@Sun.COM }
127810491SRishi.Srivatsavai@Sun.COM 
127910491SRishi.Srivatsavai@Sun.COM /*
128010491SRishi.Srivatsavai@Sun.COM  * This callback is invoked by a walk of the links attached to a bridge.  If
128110491SRishi.Srivatsavai@Sun.COM  * we're showing link details, then they're printed here.  If not, then we just
128210491SRishi.Srivatsavai@Sun.COM  * count up the links for the bridge summary.
128310491SRishi.Srivatsavai@Sun.COM  */
128410491SRishi.Srivatsavai@Sun.COM static int
do_bridge_links(uintptr_t addr,const void * data,void * ptr)128510491SRishi.Srivatsavai@Sun.COM do_bridge_links(uintptr_t addr, const void *data, void *ptr)
128610491SRishi.Srivatsavai@Sun.COM {
128710491SRishi.Srivatsavai@Sun.COM 	show_bridge_args_t *args = ptr;
128810491SRishi.Srivatsavai@Sun.COM 	const bridge_link_t *blp = data;
128910491SRishi.Srivatsavai@Sun.COM 	char macaddr[ETHERADDRL * 3];
129010491SRishi.Srivatsavai@Sun.COM 	const char *name;
129110491SRishi.Srivatsavai@Sun.COM 
129210491SRishi.Srivatsavai@Sun.COM 	args->nlinks++;
129310491SRishi.Srivatsavai@Sun.COM 
129410491SRishi.Srivatsavai@Sun.COM 	if (!args->opt_l)
129510491SRishi.Srivatsavai@Sun.COM 		return (WALK_NEXT);
129610491SRishi.Srivatsavai@Sun.COM 
129710491SRishi.Srivatsavai@Sun.COM 	if (mdb_vread(&args->mi, sizeof (args->mi),
129810491SRishi.Srivatsavai@Sun.COM 	    (uintptr_t)blp->bl_mh) == -1) {
129910491SRishi.Srivatsavai@Sun.COM 		mdb_warn("cannot read mac data at %p", blp->bl_mh);
130010491SRishi.Srivatsavai@Sun.COM 		name = "?";
130110491SRishi.Srivatsavai@Sun.COM 	} else  {
130210491SRishi.Srivatsavai@Sun.COM 		name = args->mi.mi_name;
130310491SRishi.Srivatsavai@Sun.COM 	}
130410491SRishi.Srivatsavai@Sun.COM 
130510491SRishi.Srivatsavai@Sun.COM 	mdb_mac_addr(blp->bl_local_mac, ETHERADDRL, macaddr,
130610491SRishi.Srivatsavai@Sun.COM 	    sizeof (macaddr));
130710491SRishi.Srivatsavai@Sun.COM 
130810491SRishi.Srivatsavai@Sun.COM 	mdb_printf("%-?p %-16s %-17s %03X %-4d ", addr, name, macaddr,
130910491SRishi.Srivatsavai@Sun.COM 	    blp->bl_flags, blp->bl_pvid);
131010491SRishi.Srivatsavai@Sun.COM 
131110491SRishi.Srivatsavai@Sun.COM 	if (blp->bl_trilldata == NULL) {
131210491SRishi.Srivatsavai@Sun.COM 		switch (blp->bl_state) {
131310491SRishi.Srivatsavai@Sun.COM 		case BLS_BLOCKLISTEN:
131410491SRishi.Srivatsavai@Sun.COM 			name = "BLOCK";
131510491SRishi.Srivatsavai@Sun.COM 			break;
131610491SRishi.Srivatsavai@Sun.COM 		case BLS_LEARNING:
131710491SRishi.Srivatsavai@Sun.COM 			name = "LEARN";
131810491SRishi.Srivatsavai@Sun.COM 			break;
131910491SRishi.Srivatsavai@Sun.COM 		case BLS_FORWARDING:
132010491SRishi.Srivatsavai@Sun.COM 			name = "FWD";
132110491SRishi.Srivatsavai@Sun.COM 			break;
132210491SRishi.Srivatsavai@Sun.COM 		default:
132310491SRishi.Srivatsavai@Sun.COM 			name = "?";
132410491SRishi.Srivatsavai@Sun.COM 		}
132510491SRishi.Srivatsavai@Sun.COM 		mdb_printf("%-5s ", name);
132610491SRishi.Srivatsavai@Sun.COM 		show_vlans(blp->bl_vlans);
132710491SRishi.Srivatsavai@Sun.COM 	} else {
132810491SRishi.Srivatsavai@Sun.COM 		show_vlans(blp->bl_afs);
132910491SRishi.Srivatsavai@Sun.COM 	}
133010491SRishi.Srivatsavai@Sun.COM 
133110491SRishi.Srivatsavai@Sun.COM 	return (WALK_NEXT);
133210491SRishi.Srivatsavai@Sun.COM }
133310491SRishi.Srivatsavai@Sun.COM 
133410491SRishi.Srivatsavai@Sun.COM /*
133510491SRishi.Srivatsavai@Sun.COM  * It seems a shame to duplicate this code, but merging it with the link
133610491SRishi.Srivatsavai@Sun.COM  * printing code above is more trouble than it would be worth.
133710491SRishi.Srivatsavai@Sun.COM  */
133810491SRishi.Srivatsavai@Sun.COM static void
print_link_name(show_bridge_args_t * args,uintptr_t addr,char sep)133910491SRishi.Srivatsavai@Sun.COM print_link_name(show_bridge_args_t *args, uintptr_t addr, char sep)
134010491SRishi.Srivatsavai@Sun.COM {
134110491SRishi.Srivatsavai@Sun.COM 	const char *name;
134210491SRishi.Srivatsavai@Sun.COM 
134310491SRishi.Srivatsavai@Sun.COM 	if (mdb_vread(&args->bl, sizeof (args->bl), addr) == -1) {
134410491SRishi.Srivatsavai@Sun.COM 		mdb_warn("cannot read bridge link at %p", addr);
134510491SRishi.Srivatsavai@Sun.COM 		return;
134610491SRishi.Srivatsavai@Sun.COM 	}
134710491SRishi.Srivatsavai@Sun.COM 
134810491SRishi.Srivatsavai@Sun.COM 	if (mdb_vread(&args->mi, sizeof (args->mi),
134910491SRishi.Srivatsavai@Sun.COM 	    (uintptr_t)args->bl.bl_mh) == -1) {
135010491SRishi.Srivatsavai@Sun.COM 		name = "?";
135110491SRishi.Srivatsavai@Sun.COM 	} else  {
135210491SRishi.Srivatsavai@Sun.COM 		name = args->mi.mi_name;
135310491SRishi.Srivatsavai@Sun.COM 	}
135410491SRishi.Srivatsavai@Sun.COM 
135510491SRishi.Srivatsavai@Sun.COM 	mdb_printf("%s%c", name, sep);
135610491SRishi.Srivatsavai@Sun.COM }
135710491SRishi.Srivatsavai@Sun.COM 
135810491SRishi.Srivatsavai@Sun.COM static int
do_bridge_fwd(uintptr_t addr,const void * data,void * ptr)135910491SRishi.Srivatsavai@Sun.COM do_bridge_fwd(uintptr_t addr, const void *data, void *ptr)
136010491SRishi.Srivatsavai@Sun.COM {
136110491SRishi.Srivatsavai@Sun.COM 	show_bridge_args_t *args = ptr;
136210491SRishi.Srivatsavai@Sun.COM 	const bridge_fwd_t *bfp = data;
136310491SRishi.Srivatsavai@Sun.COM 	char macaddr[ETHERADDRL * 3];
136410491SRishi.Srivatsavai@Sun.COM 	int i;
136510491SRishi.Srivatsavai@Sun.COM #define	MAX_FWD_LINKS	16
136610491SRishi.Srivatsavai@Sun.COM 	bridge_link_t *links[MAX_FWD_LINKS];
136710491SRishi.Srivatsavai@Sun.COM 	uint_t nlinks;
136810491SRishi.Srivatsavai@Sun.COM 
136910491SRishi.Srivatsavai@Sun.COM 	args->nfwd++;
137010491SRishi.Srivatsavai@Sun.COM 
137110491SRishi.Srivatsavai@Sun.COM 	if (!args->opt_f)
137210491SRishi.Srivatsavai@Sun.COM 		return (WALK_NEXT);
137310491SRishi.Srivatsavai@Sun.COM 
137410491SRishi.Srivatsavai@Sun.COM 	if ((nlinks = bfp->bf_nlinks) > MAX_FWD_LINKS)
137510491SRishi.Srivatsavai@Sun.COM 		nlinks = MAX_FWD_LINKS;
137610491SRishi.Srivatsavai@Sun.COM 
137710491SRishi.Srivatsavai@Sun.COM 	if (mdb_vread(links, sizeof (links[0]) * nlinks,
137810491SRishi.Srivatsavai@Sun.COM 	    (uintptr_t)bfp->bf_links) == -1) {
137910491SRishi.Srivatsavai@Sun.COM 		mdb_warn("cannot read bridge forwarding links at %p",
138010491SRishi.Srivatsavai@Sun.COM 		    bfp->bf_links);
138110491SRishi.Srivatsavai@Sun.COM 		return (WALK_ERR);
138210491SRishi.Srivatsavai@Sun.COM 	}
138310491SRishi.Srivatsavai@Sun.COM 
138410491SRishi.Srivatsavai@Sun.COM 	mdb_mac_addr(bfp->bf_dest, ETHERADDRL, macaddr, sizeof (macaddr));
138510491SRishi.Srivatsavai@Sun.COM 
138610491SRishi.Srivatsavai@Sun.COM 	mdb_printf("%-?p %-17s ", addr, macaddr);
138710491SRishi.Srivatsavai@Sun.COM 	if (bfp->bf_flags & BFF_LOCALADDR)
138810491SRishi.Srivatsavai@Sun.COM 		mdb_printf("%-7s", "[self]");
138910491SRishi.Srivatsavai@Sun.COM 	else
139010491SRishi.Srivatsavai@Sun.COM 		mdb_printf("t-%-5d", args->lbolt - bfp->bf_lastheard);
139110491SRishi.Srivatsavai@Sun.COM 	mdb_printf(" %-7u ", bfp->bf_refs);
139210491SRishi.Srivatsavai@Sun.COM 
139310491SRishi.Srivatsavai@Sun.COM 	if (bfp->bf_trill_nick != 0) {
139410491SRishi.Srivatsavai@Sun.COM 		mdb_printf("%d\n", bfp->bf_trill_nick);
139510491SRishi.Srivatsavai@Sun.COM 	} else {
139610491SRishi.Srivatsavai@Sun.COM 		for (i = 0; i < bfp->bf_nlinks; i++) {
139710491SRishi.Srivatsavai@Sun.COM 			print_link_name(args, (uintptr_t)links[i],
139810491SRishi.Srivatsavai@Sun.COM 			    i == bfp->bf_nlinks - 1 ? '\n' : ' ');
139910491SRishi.Srivatsavai@Sun.COM 		}
140010491SRishi.Srivatsavai@Sun.COM 	}
140110491SRishi.Srivatsavai@Sun.COM 
140210491SRishi.Srivatsavai@Sun.COM 	return (WALK_NEXT);
140310491SRishi.Srivatsavai@Sun.COM }
140410491SRishi.Srivatsavai@Sun.COM 
140510491SRishi.Srivatsavai@Sun.COM static int
do_show_bridge(uintptr_t addr,const void * data,void * ptr)140610491SRishi.Srivatsavai@Sun.COM do_show_bridge(uintptr_t addr, const void *data, void *ptr)
140710491SRishi.Srivatsavai@Sun.COM {
140810491SRishi.Srivatsavai@Sun.COM 	show_bridge_args_t *args = ptr;
140910491SRishi.Srivatsavai@Sun.COM 	bridge_inst_t bi;
141010491SRishi.Srivatsavai@Sun.COM 	const bridge_inst_t *bip;
141110491SRishi.Srivatsavai@Sun.COM 	trill_node_t tn;
141210491SRishi.Srivatsavai@Sun.COM 	trill_sock_t tsp;
141310491SRishi.Srivatsavai@Sun.COM 	trill_nickinfo_t tni;
141410491SRishi.Srivatsavai@Sun.COM 	char bname[MAXLINKNAMELEN];
141510491SRishi.Srivatsavai@Sun.COM 	char macaddr[ETHERADDRL * 3];
141610491SRishi.Srivatsavai@Sun.COM 	char *cp;
141710491SRishi.Srivatsavai@Sun.COM 	uint_t nnicks;
141810491SRishi.Srivatsavai@Sun.COM 	int i;
141910491SRishi.Srivatsavai@Sun.COM 
142010491SRishi.Srivatsavai@Sun.COM 	if (data != NULL) {
142110491SRishi.Srivatsavai@Sun.COM 		bip = data;
142210491SRishi.Srivatsavai@Sun.COM 	} else {
142310491SRishi.Srivatsavai@Sun.COM 		if (mdb_vread(&bi, sizeof (bi), addr) == -1) {
142410491SRishi.Srivatsavai@Sun.COM 			mdb_warn("cannot read bridge instance at %p", addr);
142510491SRishi.Srivatsavai@Sun.COM 			return (WALK_ERR);
142610491SRishi.Srivatsavai@Sun.COM 		}
142710491SRishi.Srivatsavai@Sun.COM 		bip = &bi;
142810491SRishi.Srivatsavai@Sun.COM 	}
142910491SRishi.Srivatsavai@Sun.COM 
143010491SRishi.Srivatsavai@Sun.COM 	(void) strncpy(bname, bip->bi_name, sizeof (bname) - 1);
143110491SRishi.Srivatsavai@Sun.COM 	bname[MAXLINKNAMELEN - 1] = '\0';
143210491SRishi.Srivatsavai@Sun.COM 	cp = bname + strlen(bname);
143310491SRishi.Srivatsavai@Sun.COM 	if (cp > bname && cp[-1] == '0')
143410491SRishi.Srivatsavai@Sun.COM 		cp[-1] = '\0';
143510491SRishi.Srivatsavai@Sun.COM 
143610491SRishi.Srivatsavai@Sun.COM 	if (args->name != NULL && strcmp(args->name, bname) != 0)
143710491SRishi.Srivatsavai@Sun.COM 		return (WALK_NEXT);
143810491SRishi.Srivatsavai@Sun.COM 
143910491SRishi.Srivatsavai@Sun.COM 	args->found = B_TRUE;
144010491SRishi.Srivatsavai@Sun.COM 	args->nlinks = args->nfwd = 0;
144110491SRishi.Srivatsavai@Sun.COM 
144210491SRishi.Srivatsavai@Sun.COM 	if (args->opt_l) {
144310491SRishi.Srivatsavai@Sun.COM 		mdb_printf("%-?s %-16s %-17s %3s %-4s ", "ADDR", "LINK",
144410491SRishi.Srivatsavai@Sun.COM 		    "MAC-ADDR", "FLG", "PVID");
144510491SRishi.Srivatsavai@Sun.COM 		if (bip->bi_trilldata == NULL)
144610491SRishi.Srivatsavai@Sun.COM 			mdb_printf("%-5s %s\n", "STATE", "VLANS");
144710491SRishi.Srivatsavai@Sun.COM 		else
144810491SRishi.Srivatsavai@Sun.COM 			mdb_printf("%s\n", "FWD-VLANS");
144910491SRishi.Srivatsavai@Sun.COM 	}
145010491SRishi.Srivatsavai@Sun.COM 
145110491SRishi.Srivatsavai@Sun.COM 	if (!args->opt_f && !args->opt_t &&
145210491SRishi.Srivatsavai@Sun.COM 	    mdb_pwalk("list", do_bridge_links, args,
145310491SRishi.Srivatsavai@Sun.COM 	    addr + offsetof(bridge_inst_t, bi_links)) != DCMD_OK)
145410491SRishi.Srivatsavai@Sun.COM 		return (WALK_ERR);
145510491SRishi.Srivatsavai@Sun.COM 
145610491SRishi.Srivatsavai@Sun.COM 	if (args->opt_f)
145710491SRishi.Srivatsavai@Sun.COM 		mdb_printf("%-?s %-17s %-7s %-7s %s\n", "ADDR", "DEST", "TIME",
145810491SRishi.Srivatsavai@Sun.COM 		    "REFS", "OUTPUT");
145910491SRishi.Srivatsavai@Sun.COM 
146010491SRishi.Srivatsavai@Sun.COM 	if (!args->opt_l && !args->opt_t &&
146110491SRishi.Srivatsavai@Sun.COM 	    mdb_pwalk("avl", do_bridge_fwd, args,
146210491SRishi.Srivatsavai@Sun.COM 	    addr + offsetof(bridge_inst_t, bi_fwd)) != DCMD_OK)
146310491SRishi.Srivatsavai@Sun.COM 		return (WALK_ERR);
146410491SRishi.Srivatsavai@Sun.COM 
146510491SRishi.Srivatsavai@Sun.COM 	nnicks = 0;
146610491SRishi.Srivatsavai@Sun.COM 	if (bip->bi_trilldata != NULL && !args->opt_l && !args->opt_f) {
146710491SRishi.Srivatsavai@Sun.COM 		if (mdb_vread(&args->ti, sizeof (args->ti),
146810491SRishi.Srivatsavai@Sun.COM 		    (uintptr_t)bip->bi_trilldata) == -1) {
146910491SRishi.Srivatsavai@Sun.COM 			mdb_warn("cannot read trill instance at %p",
147010491SRishi.Srivatsavai@Sun.COM 			    bip->bi_trilldata);
147110491SRishi.Srivatsavai@Sun.COM 			return (WALK_ERR);
147210491SRishi.Srivatsavai@Sun.COM 		}
147310491SRishi.Srivatsavai@Sun.COM 		if (args->opt_t)
147410491SRishi.Srivatsavai@Sun.COM 			mdb_printf("%-?s %-5s %-17s %s\n", "ADDR",
147510491SRishi.Srivatsavai@Sun.COM 			    "NICK", "NEXT-HOP", "LINK");
147610491SRishi.Srivatsavai@Sun.COM 		for (i = 0; i < RBRIDGE_NICKNAME_MAX; i++) {
147710491SRishi.Srivatsavai@Sun.COM 			if (args->ti.ti_nodes[i] == NULL)
147810491SRishi.Srivatsavai@Sun.COM 				continue;
147910491SRishi.Srivatsavai@Sun.COM 			if (args->opt_t) {
148010491SRishi.Srivatsavai@Sun.COM 				if (mdb_vread(&tn, sizeof (tn),
148110491SRishi.Srivatsavai@Sun.COM 				    (uintptr_t)args->ti.ti_nodes[i]) == -1) {
148210491SRishi.Srivatsavai@Sun.COM 					mdb_warn("cannot read trill node %d at "
148310491SRishi.Srivatsavai@Sun.COM 					    "%p", i, args->ti.ti_nodes[i]);
148410491SRishi.Srivatsavai@Sun.COM 					return (WALK_ERR);
148510491SRishi.Srivatsavai@Sun.COM 				}
148610491SRishi.Srivatsavai@Sun.COM 				if (mdb_vread(&tni, sizeof (tni),
148710491SRishi.Srivatsavai@Sun.COM 				    (uintptr_t)tn.tn_ni) == -1) {
148810491SRishi.Srivatsavai@Sun.COM 					mdb_warn("cannot read trill node info "
148910491SRishi.Srivatsavai@Sun.COM 					    "%d at %p", i, tn.tn_ni);
149010491SRishi.Srivatsavai@Sun.COM 					return (WALK_ERR);
149110491SRishi.Srivatsavai@Sun.COM 				}
149210491SRishi.Srivatsavai@Sun.COM 				mdb_mac_addr(tni.tni_adjsnpa, ETHERADDRL,
149310491SRishi.Srivatsavai@Sun.COM 				    macaddr, sizeof (macaddr));
149410491SRishi.Srivatsavai@Sun.COM 				if (tni.tni_nick == args->ti.ti_nick) {
149510491SRishi.Srivatsavai@Sun.COM 					(void) strcpy(macaddr, "[self]");
149610491SRishi.Srivatsavai@Sun.COM 				}
149710491SRishi.Srivatsavai@Sun.COM 				mdb_printf("%-?p %-5u %-17s ",
149810491SRishi.Srivatsavai@Sun.COM 				    args->ti.ti_nodes[i], tni.tni_nick,
149910491SRishi.Srivatsavai@Sun.COM 				    macaddr);
150010491SRishi.Srivatsavai@Sun.COM 				if (tn.tn_tsp != NULL) {
150110491SRishi.Srivatsavai@Sun.COM 					if (mdb_vread(&tsp, sizeof (tsp),
150210491SRishi.Srivatsavai@Sun.COM 					    (uintptr_t)tn.tn_tsp) == -1) {
150310491SRishi.Srivatsavai@Sun.COM 						mdb_warn("cannot read trill "
150410491SRishi.Srivatsavai@Sun.COM 						    "socket info at %p",
150510491SRishi.Srivatsavai@Sun.COM 						    tn.tn_tsp);
150610491SRishi.Srivatsavai@Sun.COM 						return (WALK_ERR);
150710491SRishi.Srivatsavai@Sun.COM 					}
150810491SRishi.Srivatsavai@Sun.COM 					if (tsp.ts_link != NULL) {
150910491SRishi.Srivatsavai@Sun.COM 						print_link_name(args,
151010491SRishi.Srivatsavai@Sun.COM 						    (uintptr_t)tsp.ts_link,
151110491SRishi.Srivatsavai@Sun.COM 						    '\n');
151210491SRishi.Srivatsavai@Sun.COM 						continue;
151310491SRishi.Srivatsavai@Sun.COM 					}
151410491SRishi.Srivatsavai@Sun.COM 				}
151510491SRishi.Srivatsavai@Sun.COM 				mdb_printf("--\n");
151610491SRishi.Srivatsavai@Sun.COM 			} else {
151710491SRishi.Srivatsavai@Sun.COM 				nnicks++;
151810491SRishi.Srivatsavai@Sun.COM 			}
151910491SRishi.Srivatsavai@Sun.COM 		}
152010491SRishi.Srivatsavai@Sun.COM 	} else {
152110491SRishi.Srivatsavai@Sun.COM 		if (args->opt_t)
152210491SRishi.Srivatsavai@Sun.COM 			mdb_printf("bridge is not running TRILL\n");
152310491SRishi.Srivatsavai@Sun.COM 	}
152410491SRishi.Srivatsavai@Sun.COM 
152510491SRishi.Srivatsavai@Sun.COM 	if (!args->opt_l && !args->opt_f && !args->opt_t) {
152610491SRishi.Srivatsavai@Sun.COM 		mdb_printf("%-?p %-7s %-16s %-7u %-7u", addr,
152710491SRishi.Srivatsavai@Sun.COM 		    bip->bi_trilldata == NULL ? "stp" : "trill", bname,
152810491SRishi.Srivatsavai@Sun.COM 		    args->nlinks, args->nfwd);
152910491SRishi.Srivatsavai@Sun.COM 		if (bip->bi_trilldata != NULL)
153010491SRishi.Srivatsavai@Sun.COM 			mdb_printf(" %-7u %u\n", nnicks, args->ti.ti_nick);
153110491SRishi.Srivatsavai@Sun.COM 		else
153210491SRishi.Srivatsavai@Sun.COM 			mdb_printf(" %-7s %s\n", "--", "--");
153310491SRishi.Srivatsavai@Sun.COM 	}
153410491SRishi.Srivatsavai@Sun.COM 	return (WALK_NEXT);
153510491SRishi.Srivatsavai@Sun.COM }
153610491SRishi.Srivatsavai@Sun.COM 
153710491SRishi.Srivatsavai@Sun.COM static int
dladm_show_bridge(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)153810491SRishi.Srivatsavai@Sun.COM dladm_show_bridge(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
153910491SRishi.Srivatsavai@Sun.COM {
154010491SRishi.Srivatsavai@Sun.COM 	show_bridge_args_t *args;
154110491SRishi.Srivatsavai@Sun.COM 	GElf_Sym sym;
154210491SRishi.Srivatsavai@Sun.COM 	int i;
154310491SRishi.Srivatsavai@Sun.COM 
154410491SRishi.Srivatsavai@Sun.COM 	args = mdb_zalloc(sizeof (*args), UM_SLEEP);
154510491SRishi.Srivatsavai@Sun.COM 
154610491SRishi.Srivatsavai@Sun.COM 	i = mdb_getopts(argc, argv,
154710491SRishi.Srivatsavai@Sun.COM 	    'l', MDB_OPT_SETBITS, 1, &args->opt_l,
154810491SRishi.Srivatsavai@Sun.COM 	    'f', MDB_OPT_SETBITS, 1, &args->opt_f,
154910491SRishi.Srivatsavai@Sun.COM 	    't', MDB_OPT_SETBITS, 1, &args->opt_t,
155010491SRishi.Srivatsavai@Sun.COM 	    NULL);
155110491SRishi.Srivatsavai@Sun.COM 
155210491SRishi.Srivatsavai@Sun.COM 	argc -= i;
155310491SRishi.Srivatsavai@Sun.COM 	argv += i;
155410491SRishi.Srivatsavai@Sun.COM 
155510491SRishi.Srivatsavai@Sun.COM 	if (argc > 1 || (argc == 1 && argv[0].a_type != MDB_TYPE_STRING)) {
155610491SRishi.Srivatsavai@Sun.COM 		mdb_free(args, sizeof (*args));
155710491SRishi.Srivatsavai@Sun.COM 		return (DCMD_USAGE);
155810491SRishi.Srivatsavai@Sun.COM 	}
155910491SRishi.Srivatsavai@Sun.COM 	if (argc == 1)
156010491SRishi.Srivatsavai@Sun.COM 		args->name = argv[0].a_un.a_str;
156110491SRishi.Srivatsavai@Sun.COM 
1562*11066Srafael.vanoni@sun.com 	if ((args->lbolt = mdb_get_lbolt()) == -1) {
156310491SRishi.Srivatsavai@Sun.COM 		mdb_warn("failed to read lbolt");
156410491SRishi.Srivatsavai@Sun.COM 		goto err;
156510491SRishi.Srivatsavai@Sun.COM 	}
156610491SRishi.Srivatsavai@Sun.COM 
156710491SRishi.Srivatsavai@Sun.COM 	if (flags & DCMD_ADDRSPEC) {
156810491SRishi.Srivatsavai@Sun.COM 		if (args->name != NULL) {
156910491SRishi.Srivatsavai@Sun.COM 			mdb_printf("bridge name and address are mutually "
157010491SRishi.Srivatsavai@Sun.COM 			    "exclusive\n");
157110491SRishi.Srivatsavai@Sun.COM 			goto err;
157210491SRishi.Srivatsavai@Sun.COM 		}
157310491SRishi.Srivatsavai@Sun.COM 		if (!args->opt_l && !args->opt_f && !args->opt_t)
157410491SRishi.Srivatsavai@Sun.COM 			mdb_printf("%-?s %-7s %-16s %-7s %-7s\n", "ADDR",
157510491SRishi.Srivatsavai@Sun.COM 			    "PROTECT", "NAME", "NLINKS", "NFWD");
157610491SRishi.Srivatsavai@Sun.COM 		if (do_show_bridge(addr, NULL, args) != WALK_NEXT)
157710491SRishi.Srivatsavai@Sun.COM 			goto err;
157810491SRishi.Srivatsavai@Sun.COM 		mdb_free(args, sizeof (*args));
157910491SRishi.Srivatsavai@Sun.COM 		return (DCMD_OK);
158010491SRishi.Srivatsavai@Sun.COM 	} else {
158110491SRishi.Srivatsavai@Sun.COM 		if ((args->opt_l || args->opt_f || args->opt_t) &&
158210491SRishi.Srivatsavai@Sun.COM 		    args->name == NULL) {
158310491SRishi.Srivatsavai@Sun.COM 			mdb_printf("need bridge name or address with -[lft]\n");
158410491SRishi.Srivatsavai@Sun.COM 			goto err;
158510491SRishi.Srivatsavai@Sun.COM 		}
158610491SRishi.Srivatsavai@Sun.COM 		if (mdb_lookup_by_obj("bridge", "inst_list", &sym) == -1) {
158710491SRishi.Srivatsavai@Sun.COM 			mdb_warn("failed to find 'bridge`inst_list'");
158810491SRishi.Srivatsavai@Sun.COM 			goto err;
158910491SRishi.Srivatsavai@Sun.COM 		}
159010491SRishi.Srivatsavai@Sun.COM 		if (!args->opt_l && !args->opt_f && !args->opt_t)
159110491SRishi.Srivatsavai@Sun.COM 			mdb_printf("%-?s %-7s %-16s %-7s %-7s %-7s %s\n",
159210491SRishi.Srivatsavai@Sun.COM 			    "ADDR", "PROTECT", "NAME", "NLINKS", "NFWD",
159310491SRishi.Srivatsavai@Sun.COM 			    "NNICKS", "NICK");
159410491SRishi.Srivatsavai@Sun.COM 		if (mdb_pwalk("list", do_show_bridge, args,
159510491SRishi.Srivatsavai@Sun.COM 		    (uintptr_t)sym.st_value) != DCMD_OK)
159610491SRishi.Srivatsavai@Sun.COM 			goto err;
159710491SRishi.Srivatsavai@Sun.COM 		if (!args->found && args->name != NULL) {
159810491SRishi.Srivatsavai@Sun.COM 			mdb_printf("bridge instance %s not found\n",
159910491SRishi.Srivatsavai@Sun.COM 			    args->name);
160010491SRishi.Srivatsavai@Sun.COM 			goto err;
160110491SRishi.Srivatsavai@Sun.COM 		}
160210491SRishi.Srivatsavai@Sun.COM 		mdb_free(args, sizeof (*args));
160310491SRishi.Srivatsavai@Sun.COM 		return (DCMD_OK);
160410491SRishi.Srivatsavai@Sun.COM 	}
160510491SRishi.Srivatsavai@Sun.COM 
160610491SRishi.Srivatsavai@Sun.COM err:
160710491SRishi.Srivatsavai@Sun.COM 	mdb_free(args, sizeof (*args));
160810491SRishi.Srivatsavai@Sun.COM 	return (DCMD_ERR);
160910491SRishi.Srivatsavai@Sun.COM }
161010491SRishi.Srivatsavai@Sun.COM 
161110491SRishi.Srivatsavai@Sun.COM /*
161210491SRishi.Srivatsavai@Sun.COM  * Support for the "::dladm" dcmd
161310491SRishi.Srivatsavai@Sun.COM  */
161410491SRishi.Srivatsavai@Sun.COM int
dladm(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)161510491SRishi.Srivatsavai@Sun.COM dladm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
161610491SRishi.Srivatsavai@Sun.COM {
161710491SRishi.Srivatsavai@Sun.COM 	if (argc < 1 || argv[0].a_type != MDB_TYPE_STRING)
161810491SRishi.Srivatsavai@Sun.COM 		return (DCMD_USAGE);
161910491SRishi.Srivatsavai@Sun.COM 
162010491SRishi.Srivatsavai@Sun.COM 	/*
162110491SRishi.Srivatsavai@Sun.COM 	 * This could be a bit more elaborate, once we support more of the
162210491SRishi.Srivatsavai@Sun.COM 	 * dladm show-* subcommands.
162310491SRishi.Srivatsavai@Sun.COM 	 */
162410491SRishi.Srivatsavai@Sun.COM 	argc--;
162510491SRishi.Srivatsavai@Sun.COM 	argv++;
162610491SRishi.Srivatsavai@Sun.COM 	if (strcmp(argv[-1].a_un.a_str, "show-bridge") == 0)
162710491SRishi.Srivatsavai@Sun.COM 		return (dladm_show_bridge(addr, flags, argc, argv));
162810491SRishi.Srivatsavai@Sun.COM 
162910491SRishi.Srivatsavai@Sun.COM 	return (DCMD_USAGE);
163010491SRishi.Srivatsavai@Sun.COM }
163110491SRishi.Srivatsavai@Sun.COM 
163210491SRishi.Srivatsavai@Sun.COM void
dladm_help(void)163310491SRishi.Srivatsavai@Sun.COM dladm_help(void)
163410491SRishi.Srivatsavai@Sun.COM {
163510491SRishi.Srivatsavai@Sun.COM 	mdb_printf("Subcommands:\n"
163610491SRishi.Srivatsavai@Sun.COM 	    "  show-bridge [-flt] [<name>]\n"
163710491SRishi.Srivatsavai@Sun.COM 	    "\t     Show bridge information; -l for links and -f for "
163810491SRishi.Srivatsavai@Sun.COM 	    "forwarding\n"
163910491SRishi.Srivatsavai@Sun.COM 	    "\t     entries, and -t for TRILL nicknames.  Address is required "
164010491SRishi.Srivatsavai@Sun.COM 	    "if name\n"
164110491SRishi.Srivatsavai@Sun.COM 	    "\t     is not specified.\n");
164210491SRishi.Srivatsavai@Sun.COM }
1643