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/arp_impl.h>
490Sstevel@tonic-gate #include <inet/rawip_impl.h>
500Sstevel@tonic-gate #include <inet/mi.h>
518348SEric.Yu@Sun.COM #include <fs/sockfs/socktpi_impl.h>
52*10491SRishi.Srivatsavai@Sun.COM #include <net/bridge_impl.h>
53*10491SRishi.Srivatsavai@Sun.COM #include <io/trill_impl.h>
54*10491SRishi.Srivatsavai@Sun.COM #include <sys/mac_impl.h>
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #define	ADDR_V6_WIDTH	23
570Sstevel@tonic-gate #define	ADDR_V4_WIDTH	15
580Sstevel@tonic-gate 
591676Sjpk #define	NETSTAT_ALL	0x01
601676Sjpk #define	NETSTAT_VERBOSE	0x02
611676Sjpk #define	NETSTAT_ROUTE	0x04
621676Sjpk #define	NETSTAT_V4	0x08
631676Sjpk #define	NETSTAT_V6	0x10
641676Sjpk #define	NETSTAT_UNIX	0x20
651676Sjpk 
661676Sjpk #define	NETSTAT_FIRST	0x80000000u
670Sstevel@tonic-gate 
689089SVasumathi.Sundaram@Sun.COM typedef struct netstat_cb_data_s {
699089SVasumathi.Sundaram@Sun.COM 	uint_t	opts;
709089SVasumathi.Sundaram@Sun.COM 	conn_t	conn;
719089SVasumathi.Sundaram@Sun.COM 	int	af;
729089SVasumathi.Sundaram@Sun.COM } netstat_cb_data_t;
733448Sdh155122 
743448Sdh155122 /* Walkers for various *_stack_t */
753448Sdh155122 int
763448Sdh155122 ar_stacks_walk_init(mdb_walk_state_t *wsp)
773448Sdh155122 {
783448Sdh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
793448Sdh155122 		mdb_warn("can't walk 'netstack'");
803448Sdh155122 		return (WALK_ERR);
813448Sdh155122 	}
823448Sdh155122 	return (WALK_NEXT);
833448Sdh155122 }
843448Sdh155122 
853448Sdh155122 int
863448Sdh155122 ar_stacks_walk_step(mdb_walk_state_t *wsp)
873448Sdh155122 {
883448Sdh155122 	uintptr_t kaddr;
893448Sdh155122 	netstack_t nss;
903448Sdh155122 
913448Sdh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
923448Sdh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
933448Sdh155122 		return (WALK_ERR);
943448Sdh155122 	}
953448Sdh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_ARP];
963448Sdh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
973448Sdh155122 }
983448Sdh155122 
993448Sdh155122 int
1003448Sdh155122 icmp_stacks_walk_init(mdb_walk_state_t *wsp)
1013448Sdh155122 {
1023448Sdh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
1033448Sdh155122 		mdb_warn("can't walk 'netstack'");
1043448Sdh155122 		return (WALK_ERR);
1053448Sdh155122 	}
1063448Sdh155122 	return (WALK_NEXT);
1073448Sdh155122 }
1083448Sdh155122 
1093448Sdh155122 int
1103448Sdh155122 icmp_stacks_walk_step(mdb_walk_state_t *wsp)
1113448Sdh155122 {
1123448Sdh155122 	uintptr_t kaddr;
1133448Sdh155122 	netstack_t nss;
1143448Sdh155122 
1153448Sdh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
1163448Sdh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
1173448Sdh155122 		return (WALK_ERR);
1183448Sdh155122 	}
1193448Sdh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_ICMP];
1203448Sdh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
1213448Sdh155122 }
1223448Sdh155122 
1233448Sdh155122 int
1243448Sdh155122 tcp_stacks_walk_init(mdb_walk_state_t *wsp)
1253448Sdh155122 {
1263448Sdh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
1273448Sdh155122 		mdb_warn("can't walk 'netstack'");
1283448Sdh155122 		return (WALK_ERR);
1293448Sdh155122 	}
1303448Sdh155122 	return (WALK_NEXT);
1313448Sdh155122 }
1323448Sdh155122 
1333448Sdh155122 int
1343448Sdh155122 tcp_stacks_walk_step(mdb_walk_state_t *wsp)
1353448Sdh155122 {
1363448Sdh155122 	uintptr_t kaddr;
1373448Sdh155122 	netstack_t nss;
1383448Sdh155122 
1393448Sdh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
1403448Sdh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
1413448Sdh155122 		return (WALK_ERR);
1423448Sdh155122 	}
1433448Sdh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_TCP];
1443448Sdh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
1453448Sdh155122 }
1463448Sdh155122 
1473448Sdh155122 int
1483448Sdh155122 udp_stacks_walk_init(mdb_walk_state_t *wsp)
1493448Sdh155122 {
1503448Sdh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
1513448Sdh155122 		mdb_warn("can't walk 'netstack'");
1523448Sdh155122 		return (WALK_ERR);
1533448Sdh155122 	}
1543448Sdh155122 	return (WALK_NEXT);
1553448Sdh155122 }
1563448Sdh155122 
1573448Sdh155122 int
1583448Sdh155122 udp_stacks_walk_step(mdb_walk_state_t *wsp)
1593448Sdh155122 {
1603448Sdh155122 	uintptr_t kaddr;
1613448Sdh155122 	netstack_t nss;
1623448Sdh155122 
1633448Sdh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
1643448Sdh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
1653448Sdh155122 		return (WALK_ERR);
1663448Sdh155122 	}
1673448Sdh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_UDP];
1683448Sdh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
1693448Sdh155122 }
1703448Sdh155122 
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate  * Print an IPv4 address and port number in a compact and easy to read format
1730Sstevel@tonic-gate  * The arguments are in network byte order
1740Sstevel@tonic-gate  */
1750Sstevel@tonic-gate static void
1760Sstevel@tonic-gate net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate 	uint32_t naddr = V4_PART_OF_V6((*nipv6addr));
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	mdb_nhconvert(&nport, &nport, sizeof (nport));
1810Sstevel@tonic-gate 	mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport);
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate /*
1850Sstevel@tonic-gate  * Print an IPv6 address and port number in a compact and easy to read format
1860Sstevel@tonic-gate  * The arguments are in network byte order
1870Sstevel@tonic-gate  */
1880Sstevel@tonic-gate static void
1890Sstevel@tonic-gate net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport)
1900Sstevel@tonic-gate {
1910Sstevel@tonic-gate 	mdb_nhconvert(&nport, &nport, sizeof (nport));
1920Sstevel@tonic-gate 	mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport);
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate static int
1960Sstevel@tonic-gate net_tcp_active(const tcp_t *tcp)
1970Sstevel@tonic-gate {
1980Sstevel@tonic-gate 	return (tcp->tcp_state >= TCPS_ESTABLISHED);
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate static int
2020Sstevel@tonic-gate net_tcp_ipv4(const tcp_t *tcp)
2030Sstevel@tonic-gate {
2040Sstevel@tonic-gate 	return ((tcp->tcp_ipversion == IPV4_VERSION) ||
2050Sstevel@tonic-gate 	    (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_ip_src_v6) &&
2060Sstevel@tonic-gate 	    (tcp->tcp_state <= TCPS_LISTEN)));
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate static int
2100Sstevel@tonic-gate net_tcp_ipv6(const tcp_t *tcp)
2110Sstevel@tonic-gate {
2120Sstevel@tonic-gate 	return (tcp->tcp_ipversion == IPV6_VERSION);
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate static int
2160Sstevel@tonic-gate net_udp_active(const udp_t *udp)
2170Sstevel@tonic-gate {
218741Smasputra 	return ((udp->udp_state == TS_IDLE) ||
219741Smasputra 	    (udp->udp_state == TS_DATA_XFER));
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate static int
2230Sstevel@tonic-gate net_udp_ipv4(const udp_t *udp)
2240Sstevel@tonic-gate {
2250Sstevel@tonic-gate 	return ((udp->udp_ipversion == IPV4_VERSION) ||
2260Sstevel@tonic-gate 	    (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src) &&
2270Sstevel@tonic-gate 	    (udp->udp_state <= TS_IDLE)));
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate static int
2310Sstevel@tonic-gate net_udp_ipv6(const udp_t *udp)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate 	return (udp->udp_ipversion == IPV6_VERSION);
2340Sstevel@tonic-gate }
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate int
2370Sstevel@tonic-gate sonode_walk_init(mdb_walk_state_t *wsp)
2380Sstevel@tonic-gate {
2390Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
2400Sstevel@tonic-gate 		GElf_Sym sym;
2410Sstevel@tonic-gate 		struct socklist *slp;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 		if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) {
2440Sstevel@tonic-gate 			mdb_warn("failed to lookup sockfs`socklist");
2450Sstevel@tonic-gate 			return (WALK_ERR);
2460Sstevel@tonic-gate 		}
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 		slp = (struct socklist *)(uintptr_t)sym.st_value;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 		if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),
2510Sstevel@tonic-gate 		    (uintptr_t)&slp->sl_list) == -1) {
2520Sstevel@tonic-gate 			mdb_warn("failed to read address of initial sonode "
2530Sstevel@tonic-gate 			    "at %p", &slp->sl_list);
2540Sstevel@tonic-gate 			return (WALK_ERR);
2550Sstevel@tonic-gate 		}
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 
2588348SEric.Yu@Sun.COM 	wsp->walk_data = mdb_alloc(sizeof (struct sotpi_sonode), UM_SLEEP);
2590Sstevel@tonic-gate 	return (WALK_NEXT);
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate int
2630Sstevel@tonic-gate sonode_walk_step(mdb_walk_state_t *wsp)
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate 	int status;
2668348SEric.Yu@Sun.COM 	struct sotpi_sonode *stp;
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	if (wsp->walk_addr == NULL)
2690Sstevel@tonic-gate 		return (WALK_DONE);
2700Sstevel@tonic-gate 
2718348SEric.Yu@Sun.COM 	if (mdb_vread(wsp->walk_data, sizeof (struct sotpi_sonode),
2720Sstevel@tonic-gate 	    wsp->walk_addr) == -1) {
2730Sstevel@tonic-gate 		mdb_warn("failed to read sonode at %p", wsp->walk_addr);
2740Sstevel@tonic-gate 		return (WALK_ERR);
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
2780Sstevel@tonic-gate 	    wsp->walk_cbdata);
2790Sstevel@tonic-gate 
2808348SEric.Yu@Sun.COM 	stp = wsp->walk_data;
2810Sstevel@tonic-gate 
2828348SEric.Yu@Sun.COM 	wsp->walk_addr = (uintptr_t)stp->st_info.sti_next_so;
2830Sstevel@tonic-gate 	return (status);
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate void
2870Sstevel@tonic-gate sonode_walk_fini(mdb_walk_state_t *wsp)
2880Sstevel@tonic-gate {
2898348SEric.Yu@Sun.COM 	mdb_free(wsp->walk_data, sizeof (struct sotpi_sonode));
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate struct mi_walk_data {
2930Sstevel@tonic-gate 	uintptr_t mi_wd_miofirst;
2940Sstevel@tonic-gate 	MI_O mi_wd_miodata;
2950Sstevel@tonic-gate };
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate int
2980Sstevel@tonic-gate mi_walk_init(mdb_walk_state_t *wsp)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	struct mi_walk_data *wdp;
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
3030Sstevel@tonic-gate 		mdb_warn("mi doesn't support global walks\n");
3040Sstevel@tonic-gate 		return (WALK_ERR);
3050Sstevel@tonic-gate 	}
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP);
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	/* So that we do not immediately return WALK_DONE below */
3100Sstevel@tonic-gate 	wdp->mi_wd_miofirst = NULL;
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	wsp->walk_data = wdp;
3130Sstevel@tonic-gate 	return (WALK_NEXT);
3140Sstevel@tonic-gate }
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate int
3170Sstevel@tonic-gate mi_walk_step(mdb_walk_state_t *wsp)
3180Sstevel@tonic-gate {
3190Sstevel@tonic-gate 	struct mi_walk_data *wdp = wsp->walk_data;
3200Sstevel@tonic-gate 	MI_OP miop = &wdp->mi_wd_miodata;
3210Sstevel@tonic-gate 	int status;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	/* Always false in the first iteration */
3240Sstevel@tonic-gate 	if ((wsp->walk_addr == (uintptr_t)NULL) ||
3250Sstevel@tonic-gate 	    (wsp->walk_addr == wdp->mi_wd_miofirst)) {
3260Sstevel@tonic-gate 		return (WALK_DONE);
3270Sstevel@tonic-gate 	}
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) {
3300Sstevel@tonic-gate 		mdb_warn("failed to read MI object at %p", wsp->walk_addr);
3310Sstevel@tonic-gate 		return (WALK_ERR);
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	/* Only true in the first iteration */
3353448Sdh155122 	if (wdp->mi_wd_miofirst == NULL) {
3360Sstevel@tonic-gate 		wdp->mi_wd_miofirst = wsp->walk_addr;
3373448Sdh155122 		status = WALK_NEXT;
3383448Sdh155122 	} else {
3393448Sdh155122 		status = wsp->walk_callback(wsp->walk_addr + sizeof (MI_O),
3403448Sdh155122 		    &miop[1], wsp->walk_cbdata);
3413448Sdh155122 	}
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)miop->mi_o_next;
3440Sstevel@tonic-gate 	return (status);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate void
3480Sstevel@tonic-gate mi_walk_fini(mdb_walk_state_t *wsp)
3490Sstevel@tonic-gate {
3500Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (struct mi_walk_data));
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate typedef struct mi_payload_walk_arg_s {
3543448Sdh155122 	const char *mi_pwa_walker;	/* Underlying walker */
3553448Sdh155122 	const off_t mi_pwa_head_off;	/* Offset for mi_o_head_t * in stack */
3560Sstevel@tonic-gate 	const size_t mi_pwa_size;	/* size of mi payload */
3570Sstevel@tonic-gate 	const uint_t mi_pwa_flags;	/* device and/or module */
3580Sstevel@tonic-gate } mi_payload_walk_arg_t;
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate #define	MI_PAYLOAD_DEVICE	0x1
3610Sstevel@tonic-gate #define	MI_PAYLOAD_MODULE	0x2
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate int
3640Sstevel@tonic-gate mi_payload_walk_init(mdb_walk_state_t *wsp)
3650Sstevel@tonic-gate {
3660Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
3670Sstevel@tonic-gate 
3683448Sdh155122 	if (mdb_layered_walk(arg->mi_pwa_walker, wsp) == -1) {
3693448Sdh155122 		mdb_warn("can't walk '%s'", arg->mi_pwa_walker);
3700Sstevel@tonic-gate 		return (WALK_ERR);
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 	return (WALK_NEXT);
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate int
3760Sstevel@tonic-gate mi_payload_walk_step(mdb_walk_state_t *wsp)
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate 	const mi_payload_walk_arg_t *arg = wsp->walk_arg;
3793448Sdh155122 	uintptr_t kaddr;
3800Sstevel@tonic-gate 
3813448Sdh155122 	kaddr = wsp->walk_addr + arg->mi_pwa_head_off;
3820Sstevel@tonic-gate 
3833448Sdh155122 	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
3843448Sdh155122 		mdb_warn("can't read address of mi head at %p for %s",
3853448Sdh155122 		    kaddr, arg->mi_pwa_walker);
3860Sstevel@tonic-gate 		return (WALK_ERR);
3870Sstevel@tonic-gate 	}
3880Sstevel@tonic-gate 
3893448Sdh155122 	if (kaddr == 0) {
3903448Sdh155122 		/* Empty list */
3913448Sdh155122 		return (WALK_DONE);
3923448Sdh155122 	}
3930Sstevel@tonic-gate 
3943448Sdh155122 	if (mdb_pwalk("genunix`mi", wsp->walk_callback,
3953448Sdh155122 	    wsp->walk_cbdata, kaddr) == -1) {
3963448Sdh155122 		mdb_warn("failed to walk genunix`mi");
3973448Sdh155122 		return (WALK_ERR);
3983448Sdh155122 	}
3993448Sdh155122 	return (WALK_NEXT);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate const mi_payload_walk_arg_t mi_ar_arg = {
4033448Sdh155122 	"ar_stacks", OFFSETOF(arp_stack_t, as_head), sizeof (ar_t),
4040Sstevel@tonic-gate 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
4050Sstevel@tonic-gate };
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate const mi_payload_walk_arg_t mi_icmp_arg = {
4083448Sdh155122 	"icmp_stacks", OFFSETOF(icmp_stack_t, is_head), sizeof (icmp_t),
4090Sstevel@tonic-gate 	MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
4100Sstevel@tonic-gate };
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate int
4130Sstevel@tonic-gate sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
4140Sstevel@tonic-gate {
4150Sstevel@tonic-gate 	const char *optf = NULL;
4160Sstevel@tonic-gate 	const char *optt = NULL;
4170Sstevel@tonic-gate 	const char *optp = NULL;
4180Sstevel@tonic-gate 	int family, type, proto;
4190Sstevel@tonic-gate 	int filter = 0;
4200Sstevel@tonic-gate 	struct sonode so;
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
4230Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`sonode", "genunix`sonode", argc,
4240Sstevel@tonic-gate 		    argv) == -1) {
4250Sstevel@tonic-gate 			mdb_warn("failed to walk sonode");
4260Sstevel@tonic-gate 			return (DCMD_ERR);
4270Sstevel@tonic-gate 		}
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 		return (DCMD_OK);
4300Sstevel@tonic-gate 	}
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
4330Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &optf,
4340Sstevel@tonic-gate 	    't', MDB_OPT_STR, &optt,
4350Sstevel@tonic-gate 	    'p', MDB_OPT_STR, &optp,
4360Sstevel@tonic-gate 	    NULL) != argc)
4370Sstevel@tonic-gate 		return (DCMD_USAGE);
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	if (optf != NULL) {
4400Sstevel@tonic-gate 		if (strcmp("inet", optf) == 0)
4410Sstevel@tonic-gate 			family = AF_INET;
4420Sstevel@tonic-gate 		else if (strcmp("inet6", optf) == 0)
4430Sstevel@tonic-gate 			family = AF_INET6;
4440Sstevel@tonic-gate 		else if (strcmp("unix", optf) == 0)
4450Sstevel@tonic-gate 			family = AF_UNIX;
4460Sstevel@tonic-gate 		else
4470Sstevel@tonic-gate 			family = mdb_strtoull(optf);
4480Sstevel@tonic-gate 		filter = 1;
4490Sstevel@tonic-gate 	}
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	if (optt != NULL) {
4520Sstevel@tonic-gate 		if (strcmp("stream", optt) == 0)
4530Sstevel@tonic-gate 			type = SOCK_STREAM;
4540Sstevel@tonic-gate 		else if (strcmp("dgram", optt) == 0)
4550Sstevel@tonic-gate 			type = SOCK_DGRAM;
4560Sstevel@tonic-gate 		else if (strcmp("raw", optt) == 0)
4570Sstevel@tonic-gate 			type = SOCK_RAW;
4580Sstevel@tonic-gate 		else
4590Sstevel@tonic-gate 			type = mdb_strtoull(optt);
4600Sstevel@tonic-gate 		filter = 1;
4610Sstevel@tonic-gate 	}
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	if (optp != NULL) {
4640Sstevel@tonic-gate 		proto = mdb_strtoull(optp);
4650Sstevel@tonic-gate 		filter = 1;
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && !filter) {
4690Sstevel@tonic-gate 		mdb_printf("%<u>%-?s Family Type Proto State Mode Flag "
4700Sstevel@tonic-gate 		    "AccessVP%</u>\n", "Sonode:");
4710Sstevel@tonic-gate 	}
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	if (mdb_vread(&so, sizeof (so), addr) == -1) {
4740Sstevel@tonic-gate 		mdb_warn("failed to read sonode at %p", addr);
4750Sstevel@tonic-gate 		return (DCMD_ERR);
4760Sstevel@tonic-gate 	}
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	if ((optf != NULL) && (so.so_family != family))
4790Sstevel@tonic-gate 		return (DCMD_OK);
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	if ((optt != NULL) && (so.so_type != type))
4820Sstevel@tonic-gate 		return (DCMD_OK);
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	if ((optp != NULL) && (so.so_protocol != proto))
4850Sstevel@tonic-gate 		return (DCMD_OK);
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	if (filter) {
4880Sstevel@tonic-gate 		mdb_printf("%0?p\n", addr);
4890Sstevel@tonic-gate 		return (DCMD_OK);
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	mdb_printf("%0?p ", addr);
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	switch (so.so_family) {
4955563Snordmark 	case AF_UNIX:
4960Sstevel@tonic-gate 		mdb_printf("unix  ");
4970Sstevel@tonic-gate 		break;
4985563Snordmark 	case AF_INET:
4990Sstevel@tonic-gate 		mdb_printf("inet  ");
5000Sstevel@tonic-gate 		break;
5015563Snordmark 	case AF_INET6:
5020Sstevel@tonic-gate 		mdb_printf("inet6 ");
5030Sstevel@tonic-gate 		break;
5045563Snordmark 	default:
5050Sstevel@tonic-gate 		mdb_printf("%6hi", so.so_family);
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	switch (so.so_type) {
5095563Snordmark 	case SOCK_STREAM:
5100Sstevel@tonic-gate 		mdb_printf(" strm");
5110Sstevel@tonic-gate 		break;
5125563Snordmark 	case SOCK_DGRAM:
5130Sstevel@tonic-gate 		mdb_printf(" dgrm");
5140Sstevel@tonic-gate 		break;
5155563Snordmark 	case SOCK_RAW:
5160Sstevel@tonic-gate 		mdb_printf(" raw ");
5170Sstevel@tonic-gate 		break;
5185563Snordmark 	default:
5190Sstevel@tonic-gate 		mdb_printf(" %4hi", so.so_type);
5200Sstevel@tonic-gate 	}
5210Sstevel@tonic-gate 
5228348SEric.Yu@Sun.COM 	mdb_printf(" %5hi %05x %04x %04hx\n",
5230Sstevel@tonic-gate 	    so.so_protocol, so.so_state, so.so_mode,
5248348SEric.Yu@Sun.COM 	    so.so_flag);
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	return (DCMD_OK);
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate #define	MI_PAYLOAD	0x1
5300Sstevel@tonic-gate #define	MI_DEVICE	0x2
5310Sstevel@tonic-gate #define	MI_MODULE	0x4
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate int
5340Sstevel@tonic-gate mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5350Sstevel@tonic-gate {
5360Sstevel@tonic-gate 	uint_t opts = 0;
5370Sstevel@tonic-gate 	MI_O	mio;
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
5400Sstevel@tonic-gate 		return (DCMD_USAGE);
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
5430Sstevel@tonic-gate 	    'p', MDB_OPT_SETBITS, MI_PAYLOAD, &opts,
5440Sstevel@tonic-gate 	    'd', MDB_OPT_SETBITS, MI_DEVICE, &opts,
5450Sstevel@tonic-gate 	    'm', MDB_OPT_SETBITS, MI_MODULE, &opts,
5460Sstevel@tonic-gate 	    NULL) != argc)
5470Sstevel@tonic-gate 		return (DCMD_USAGE);
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	if ((opts & (MI_DEVICE | MI_MODULE)) == (MI_DEVICE | MI_MODULE)) {
5500Sstevel@tonic-gate 		mdb_warn("at most one filter, d for devices or m "
5510Sstevel@tonic-gate 		    "for modules, may be specified\n");
5520Sstevel@tonic-gate 		return (DCMD_USAGE);
5530Sstevel@tonic-gate 	}
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	if ((opts == 0) && (DCMD_HDRSPEC(flags))) {
5560Sstevel@tonic-gate 		mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n",
5570Sstevel@tonic-gate 		    "MI_O", "Next", "Prev");
5580Sstevel@tonic-gate 	}
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	if (mdb_vread(&mio, sizeof (mio), addr) == -1) {
5610Sstevel@tonic-gate 		mdb_warn("failed to read mi object MI_O at %p", addr);
5620Sstevel@tonic-gate 		return (DCMD_ERR);
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	if (opts != 0) {
5660Sstevel@tonic-gate 		if (mio.mi_o_isdev == B_FALSE) {
5670Sstevel@tonic-gate 			/* mio is a module */
5680Sstevel@tonic-gate 			if (!(opts & MI_MODULE) && (opts & MI_DEVICE))
5690Sstevel@tonic-gate 				return (DCMD_OK);
5700Sstevel@tonic-gate 		} else {
5710Sstevel@tonic-gate 			/* mio is a device */
5720Sstevel@tonic-gate 			if (!(opts & MI_DEVICE) && (opts & MI_MODULE))
5730Sstevel@tonic-gate 				return (DCMD_OK);
5740Sstevel@tonic-gate 		}
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 		if (opts & MI_PAYLOAD)
5770Sstevel@tonic-gate 			mdb_printf("%p\n", addr + sizeof (MI_O));
5780Sstevel@tonic-gate 		else
5790Sstevel@tonic-gate 			mdb_printf("%p\n", addr);
5800Sstevel@tonic-gate 		return (DCMD_OK);
5810Sstevel@tonic-gate 	}
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev);
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	if (mio.mi_o_isdev == B_FALSE)
5860Sstevel@tonic-gate 		mdb_printf("FALSE");
5870Sstevel@tonic-gate 	else
5880Sstevel@tonic-gate 		mdb_printf("TRUE ");
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	mdb_printf(" %0?p\n", mio.mi_o_dev);
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	return (DCMD_OK);
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate 
5953448Sdh155122 static int
5963448Sdh155122 ns_to_stackid(uintptr_t kaddr)
5973448Sdh155122 {
5983448Sdh155122 	netstack_t nss;
5993448Sdh155122 
6003448Sdh155122 	if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
6013448Sdh155122 		mdb_warn("failed to read netstack_t %p", kaddr);
6023448Sdh155122 		return (0);
6033448Sdh155122 	}
6043448Sdh155122 	return (nss.netstack_stackid);
6053448Sdh155122 }
6063448Sdh155122 
6073448Sdh155122 
6083448Sdh155122 
6090Sstevel@tonic-gate static void
6100Sstevel@tonic-gate netstat_tcp_verbose_pr(const tcp_t *tcp)
6110Sstevel@tonic-gate {
6120Sstevel@tonic-gate 	mdb_printf("       %5i %08x %08x %5i %08x %08x %5li %5i\n",
6130Sstevel@tonic-gate 	    tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
6140Sstevel@tonic-gate 	    tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate /*ARGSUSED*/
6180Sstevel@tonic-gate static int
6199089SVasumathi.Sundaram@Sun.COM netstat_tcp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
6200Sstevel@tonic-gate {
6219089SVasumathi.Sundaram@Sun.COM 	netstat_cb_data_t *ncb = cb_data;
6229089SVasumathi.Sundaram@Sun.COM 	uint_t opts = ncb->opts;
6239089SVasumathi.Sundaram@Sun.COM 	int af = ncb->af;
6240Sstevel@tonic-gate 	uintptr_t tcp_kaddr;
6259089SVasumathi.Sundaram@Sun.COM 	conn_t *connp = &ncb->conn;
6265563Snordmark 	tcp_t tcps, *tcp;
6270Sstevel@tonic-gate 
6289089SVasumathi.Sundaram@Sun.COM 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
6295563Snordmark 		mdb_warn("failed to read conn_t at %p", kaddr);
6305563Snordmark 		return (WALK_ERR);
6310Sstevel@tonic-gate 	}
6320Sstevel@tonic-gate 
6335563Snordmark 	tcp_kaddr = (uintptr_t)connp->conn_tcp;
6345563Snordmark 	if (mdb_vread(&tcps, sizeof (tcp_t), tcp_kaddr) == -1) {
6355563Snordmark 		mdb_warn("failed to read tcp_t at %p", kaddr);
6360Sstevel@tonic-gate 		return (WALK_ERR);
6370Sstevel@tonic-gate 	}
6380Sstevel@tonic-gate 
6395563Snordmark 	tcp = &tcps;
6400Sstevel@tonic-gate 	connp->conn_tcp = tcp;
6410Sstevel@tonic-gate 	tcp->tcp_connp = connp;
6420Sstevel@tonic-gate 
643741Smasputra 	if (!((opts & NETSTAT_ALL) || net_tcp_active(tcp)) ||
6440Sstevel@tonic-gate 	    (af == AF_INET && !net_tcp_ipv4(tcp)) ||
6450Sstevel@tonic-gate 	    (af == AF_INET6 && !net_tcp_ipv6(tcp))) {
6460Sstevel@tonic-gate 		return (WALK_NEXT);
6470Sstevel@tonic-gate 	}
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state);
6500Sstevel@tonic-gate 	if (af == AF_INET) {
6510Sstevel@tonic-gate 		net_ipv4addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport);
6520Sstevel@tonic-gate 		mdb_printf(" ");
6530Sstevel@tonic-gate 		net_ipv4addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport);
6540Sstevel@tonic-gate 	} else if (af == AF_INET6) {
6550Sstevel@tonic-gate 		net_ipv6addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport);
6560Sstevel@tonic-gate 		mdb_printf(" ");
6570Sstevel@tonic-gate 		net_ipv6addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport);
6580Sstevel@tonic-gate 	}
6599089SVasumathi.Sundaram@Sun.COM 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
6600Sstevel@tonic-gate 	mdb_printf(" %4i\n", connp->conn_zoneid);
6610Sstevel@tonic-gate 	if (opts & NETSTAT_VERBOSE)
6620Sstevel@tonic-gate 		netstat_tcp_verbose_pr(tcp);
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	return (WALK_NEXT);
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate 
667741Smasputra /*ARGSUSED*/
6680Sstevel@tonic-gate static int
6699089SVasumathi.Sundaram@Sun.COM netstat_udp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
6700Sstevel@tonic-gate {
6719089SVasumathi.Sundaram@Sun.COM 	netstat_cb_data_t *ncb = cb_data;
6729089SVasumathi.Sundaram@Sun.COM 	uint_t opts = ncb->opts;
6739089SVasumathi.Sundaram@Sun.COM 	int af = ncb->af;
674741Smasputra 	udp_t udp;
6759089SVasumathi.Sundaram@Sun.COM 	conn_t *connp = &ncb->conn;
6769089SVasumathi.Sundaram@Sun.COM 	char *state;
677741Smasputra 
6789089SVasumathi.Sundaram@Sun.COM 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
6795563Snordmark 		mdb_warn("failed to read conn_t at %p", kaddr);
680741Smasputra 		return (WALK_ERR);
681741Smasputra 	}
6820Sstevel@tonic-gate 
6835563Snordmark 	if (mdb_vread(&udp, sizeof (udp_t),
6849089SVasumathi.Sundaram@Sun.COM 	    (uintptr_t)connp->conn_udp) == -1) {
6855563Snordmark 		mdb_warn("failed to read conn_udp at %p",
6869089SVasumathi.Sundaram@Sun.COM 		    (uintptr_t)connp->conn_udp);
687741Smasputra 		return (WALK_ERR);
688741Smasputra 	}
6890Sstevel@tonic-gate 
690741Smasputra 	if (!((opts & NETSTAT_ALL) || net_udp_active(&udp)) ||
691741Smasputra 	    (af == AF_INET && !net_udp_ipv4(&udp)) ||
692741Smasputra 	    (af == AF_INET6 && !net_udp_ipv6(&udp))) {
693741Smasputra 		return (WALK_NEXT);
694741Smasputra 	}
695741Smasputra 
6969089SVasumathi.Sundaram@Sun.COM 	if (udp.udp_state == TS_UNBND)
6979089SVasumathi.Sundaram@Sun.COM 		state = "UNBOUND";
6989089SVasumathi.Sundaram@Sun.COM 	else if (udp.udp_state == TS_IDLE)
6999089SVasumathi.Sundaram@Sun.COM 		state = "IDLE";
7009089SVasumathi.Sundaram@Sun.COM 	else if (udp.udp_state == TS_DATA_XFER)
7019089SVasumathi.Sundaram@Sun.COM 		state = "CONNECTED";
7029089SVasumathi.Sundaram@Sun.COM 	else
7039089SVasumathi.Sundaram@Sun.COM 		state = "UNKNOWN";
7049089SVasumathi.Sundaram@Sun.COM 
7059089SVasumathi.Sundaram@Sun.COM 	mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_udp, state);
706741Smasputra 	if (af == AF_INET) {
707741Smasputra 		net_ipv4addrport_pr(&udp.udp_v6src, udp.udp_port);
708741Smasputra 		mdb_printf(" ");
709741Smasputra 		net_ipv4addrport_pr(&udp.udp_v6dst, udp.udp_dstport);
710741Smasputra 	} else if (af == AF_INET6) {
711741Smasputra 		net_ipv6addrport_pr(&udp.udp_v6src, udp.udp_port);
712741Smasputra 		mdb_printf(" ");
713741Smasputra 		net_ipv6addrport_pr(&udp.udp_v6dst, udp.udp_dstport);
714741Smasputra 	}
7159089SVasumathi.Sundaram@Sun.COM 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
7169089SVasumathi.Sundaram@Sun.COM 	mdb_printf(" %4i\n", connp->conn_zoneid);
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	return (WALK_NEXT);
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate 
7219089SVasumathi.Sundaram@Sun.COM /*ARGSUSED*/
7220Sstevel@tonic-gate static int
7239089SVasumathi.Sundaram@Sun.COM netstat_icmp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
724741Smasputra {
7259089SVasumathi.Sundaram@Sun.COM 	netstat_cb_data_t *ncb = cb_data;
7269089SVasumathi.Sundaram@Sun.COM 	int af = ncb->af;
7279089SVasumathi.Sundaram@Sun.COM 	icmp_t icmp;
7289089SVasumathi.Sundaram@Sun.COM 	conn_t *connp = &ncb->conn;
7299089SVasumathi.Sundaram@Sun.COM 	char *state;
7309089SVasumathi.Sundaram@Sun.COM 
7319089SVasumathi.Sundaram@Sun.COM 	if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
7329089SVasumathi.Sundaram@Sun.COM 		mdb_warn("failed to read conn_t at %p", kaddr);
7339089SVasumathi.Sundaram@Sun.COM 		return (WALK_ERR);
7349089SVasumathi.Sundaram@Sun.COM 	}
7359089SVasumathi.Sundaram@Sun.COM 
7369089SVasumathi.Sundaram@Sun.COM 	if (mdb_vread(&icmp, sizeof (icmp_t),
7379089SVasumathi.Sundaram@Sun.COM 	    (uintptr_t)connp->conn_icmp) == -1) {
7389089SVasumathi.Sundaram@Sun.COM 		mdb_warn("failed to read conn_icmp at %p",
7399089SVasumathi.Sundaram@Sun.COM 		    (uintptr_t)connp->conn_icmp);
7409089SVasumathi.Sundaram@Sun.COM 		return (WALK_ERR);
7419089SVasumathi.Sundaram@Sun.COM 	}
7429089SVasumathi.Sundaram@Sun.COM 
7439089SVasumathi.Sundaram@Sun.COM 	if ((af == AF_INET && icmp.icmp_ipversion != IPV4_VERSION) ||
7449089SVasumathi.Sundaram@Sun.COM 	    (af == AF_INET6 && icmp.icmp_ipversion != IPV6_VERSION)) {
7459089SVasumathi.Sundaram@Sun.COM 		return (WALK_NEXT);
7469089SVasumathi.Sundaram@Sun.COM 	}
747741Smasputra 
7489089SVasumathi.Sundaram@Sun.COM 	if (icmp.icmp_state == TS_UNBND)
7499089SVasumathi.Sundaram@Sun.COM 		state = "UNBOUND";
7509089SVasumathi.Sundaram@Sun.COM 	else if (icmp.icmp_state == TS_IDLE)
7519089SVasumathi.Sundaram@Sun.COM 		state = "IDLE";
7529089SVasumathi.Sundaram@Sun.COM 	else if (icmp.icmp_state == TS_DATA_XFER)
7539089SVasumathi.Sundaram@Sun.COM 		state = "CONNECTED";
7549089SVasumathi.Sundaram@Sun.COM 	else
7559089SVasumathi.Sundaram@Sun.COM 		state = "UNKNOWN";
7569089SVasumathi.Sundaram@Sun.COM 
7579089SVasumathi.Sundaram@Sun.COM 	mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_icmp, state);
7589089SVasumathi.Sundaram@Sun.COM 	if (af == AF_INET) {
7599089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%*I ", ADDR_V4_WIDTH,
7609089SVasumathi.Sundaram@Sun.COM 		    V4_PART_OF_V6((icmp.icmp_v6src)));
7619089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%*I ", ADDR_V4_WIDTH,
7629089SVasumathi.Sundaram@Sun.COM 		    V4_PART_OF_V6((icmp.icmp_v6dst.sin6_addr)));
7639089SVasumathi.Sundaram@Sun.COM 	} else if (af == AF_INET6) {
7649089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%*N ", ADDR_V6_WIDTH, &icmp.icmp_v6src);
7659089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%*N ", ADDR_V6_WIDTH, &icmp.icmp_v6dst);
7669089SVasumathi.Sundaram@Sun.COM 	}
7679089SVasumathi.Sundaram@Sun.COM 	mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
7689089SVasumathi.Sundaram@Sun.COM 	mdb_printf(" %4i\n", icmp.icmp_zoneid);
7699089SVasumathi.Sundaram@Sun.COM 
7709089SVasumathi.Sundaram@Sun.COM 	return (WALK_NEXT);
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate /*
7740Sstevel@tonic-gate  * print the address of a unix domain socket
7750Sstevel@tonic-gate  *
7760Sstevel@tonic-gate  * so is the address of a AF_UNIX struct sonode in mdb's address space
7770Sstevel@tonic-gate  * soa is the address of the struct soaddr to print
7780Sstevel@tonic-gate  *
7790Sstevel@tonic-gate  * returns 0 on success, -1 otherwise
7800Sstevel@tonic-gate  */
7810Sstevel@tonic-gate static int
7828348SEric.Yu@Sun.COM netstat_unix_name_pr(const struct sotpi_sonode *st, const struct soaddr *soa)
7830Sstevel@tonic-gate {
7848348SEric.Yu@Sun.COM 	const struct sonode *so = &st->st_sonode;
7850Sstevel@tonic-gate 	const char none[] = " (none)";
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) {
7888348SEric.Yu@Sun.COM 		if (st->st_info.sti_faddr_noxlate) {
7890Sstevel@tonic-gate 			mdb_printf("%-14s ", " (socketpair)");
7900Sstevel@tonic-gate 		} else {
7910Sstevel@tonic-gate 			if (soa->soa_len > sizeof (sa_family_t)) {
7920Sstevel@tonic-gate 				char addr[MAXPATHLEN + 1];
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 				if (mdb_readstr(addr, sizeof (addr),
7950Sstevel@tonic-gate 				    (uintptr_t)&soa->soa_sa->sa_data) == -1) {
7960Sstevel@tonic-gate 					mdb_warn("failed to read unix address "
7970Sstevel@tonic-gate 					    "at %p", &soa->soa_sa->sa_data);
7980Sstevel@tonic-gate 					return (-1);
7990Sstevel@tonic-gate 				}
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 				mdb_printf("%-14s ", addr);
8020Sstevel@tonic-gate 			} else {
8030Sstevel@tonic-gate 				mdb_printf("%-14s ", none);
8040Sstevel@tonic-gate 			}
8050Sstevel@tonic-gate 		}
8060Sstevel@tonic-gate 	} else {
8070Sstevel@tonic-gate 		mdb_printf("%-14s ", none);
8080Sstevel@tonic-gate 	}
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	return (0);
8110Sstevel@tonic-gate }
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate /* based on sockfs_snapshot */
8140Sstevel@tonic-gate /*ARGSUSED*/
8150Sstevel@tonic-gate static int
8160Sstevel@tonic-gate netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
8170Sstevel@tonic-gate {
8188348SEric.Yu@Sun.COM 	const struct sotpi_sonode *st = walk_data;
8198348SEric.Yu@Sun.COM 	const struct sonode *so = &st->st_sonode;
8208348SEric.Yu@Sun.COM 	const struct sotpi_info *sti = &st->st_info;
8210Sstevel@tonic-gate 
8228348SEric.Yu@Sun.COM 	if (so->so_count == 0)
8230Sstevel@tonic-gate 		return (WALK_NEXT);
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	if (so->so_family != AF_UNIX) {
8260Sstevel@tonic-gate 		mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr);
8270Sstevel@tonic-gate 		return (WALK_ERR);
8280Sstevel@tonic-gate 	}
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	mdb_printf("%-?p ", kaddr);
8310Sstevel@tonic-gate 
8328348SEric.Yu@Sun.COM 	switch (sti->sti_serv_type) {
8335563Snordmark 	case T_CLTS:
8340Sstevel@tonic-gate 		mdb_printf("%-10s ", "dgram");
8350Sstevel@tonic-gate 		break;
8365563Snordmark 	case T_COTS:
8370Sstevel@tonic-gate 		mdb_printf("%-10s ", "stream");
8380Sstevel@tonic-gate 		break;
8395563Snordmark 	case T_COTS_ORD:
8400Sstevel@tonic-gate 		mdb_printf("%-10s ", "stream-ord");
8410Sstevel@tonic-gate 		break;
8425563Snordmark 	default:
8438348SEric.Yu@Sun.COM 		mdb_printf("%-10i ", sti->sti_serv_type);
8440Sstevel@tonic-gate 	}
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	if ((so->so_state & SS_ISBOUND) &&
8478348SEric.Yu@Sun.COM 	    (sti->sti_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
8488348SEric.Yu@Sun.COM 		mdb_printf("%0?p ", sti->sti_ux_laddr.soua_vp);
8490Sstevel@tonic-gate 	} else {
8500Sstevel@tonic-gate 		mdb_printf("%0?p ", NULL);
8510Sstevel@tonic-gate 	}
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	if ((so->so_state & SS_ISCONNECTED) &&
8548348SEric.Yu@Sun.COM 	    (sti->sti_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
8558348SEric.Yu@Sun.COM 		mdb_printf("%0?p ", sti->sti_ux_faddr.soua_vp);
8560Sstevel@tonic-gate 	} else {
8570Sstevel@tonic-gate 		mdb_printf("%0?p ", NULL);
8580Sstevel@tonic-gate 	}
8590Sstevel@tonic-gate 
8608348SEric.Yu@Sun.COM 	if (netstat_unix_name_pr(st, &sti->sti_laddr) == -1)
8610Sstevel@tonic-gate 		return (WALK_ERR);
8620Sstevel@tonic-gate 
8638348SEric.Yu@Sun.COM 	if (netstat_unix_name_pr(st, &sti->sti_faddr) == -1)
8640Sstevel@tonic-gate 		return (WALK_ERR);
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	mdb_printf("%4i\n", so->so_zoneid);
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	return (WALK_NEXT);
8690Sstevel@tonic-gate }
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate static void
8720Sstevel@tonic-gate netstat_tcp_verbose_header_pr(void)
8730Sstevel@tonic-gate {
8740Sstevel@tonic-gate 	mdb_printf("       %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n",
8750Sstevel@tonic-gate 	    "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss");
8760Sstevel@tonic-gate }
8770Sstevel@tonic-gate 
8781676Sjpk static void
8791676Sjpk get_ifname(const ire_t *ire, char *intf)
8801676Sjpk {
8811676Sjpk 	ill_t ill;
8821676Sjpk 
8831676Sjpk 	*intf = '\0';
8841676Sjpk 	if (ire->ire_type == IRE_CACHE) {
8851676Sjpk 		queue_t stq;
8861676Sjpk 
8871676Sjpk 		if (mdb_vread(&stq, sizeof (stq), (uintptr_t)ire->ire_stq) ==
8881676Sjpk 		    -1)
8891676Sjpk 			return;
8901676Sjpk 		if (mdb_vread(&ill, sizeof (ill), (uintptr_t)stq.q_ptr) == -1)
8911676Sjpk 			return;
8921676Sjpk 		(void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
8931676Sjpk 		    (uintptr_t)ill.ill_name);
8941676Sjpk 	} else if (ire->ire_ipif != NULL) {
8951676Sjpk 		ipif_t ipif;
8961676Sjpk 		char *cp;
8971676Sjpk 
8981676Sjpk 		if (mdb_vread(&ipif, sizeof (ipif),
8991676Sjpk 		    (uintptr_t)ire->ire_ipif) == -1)
9001676Sjpk 			return;
9011676Sjpk 		if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ipif.ipif_ill) ==
9021676Sjpk 		    -1)
9031676Sjpk 			return;
9041676Sjpk 		(void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
9051676Sjpk 		    (uintptr_t)ill.ill_name);
9061676Sjpk 		if (ipif.ipif_id != 0) {
9071676Sjpk 			cp = intf + strlen(intf);
9081676Sjpk 			(void) mdb_snprintf(cp, LIFNAMSIZ + 1 - (cp - intf),
9091676Sjpk 			    ":%u", ipif.ipif_id);
9101676Sjpk 		}
9111676Sjpk 	}
9121676Sjpk }
9131676Sjpk 
9141676Sjpk static void
9151676Sjpk get_v4flags(const ire_t *ire, char *flags)
9161676Sjpk {
9171676Sjpk 	(void) strcpy(flags, "U");
9181676Sjpk 	if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX ||
9191676Sjpk 	    ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT)
9201676Sjpk 		(void) strcat(flags, "G");
9211676Sjpk 	if (ire->ire_mask == IP_HOST_MASK)
9221676Sjpk 		(void) strcat(flags, "H");
9231676Sjpk 	if (ire->ire_type == IRE_HOST_REDIRECT)
9241676Sjpk 		(void) strcat(flags, "D");
9251676Sjpk 	if (ire->ire_type == IRE_CACHE)
9261676Sjpk 		(void) strcat(flags, "A");
9271676Sjpk 	if (ire->ire_type == IRE_BROADCAST)
9281676Sjpk 		(void) strcat(flags, "B");
9291676Sjpk 	if (ire->ire_type == IRE_LOCAL)
9301676Sjpk 		(void) strcat(flags, "L");
9311676Sjpk 	if (ire->ire_flags & RTF_MULTIRT)
9321676Sjpk 		(void) strcat(flags, "M");
9331676Sjpk 	if (ire->ire_flags & RTF_SETSRC)
9341676Sjpk 		(void) strcat(flags, "S");
9351676Sjpk }
9361676Sjpk 
9371676Sjpk static int
9381676Sjpk netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
9391676Sjpk {
9401676Sjpk 	const ire_t *ire = walk_data;
9411676Sjpk 	uint_t *opts = cb_data;
9421676Sjpk 	ipaddr_t gate;
9431676Sjpk 	char flags[10], intf[LIFNAMSIZ + 1];
9441676Sjpk 
9454823Sseb 	if (ire->ire_ipversion != IPV4_VERSION)
9461676Sjpk 		return (WALK_NEXT);
9471676Sjpk 
9481676Sjpk 	if (!(*opts & NETSTAT_ALL) && (ire->ire_type == IRE_CACHE ||
9491676Sjpk 	    ire->ire_type == IRE_BROADCAST || ire->ire_type == IRE_LOCAL))
9501676Sjpk 		return (WALK_NEXT);
9511676Sjpk 
9521676Sjpk 	if (*opts & NETSTAT_FIRST) {
9531676Sjpk 		*opts &= ~NETSTAT_FIRST;
9541676Sjpk 		mdb_printf("%<u>%s Table: IPv4%</u>\n",
9551676Sjpk 		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
9561676Sjpk 		if (*opts & NETSTAT_VERBOSE) {
9571676Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt  "
9581676Sjpk 			    " Ref Flg Out   In/Fwd%</u>\n",
9591676Sjpk 			    "Address", ADDR_V4_WIDTH, "Destination",
9601676Sjpk 			    ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway");
9611676Sjpk 		} else {
9621676Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref  Use   "
9631676Sjpk 			    "Interface%</u>\n",
9641676Sjpk 			    "Address", ADDR_V4_WIDTH, "Destination",
9651676Sjpk 			    ADDR_V4_WIDTH, "Gateway");
9661676Sjpk 		}
9671676Sjpk 	}
9681676Sjpk 
9691676Sjpk 	gate = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK|IRE_BROADCAST)) ?
9701676Sjpk 	    ire->ire_src_addr : ire->ire_gateway_addr;
9711676Sjpk 
9721676Sjpk 	get_v4flags(ire, flags);
9731676Sjpk 
9741676Sjpk 	get_ifname(ire, intf);
9751676Sjpk 
9761676Sjpk 	if (*opts & NETSTAT_VERBOSE) {
9771676Sjpk 		mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u "
9781676Sjpk 		    "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH,
9791676Sjpk 		    ire->ire_mask, ADDR_V4_WIDTH, gate, intf,
9801676Sjpk 		    ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ',
9811676Sjpk 		    ire->ire_uinfo.iulp_rtt, ire->ire_refcnt, flags,
9821676Sjpk 		    ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
9831676Sjpk 	} else {
9841676Sjpk 		mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr,
9851676Sjpk 		    ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags,
9861676Sjpk 		    ire->ire_refcnt,
9871676Sjpk 		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
9881676Sjpk 	}
9891676Sjpk 
9901676Sjpk 	return (WALK_NEXT);
9911676Sjpk }
9921676Sjpk 
9931676Sjpk int
9941676Sjpk ip_mask_to_plen_v6(const in6_addr_t *v6mask)
9951676Sjpk {
9961676Sjpk 	int plen;
9971676Sjpk 	int i;
9981676Sjpk 	uint32_t val;
9991676Sjpk 
10001676Sjpk 	for (i = 3; i >= 0; i--)
10011676Sjpk 		if (v6mask->s6_addr32[i] != 0)
10021676Sjpk 			break;
10031676Sjpk 	if (i < 0)
10041676Sjpk 		return (0);
10051676Sjpk 	plen = 32 + 32 * i;
10061676Sjpk 	val = v6mask->s6_addr32[i];
10071676Sjpk 	while (!(val & 1)) {
10081676Sjpk 		val >>= 1;
10091676Sjpk 		plen--;
10101676Sjpk 	}
10111676Sjpk 
10121676Sjpk 	return (plen);
10131676Sjpk }
10141676Sjpk 
10151676Sjpk static int
10161676Sjpk netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
10171676Sjpk {
10181676Sjpk 	const ire_t *ire = walk_data;
10191676Sjpk 	uint_t *opts = cb_data;
10201676Sjpk 	const in6_addr_t *gatep;
10211676Sjpk 	char deststr[ADDR_V6_WIDTH + 5];
10221676Sjpk 	char flags[10], intf[LIFNAMSIZ + 1];
10231676Sjpk 	int masklen;
10241676Sjpk 
10251676Sjpk 	if (ire->ire_ipversion != IPV6_VERSION)
10261676Sjpk 		return (WALK_NEXT);
10271676Sjpk 
10281676Sjpk 	if (!(*opts & NETSTAT_ALL) && ire->ire_type == IRE_CACHE)
10291676Sjpk 		return (WALK_NEXT);
10301676Sjpk 
10311676Sjpk 	if (*opts & NETSTAT_FIRST) {
10321676Sjpk 		*opts &= ~NETSTAT_FIRST;
10331676Sjpk 		mdb_printf("\n%<u>%s Table: IPv6%</u>\n",
10341676Sjpk 		    (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
10351676Sjpk 		if (*opts & NETSTAT_VERBOSE) {
10361676Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s If    PMTU   Rtt   Ref "
10371676Sjpk 			    "Flags Out    In/Fwd%</u>\n",
10381676Sjpk 			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
10391676Sjpk 			    ADDR_V6_WIDTH, "Gateway");
10401676Sjpk 		} else {
10411676Sjpk 			mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use    If"
10421676Sjpk 			    "%</u>\n",
10431676Sjpk 			    "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
10441676Sjpk 			    ADDR_V6_WIDTH, "Gateway");
10451676Sjpk 		}
10461676Sjpk 	}
10471676Sjpk 
10481676Sjpk 	gatep = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK)) ?
10491676Sjpk 	    &ire->ire_src_addr_v6 : &ire->ire_gateway_addr_v6;
10501676Sjpk 
10511676Sjpk 	masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6);
10521676Sjpk 	(void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d",
10531676Sjpk 	    &ire->ire_addr_v6, masklen);
10541676Sjpk 
10551676Sjpk 	(void) strcpy(flags, "U");
10561676Sjpk 	if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX ||
10571676Sjpk 	    ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT)
10581676Sjpk 		(void) strcat(flags, "G");
10591676Sjpk 	if (masklen == IPV6_ABITS)
10601676Sjpk 		(void) strcat(flags, "H");
10611676Sjpk 	if (ire->ire_type == IRE_HOST_REDIRECT)
10621676Sjpk 		(void) strcat(flags, "D");
10631676Sjpk 	if (ire->ire_type == IRE_CACHE)
10641676Sjpk 		(void) strcat(flags, "A");
10651676Sjpk 	if (ire->ire_type == IRE_LOCAL)
10661676Sjpk 		(void) strcat(flags, "L");
10671676Sjpk 	if (ire->ire_flags & RTF_MULTIRT)
10681676Sjpk 		(void) strcat(flags, "M");
10691676Sjpk 	if (ire->ire_flags & RTF_SETSRC)
10701676Sjpk 		(void) strcat(flags, "S");
10711676Sjpk 
10721676Sjpk 	get_ifname(ire, intf);
10731676Sjpk 
10741676Sjpk 	if (*opts & NETSTAT_VERBOSE) {
10751676Sjpk 		mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n",
10761676Sjpk 		    kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep,
10771676Sjpk 		    intf, ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ',
10781676Sjpk 		    ire->ire_uinfo.iulp_rtt, ire->ire_refcnt,
10791676Sjpk 		    flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
10801676Sjpk 	} else {
10811676Sjpk 		mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr,
10821676Sjpk 		    ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags,
10831676Sjpk 		    ire->ire_refcnt,
10841676Sjpk 		    ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
10851676Sjpk 	}
10861676Sjpk 
10871676Sjpk 	return (WALK_NEXT);
10881676Sjpk }
10891676Sjpk 
10909089SVasumathi.Sundaram@Sun.COM static void
10919089SVasumathi.Sundaram@Sun.COM netstat_header_v4(int proto)
10929089SVasumathi.Sundaram@Sun.COM {
10939089SVasumathi.Sundaram@Sun.COM 	if (proto == IPPROTO_TCP)
10949089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%<u>%-?s ", "TCPv4");
10959089SVasumathi.Sundaram@Sun.COM 	else if (proto == IPPROTO_UDP)
10969089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%<u>%-?s ", "UDPv4");
10979089SVasumathi.Sundaram@Sun.COM 	else if (proto == IPPROTO_ICMP)
10989089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%<u>%-?s ", "ICMPv4");
10999089SVasumathi.Sundaram@Sun.COM 	mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
11009089SVasumathi.Sundaram@Sun.COM 	    "", ADDR_V4_WIDTH, "Local Address",
11019089SVasumathi.Sundaram@Sun.COM 	    "", ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone");
11029089SVasumathi.Sundaram@Sun.COM }
11039089SVasumathi.Sundaram@Sun.COM 
11049089SVasumathi.Sundaram@Sun.COM static void
11059089SVasumathi.Sundaram@Sun.COM netstat_header_v6(int proto)
11069089SVasumathi.Sundaram@Sun.COM {
11079089SVasumathi.Sundaram@Sun.COM 	if (proto == IPPROTO_TCP)
11089089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%<u>%-?s ", "TCPv6");
11099089SVasumathi.Sundaram@Sun.COM 	else if (proto == IPPROTO_UDP)
11109089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%<u>%-?s ", "UDPv6");
11119089SVasumathi.Sundaram@Sun.COM 	else if (proto == IPPROTO_ICMP)
11129089SVasumathi.Sundaram@Sun.COM 		mdb_printf("%<u>%-?s ", "ICMPv6");
11139089SVasumathi.Sundaram@Sun.COM 	mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
11149089SVasumathi.Sundaram@Sun.COM 	    "", ADDR_V6_WIDTH, "Local Address",
11159089SVasumathi.Sundaram@Sun.COM 	    "", ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone");
11169089SVasumathi.Sundaram@Sun.COM }
11179089SVasumathi.Sundaram@Sun.COM 
11189089SVasumathi.Sundaram@Sun.COM static int
11199089SVasumathi.Sundaram@Sun.COM netstat_print_conn(const char *cache, int proto, mdb_walk_cb_t cbfunc,
11209089SVasumathi.Sundaram@Sun.COM     void *cbdata)
11219089SVasumathi.Sundaram@Sun.COM {
11229089SVasumathi.Sundaram@Sun.COM 	netstat_cb_data_t *ncb = cbdata;
11239089SVasumathi.Sundaram@Sun.COM 
11249089SVasumathi.Sundaram@Sun.COM 	if ((ncb->opts & NETSTAT_VERBOSE) && proto == IPPROTO_TCP)
11259089SVasumathi.Sundaram@Sun.COM 		netstat_tcp_verbose_header_pr();
11269089SVasumathi.Sundaram@Sun.COM 	if (mdb_walk(cache, cbfunc, cbdata) == -1) {
11279089SVasumathi.Sundaram@Sun.COM 		mdb_warn("failed to walk %s", cache);
11289089SVasumathi.Sundaram@Sun.COM 		return (DCMD_ERR);
11299089SVasumathi.Sundaram@Sun.COM 	}
11309089SVasumathi.Sundaram@Sun.COM 	return (DCMD_OK);
11319089SVasumathi.Sundaram@Sun.COM }
11329089SVasumathi.Sundaram@Sun.COM 
11339089SVasumathi.Sundaram@Sun.COM static int
11349089SVasumathi.Sundaram@Sun.COM netstat_print_common(const char *cache, int proto, mdb_walk_cb_t cbfunc,
11359089SVasumathi.Sundaram@Sun.COM     void *cbdata)
11369089SVasumathi.Sundaram@Sun.COM {
11379089SVasumathi.Sundaram@Sun.COM 	netstat_cb_data_t *ncb = cbdata;
11389089SVasumathi.Sundaram@Sun.COM 	int af = ncb->af;
11399089SVasumathi.Sundaram@Sun.COM 	int status = DCMD_OK;
11409089SVasumathi.Sundaram@Sun.COM 
11419089SVasumathi.Sundaram@Sun.COM 	if (af != AF_INET6) {
11429089SVasumathi.Sundaram@Sun.COM 		ncb->af = AF_INET;
11439089SVasumathi.Sundaram@Sun.COM 		netstat_header_v4(proto);
11449089SVasumathi.Sundaram@Sun.COM 		status = netstat_print_conn(cache, proto, cbfunc, cbdata);
11459089SVasumathi.Sundaram@Sun.COM 	}
11469089SVasumathi.Sundaram@Sun.COM 	if (status == DCMD_OK && af != AF_INET) {
11479089SVasumathi.Sundaram@Sun.COM 		ncb->af = AF_INET6;
11489089SVasumathi.Sundaram@Sun.COM 		netstat_header_v6(proto);
11499089SVasumathi.Sundaram@Sun.COM 		status = netstat_print_conn(cache, proto, cbfunc, cbdata);
11509089SVasumathi.Sundaram@Sun.COM 	}
11519089SVasumathi.Sundaram@Sun.COM 	ncb->af = af;
11529089SVasumathi.Sundaram@Sun.COM 	return (status);
11539089SVasumathi.Sundaram@Sun.COM }
11549089SVasumathi.Sundaram@Sun.COM 
11550Sstevel@tonic-gate /*ARGSUSED*/
11560Sstevel@tonic-gate int
11570Sstevel@tonic-gate netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
11580Sstevel@tonic-gate {
11590Sstevel@tonic-gate 	uint_t opts = 0;
11600Sstevel@tonic-gate 	const char *optf = NULL;
11610Sstevel@tonic-gate 	const char *optP = NULL;
11629089SVasumathi.Sundaram@Sun.COM 	netstat_cb_data_t *cbdata;
11639089SVasumathi.Sundaram@Sun.COM 	int status;
11649089SVasumathi.Sundaram@Sun.COM 	int af = 0;
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
11670Sstevel@tonic-gate 	    'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts,
11680Sstevel@tonic-gate 	    'f', MDB_OPT_STR, &optf,
11690Sstevel@tonic-gate 	    'P', MDB_OPT_STR, &optP,
11701676Sjpk 	    'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts,
11711676Sjpk 	    'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts,
11720Sstevel@tonic-gate 	    NULL) != argc)
11730Sstevel@tonic-gate 		return (DCMD_USAGE);
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 	if (optP != NULL) {
11769089SVasumathi.Sundaram@Sun.COM 		if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0) &&
11779089SVasumathi.Sundaram@Sun.COM 		    (strcmp("icmp", optP) != 0))
11780Sstevel@tonic-gate 			return (DCMD_USAGE);
11791676Sjpk 		if (opts & NETSTAT_ROUTE)
11801676Sjpk 			return (DCMD_USAGE);
11810Sstevel@tonic-gate 	}
11820Sstevel@tonic-gate 
11831676Sjpk 	if (optf == NULL)
11841676Sjpk 		opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX;
11851676Sjpk 	else if (strcmp("inet", optf) == 0)
11861676Sjpk 		opts |= NETSTAT_V4;
11871676Sjpk 	else if (strcmp("inet6", optf) == 0)
11881676Sjpk 		opts |= NETSTAT_V6;
11891676Sjpk 	else if (strcmp("unix", optf) == 0)
11901676Sjpk 		opts |= NETSTAT_UNIX;
11911676Sjpk 	else
11921676Sjpk 		return (DCMD_USAGE);
11931676Sjpk 
11941676Sjpk 	if (opts & NETSTAT_ROUTE) {
11951676Sjpk 		if (!(opts & (NETSTAT_V4|NETSTAT_V6)))
11960Sstevel@tonic-gate 			return (DCMD_USAGE);
11971676Sjpk 		if (opts & NETSTAT_V4) {
11981676Sjpk 			opts |= NETSTAT_FIRST;
11991676Sjpk 			if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) {
12001676Sjpk 				mdb_warn("failed to walk ip`ire");
12011676Sjpk 				return (DCMD_ERR);
12021676Sjpk 			}
12031676Sjpk 		}
12041676Sjpk 		if (opts & NETSTAT_V6) {
12051676Sjpk 			opts |= NETSTAT_FIRST;
12061676Sjpk 			if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) {
12071676Sjpk 				mdb_warn("failed to walk ip`ire");
12081676Sjpk 				return (DCMD_ERR);
12091676Sjpk 			}
12101676Sjpk 		}
12111676Sjpk 		return (DCMD_OK);
12120Sstevel@tonic-gate 	}
12130Sstevel@tonic-gate 
12149089SVasumathi.Sundaram@Sun.COM 	if ((opts & NETSTAT_UNIX) && (optP == NULL)) {
12150Sstevel@tonic-gate 		/* Print Unix Domain Sockets */
12160Sstevel@tonic-gate 		mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n",
12170Sstevel@tonic-gate 		    "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr",
12180Sstevel@tonic-gate 		    "Remote Addr", "Zone");
12190Sstevel@tonic-gate 
12200Sstevel@tonic-gate 		if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) {
12210Sstevel@tonic-gate 			mdb_warn("failed to walk genunix`sonode");
12220Sstevel@tonic-gate 			return (DCMD_ERR);
12230Sstevel@tonic-gate 		}
12249089SVasumathi.Sundaram@Sun.COM 		if (!(opts & (NETSTAT_V4 | NETSTAT_V6)))
12259089SVasumathi.Sundaram@Sun.COM 			return (DCMD_OK);
12260Sstevel@tonic-gate 	}
12270Sstevel@tonic-gate 
12289089SVasumathi.Sundaram@Sun.COM 	cbdata = mdb_alloc(sizeof (netstat_cb_data_t), UM_SLEEP);
12299089SVasumathi.Sundaram@Sun.COM 	cbdata->opts = opts;
12309089SVasumathi.Sundaram@Sun.COM 	if ((optf != NULL) && (opts & NETSTAT_V4))
12319089SVasumathi.Sundaram@Sun.COM 		af = AF_INET;
12329089SVasumathi.Sundaram@Sun.COM 	else if ((optf != NULL) && (opts & NETSTAT_V6))
12339089SVasumathi.Sundaram@Sun.COM 		af = AF_INET6;
12349089SVasumathi.Sundaram@Sun.COM 
12359089SVasumathi.Sundaram@Sun.COM 	cbdata->af = af;
12369089SVasumathi.Sundaram@Sun.COM 	if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
12379089SVasumathi.Sundaram@Sun.COM 		status = netstat_print_common("tcp_conn_cache", IPPROTO_TCP,
12389089SVasumathi.Sundaram@Sun.COM 		    netstat_tcp_cb, cbdata);
12399089SVasumathi.Sundaram@Sun.COM 		if (status != DCMD_OK)
12409089SVasumathi.Sundaram@Sun.COM 			goto out;
12419089SVasumathi.Sundaram@Sun.COM 	}
12429089SVasumathi.Sundaram@Sun.COM 
12439089SVasumathi.Sundaram@Sun.COM 	if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
12449089SVasumathi.Sundaram@Sun.COM 		status = netstat_print_common("udp_conn_cache", IPPROTO_UDP,
12459089SVasumathi.Sundaram@Sun.COM 		    netstat_udp_cb, cbdata);
12469089SVasumathi.Sundaram@Sun.COM 		if (status != DCMD_OK)
12479089SVasumathi.Sundaram@Sun.COM 			goto out;
12489089SVasumathi.Sundaram@Sun.COM 	}
12499089SVasumathi.Sundaram@Sun.COM 
12509089SVasumathi.Sundaram@Sun.COM 	if ((optP == NULL) || (strcmp("icmp", optP) == 0)) {
12519089SVasumathi.Sundaram@Sun.COM 		status = netstat_print_common("rawip_conn_cache", IPPROTO_ICMP,
12529089SVasumathi.Sundaram@Sun.COM 		    netstat_icmp_cb, cbdata);
12539089SVasumathi.Sundaram@Sun.COM 		if (status != DCMD_OK)
12549089SVasumathi.Sundaram@Sun.COM 			goto out;
12559089SVasumathi.Sundaram@Sun.COM 	}
12569089SVasumathi.Sundaram@Sun.COM out:
12579089SVasumathi.Sundaram@Sun.COM 	mdb_free(cbdata, sizeof (netstat_cb_data_t));
12589089SVasumathi.Sundaram@Sun.COM 	return (status);
12590Sstevel@tonic-gate }
1260*10491SRishi.Srivatsavai@Sun.COM 
1261*10491SRishi.Srivatsavai@Sun.COM /*
1262*10491SRishi.Srivatsavai@Sun.COM  * "::dladm show-bridge" support
1263*10491SRishi.Srivatsavai@Sun.COM  */
1264*10491SRishi.Srivatsavai@Sun.COM typedef struct {
1265*10491SRishi.Srivatsavai@Sun.COM 	uint_t opt_l;
1266*10491SRishi.Srivatsavai@Sun.COM 	uint_t opt_f;
1267*10491SRishi.Srivatsavai@Sun.COM 	uint_t opt_t;
1268*10491SRishi.Srivatsavai@Sun.COM 	const char *name;
1269*10491SRishi.Srivatsavai@Sun.COM 	clock_t lbolt;
1270*10491SRishi.Srivatsavai@Sun.COM 	boolean_t found;
1271*10491SRishi.Srivatsavai@Sun.COM 	uint_t nlinks;
1272*10491SRishi.Srivatsavai@Sun.COM 	uint_t nfwd;
1273*10491SRishi.Srivatsavai@Sun.COM 
1274*10491SRishi.Srivatsavai@Sun.COM 	/*
1275*10491SRishi.Srivatsavai@Sun.COM 	 * These structures are kept inside the 'args' for allocation reasons.
1276*10491SRishi.Srivatsavai@Sun.COM 	 * They're all large data structures (over 1K), and may cause the stack
1277*10491SRishi.Srivatsavai@Sun.COM 	 * to explode.  mdb and kmdb will fail in these cases, and thus we
1278*10491SRishi.Srivatsavai@Sun.COM 	 * allocate them from the heap.
1279*10491SRishi.Srivatsavai@Sun.COM 	 */
1280*10491SRishi.Srivatsavai@Sun.COM 	trill_inst_t ti;
1281*10491SRishi.Srivatsavai@Sun.COM 	bridge_link_t bl;
1282*10491SRishi.Srivatsavai@Sun.COM 	mac_impl_t mi;
1283*10491SRishi.Srivatsavai@Sun.COM } show_bridge_args_t;
1284*10491SRishi.Srivatsavai@Sun.COM 
1285*10491SRishi.Srivatsavai@Sun.COM static void
1286*10491SRishi.Srivatsavai@Sun.COM show_vlans(const uint8_t *vlans)
1287*10491SRishi.Srivatsavai@Sun.COM {
1288*10491SRishi.Srivatsavai@Sun.COM 	int i, bit;
1289*10491SRishi.Srivatsavai@Sun.COM 	uint8_t val;
1290*10491SRishi.Srivatsavai@Sun.COM 	int rstart = -1, rnext = -1;
1291*10491SRishi.Srivatsavai@Sun.COM 
1292*10491SRishi.Srivatsavai@Sun.COM 	for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) {
1293*10491SRishi.Srivatsavai@Sun.COM 		val = vlans[i];
1294*10491SRishi.Srivatsavai@Sun.COM 		if (i == 0)
1295*10491SRishi.Srivatsavai@Sun.COM 			val &= ~1;
1296*10491SRishi.Srivatsavai@Sun.COM 		while ((bit = mdb_ffs(val)) != 0) {
1297*10491SRishi.Srivatsavai@Sun.COM 			bit--;
1298*10491SRishi.Srivatsavai@Sun.COM 			val &= ~(1 << bit);
1299*10491SRishi.Srivatsavai@Sun.COM 			bit += i * sizeof (*vlans) * NBBY;
1300*10491SRishi.Srivatsavai@Sun.COM 			if (bit != rnext) {
1301*10491SRishi.Srivatsavai@Sun.COM 				if (rnext != -1 && rstart + 1 != rnext)
1302*10491SRishi.Srivatsavai@Sun.COM 					mdb_printf("-%d", rnext - 1);
1303*10491SRishi.Srivatsavai@Sun.COM 				if (rstart != -1)
1304*10491SRishi.Srivatsavai@Sun.COM 					mdb_printf(",");
1305*10491SRishi.Srivatsavai@Sun.COM 				mdb_printf("%d", bit);
1306*10491SRishi.Srivatsavai@Sun.COM 				rstart = bit;
1307*10491SRishi.Srivatsavai@Sun.COM 			}
1308*10491SRishi.Srivatsavai@Sun.COM 			rnext = bit + 1;
1309*10491SRishi.Srivatsavai@Sun.COM 		}
1310*10491SRishi.Srivatsavai@Sun.COM 	}
1311*10491SRishi.Srivatsavai@Sun.COM 	if (rnext != -1 && rstart + 1 != rnext)
1312*10491SRishi.Srivatsavai@Sun.COM 		mdb_printf("-%d", rnext - 1);
1313*10491SRishi.Srivatsavai@Sun.COM 	mdb_printf("\n");
1314*10491SRishi.Srivatsavai@Sun.COM }
1315*10491SRishi.Srivatsavai@Sun.COM 
1316*10491SRishi.Srivatsavai@Sun.COM /*
1317*10491SRishi.Srivatsavai@Sun.COM  * This callback is invoked by a walk of the links attached to a bridge.  If
1318*10491SRishi.Srivatsavai@Sun.COM  * we're showing link details, then they're printed here.  If not, then we just
1319*10491SRishi.Srivatsavai@Sun.COM  * count up the links for the bridge summary.
1320*10491SRishi.Srivatsavai@Sun.COM  */
1321*10491SRishi.Srivatsavai@Sun.COM static int
1322*10491SRishi.Srivatsavai@Sun.COM do_bridge_links(uintptr_t addr, const void *data, void *ptr)
1323*10491SRishi.Srivatsavai@Sun.COM {
1324*10491SRishi.Srivatsavai@Sun.COM 	show_bridge_args_t *args = ptr;
1325*10491SRishi.Srivatsavai@Sun.COM 	const bridge_link_t *blp = data;
1326*10491SRishi.Srivatsavai@Sun.COM 	char macaddr[ETHERADDRL * 3];
1327*10491SRishi.Srivatsavai@Sun.COM 	const char *name;
1328*10491SRishi.Srivatsavai@Sun.COM 
1329*10491SRishi.Srivatsavai@Sun.COM 	args->nlinks++;
1330*10491SRishi.Srivatsavai@Sun.COM 
1331*10491SRishi.Srivatsavai@Sun.COM 	if (!args->opt_l)
1332*10491SRishi.Srivatsavai@Sun.COM 		return (WALK_NEXT);
1333*10491SRishi.Srivatsavai@Sun.COM 
1334*10491SRishi.Srivatsavai@Sun.COM 	if (mdb_vread(&args->mi, sizeof (args->mi),
1335*10491SRishi.Srivatsavai@Sun.COM 	    (uintptr_t)blp->bl_mh) == -1) {
1336*10491SRishi.Srivatsavai@Sun.COM 		mdb_warn("cannot read mac data at %p", blp->bl_mh);
1337*10491SRishi.Srivatsavai@Sun.COM 		name = "?";
1338*10491SRishi.Srivatsavai@Sun.COM 	} else  {
1339*10491SRishi.Srivatsavai@Sun.COM 		name = args->mi.mi_name;
1340*10491SRishi.Srivatsavai@Sun.COM 	}
1341*10491SRishi.Srivatsavai@Sun.COM 
1342*10491SRishi.Srivatsavai@Sun.COM 	mdb_mac_addr(blp->bl_local_mac, ETHERADDRL, macaddr,
1343*10491SRishi.Srivatsavai@Sun.COM 	    sizeof (macaddr));
1344*10491SRishi.Srivatsavai@Sun.COM 
1345*10491SRishi.Srivatsavai@Sun.COM 	mdb_printf("%-?p %-16s %-17s %03X %-4d ", addr, name, macaddr,
1346*10491SRishi.Srivatsavai@Sun.COM 	    blp->bl_flags, blp->bl_pvid);
1347*10491SRishi.Srivatsavai@Sun.COM 
1348*10491SRishi.Srivatsavai@Sun.COM 	if (blp->bl_trilldata == NULL) {
1349*10491SRishi.Srivatsavai@Sun.COM 		switch (blp->bl_state) {
1350*10491SRishi.Srivatsavai@Sun.COM 		case BLS_BLOCKLISTEN:
1351*10491SRishi.Srivatsavai@Sun.COM 			name = "BLOCK";
1352*10491SRishi.Srivatsavai@Sun.COM 			break;
1353*10491SRishi.Srivatsavai@Sun.COM 		case BLS_LEARNING:
1354*10491SRishi.Srivatsavai@Sun.COM 			name = "LEARN";
1355*10491SRishi.Srivatsavai@Sun.COM 			break;
1356*10491SRishi.Srivatsavai@Sun.COM 		case BLS_FORWARDING:
1357*10491SRishi.Srivatsavai@Sun.COM 			name = "FWD";
1358*10491SRishi.Srivatsavai@Sun.COM 			break;
1359*10491SRishi.Srivatsavai@Sun.COM 		default:
1360*10491SRishi.Srivatsavai@Sun.COM 			name = "?";
1361*10491SRishi.Srivatsavai@Sun.COM 		}
1362*10491SRishi.Srivatsavai@Sun.COM 		mdb_printf("%-5s ", name);
1363*10491SRishi.Srivatsavai@Sun.COM 		show_vlans(blp->bl_vlans);
1364*10491SRishi.Srivatsavai@Sun.COM 	} else {
1365*10491SRishi.Srivatsavai@Sun.COM 		show_vlans(blp->bl_afs);
1366*10491SRishi.Srivatsavai@Sun.COM 	}
1367*10491SRishi.Srivatsavai@Sun.COM 
1368*10491SRishi.Srivatsavai@Sun.COM 	return (WALK_NEXT);
1369*10491SRishi.Srivatsavai@Sun.COM }
1370*10491SRishi.Srivatsavai@Sun.COM 
1371*10491SRishi.Srivatsavai@Sun.COM /*
1372*10491SRishi.Srivatsavai@Sun.COM  * It seems a shame to duplicate this code, but merging it with the link
1373*10491SRishi.Srivatsavai@Sun.COM  * printing code above is more trouble than it would be worth.
1374*10491SRishi.Srivatsavai@Sun.COM  */
1375*10491SRishi.Srivatsavai@Sun.COM static void
1376*10491SRishi.Srivatsavai@Sun.COM print_link_name(show_bridge_args_t *args, uintptr_t addr, char sep)
1377*10491SRishi.Srivatsavai@Sun.COM {
1378*10491SRishi.Srivatsavai@Sun.COM 	const char *name;
1379*10491SRishi.Srivatsavai@Sun.COM 
1380*10491SRishi.Srivatsavai@Sun.COM 	if (mdb_vread(&args->bl, sizeof (args->bl), addr) == -1) {
1381*10491SRishi.Srivatsavai@Sun.COM 		mdb_warn("cannot read bridge link at %p", addr);
1382*10491SRishi.Srivatsavai@Sun.COM 		return;
1383*10491SRishi.Srivatsavai@Sun.COM 	}
1384*10491SRishi.Srivatsavai@Sun.COM 
1385*10491SRishi.Srivatsavai@Sun.COM 	if (mdb_vread(&args->mi, sizeof (args->mi),
1386*10491SRishi.Srivatsavai@Sun.COM 	    (uintptr_t)args->bl.bl_mh) == -1) {
1387*10491SRishi.Srivatsavai@Sun.COM 		name = "?";
1388*10491SRishi.Srivatsavai@Sun.COM 	} else  {
1389*10491SRishi.Srivatsavai@Sun.COM 		name = args->mi.mi_name;
1390*10491SRishi.Srivatsavai@Sun.COM 	}
1391*10491SRishi.Srivatsavai@Sun.COM 
1392*10491SRishi.Srivatsavai@Sun.COM 	mdb_printf("%s%c", name, sep);
1393*10491SRishi.Srivatsavai@Sun.COM }
1394*10491SRishi.Srivatsavai@Sun.COM 
1395*10491SRishi.Srivatsavai@Sun.COM static int
1396*10491SRishi.Srivatsavai@Sun.COM do_bridge_fwd(uintptr_t addr, const void *data, void *ptr)
1397*10491SRishi.Srivatsavai@Sun.COM {
1398*10491SRishi.Srivatsavai@Sun.COM 	show_bridge_args_t *args = ptr;
1399*10491SRishi.Srivatsavai@Sun.COM 	const bridge_fwd_t *bfp = data;
1400*10491SRishi.Srivatsavai@Sun.COM 	char macaddr[ETHERADDRL * 3];
1401*10491SRishi.Srivatsavai@Sun.COM 	int i;
1402*10491SRishi.Srivatsavai@Sun.COM #define	MAX_FWD_LINKS	16
1403*10491SRishi.Srivatsavai@Sun.COM 	bridge_link_t *links[MAX_FWD_LINKS];
1404*10491SRishi.Srivatsavai@Sun.COM 	uint_t nlinks;
1405*10491SRishi.Srivatsavai@Sun.COM 
1406*10491SRishi.Srivatsavai@Sun.COM 	args->nfwd++;
1407*10491SRishi.Srivatsavai@Sun.COM 
1408*10491SRishi.Srivatsavai@Sun.COM 	if (!args->opt_f)
1409*10491SRishi.Srivatsavai@Sun.COM 		return (WALK_NEXT);
1410*10491SRishi.Srivatsavai@Sun.COM 
1411*10491SRishi.Srivatsavai@Sun.COM 	if ((nlinks = bfp->bf_nlinks) > MAX_FWD_LINKS)
1412*10491SRishi.Srivatsavai@Sun.COM 		nlinks = MAX_FWD_LINKS;
1413*10491SRishi.Srivatsavai@Sun.COM 
1414*10491SRishi.Srivatsavai@Sun.COM 	if (mdb_vread(links, sizeof (links[0]) * nlinks,
1415*10491SRishi.Srivatsavai@Sun.COM 	    (uintptr_t)bfp->bf_links) == -1) {
1416*10491SRishi.Srivatsavai@Sun.COM 		mdb_warn("cannot read bridge forwarding links at %p",
1417*10491SRishi.Srivatsavai@Sun.COM 		    bfp->bf_links);
1418*10491SRishi.Srivatsavai@Sun.COM 		return (WALK_ERR);
1419*10491SRishi.Srivatsavai@Sun.COM 	}
1420*10491SRishi.Srivatsavai@Sun.COM 
1421*10491SRishi.Srivatsavai@Sun.COM 	mdb_mac_addr(bfp->bf_dest, ETHERADDRL, macaddr, sizeof (macaddr));
1422*10491SRishi.Srivatsavai@Sun.COM 
1423*10491SRishi.Srivatsavai@Sun.COM 	mdb_printf("%-?p %-17s ", addr, macaddr);
1424*10491SRishi.Srivatsavai@Sun.COM 	if (bfp->bf_flags & BFF_LOCALADDR)
1425*10491SRishi.Srivatsavai@Sun.COM 		mdb_printf("%-7s", "[self]");
1426*10491SRishi.Srivatsavai@Sun.COM 	else
1427*10491SRishi.Srivatsavai@Sun.COM 		mdb_printf("t-%-5d", args->lbolt - bfp->bf_lastheard);
1428*10491SRishi.Srivatsavai@Sun.COM 	mdb_printf(" %-7u ", bfp->bf_refs);
1429*10491SRishi.Srivatsavai@Sun.COM 
1430*10491SRishi.Srivatsavai@Sun.COM 	if (bfp->bf_trill_nick != 0) {
1431*10491SRishi.Srivatsavai@Sun.COM 		mdb_printf("%d\n", bfp->bf_trill_nick);
1432*10491SRishi.Srivatsavai@Sun.COM 	} else {
1433*10491SRishi.Srivatsavai@Sun.COM 		for (i = 0; i < bfp->bf_nlinks; i++) {
1434*10491SRishi.Srivatsavai@Sun.COM 			print_link_name(args, (uintptr_t)links[i],
1435*10491SRishi.Srivatsavai@Sun.COM 			    i == bfp->bf_nlinks - 1 ? '\n' : ' ');
1436*10491SRishi.Srivatsavai@Sun.COM 		}
1437*10491SRishi.Srivatsavai@Sun.COM 	}
1438*10491SRishi.Srivatsavai@Sun.COM 
1439*10491SRishi.Srivatsavai@Sun.COM 	return (WALK_NEXT);
1440*10491SRishi.Srivatsavai@Sun.COM }
1441*10491SRishi.Srivatsavai@Sun.COM 
1442*10491SRishi.Srivatsavai@Sun.COM static int
1443*10491SRishi.Srivatsavai@Sun.COM do_show_bridge(uintptr_t addr, const void *data, void *ptr)
1444*10491SRishi.Srivatsavai@Sun.COM {
1445*10491SRishi.Srivatsavai@Sun.COM 	show_bridge_args_t *args = ptr;
1446*10491SRishi.Srivatsavai@Sun.COM 	bridge_inst_t bi;
1447*10491SRishi.Srivatsavai@Sun.COM 	const bridge_inst_t *bip;
1448*10491SRishi.Srivatsavai@Sun.COM 	trill_node_t tn;
1449*10491SRishi.Srivatsavai@Sun.COM 	trill_sock_t tsp;
1450*10491SRishi.Srivatsavai@Sun.COM 	trill_nickinfo_t tni;
1451*10491SRishi.Srivatsavai@Sun.COM 	char bname[MAXLINKNAMELEN];
1452*10491SRishi.Srivatsavai@Sun.COM 	char macaddr[ETHERADDRL * 3];
1453*10491SRishi.Srivatsavai@Sun.COM 	char *cp;
1454*10491SRishi.Srivatsavai@Sun.COM 	uint_t nnicks;
1455*10491SRishi.Srivatsavai@Sun.COM 	int i;
1456*10491SRishi.Srivatsavai@Sun.COM 
1457*10491SRishi.Srivatsavai@Sun.COM 	if (data != NULL) {
1458*10491SRishi.Srivatsavai@Sun.COM 		bip = data;
1459*10491SRishi.Srivatsavai@Sun.COM 	} else {
1460*10491SRishi.Srivatsavai@Sun.COM 		if (mdb_vread(&bi, sizeof (bi), addr) == -1) {
1461*10491SRishi.Srivatsavai@Sun.COM 			mdb_warn("cannot read bridge instance at %p", addr);
1462*10491SRishi.Srivatsavai@Sun.COM 			return (WALK_ERR);
1463*10491SRishi.Srivatsavai@Sun.COM 		}
1464*10491SRishi.Srivatsavai@Sun.COM 		bip = &bi;
1465*10491SRishi.Srivatsavai@Sun.COM 	}
1466*10491SRishi.Srivatsavai@Sun.COM 
1467*10491SRishi.Srivatsavai@Sun.COM 	(void) strncpy(bname, bip->bi_name, sizeof (bname) - 1);
1468*10491SRishi.Srivatsavai@Sun.COM 	bname[MAXLINKNAMELEN - 1] = '\0';
1469*10491SRishi.Srivatsavai@Sun.COM 	cp = bname + strlen(bname);
1470*10491SRishi.Srivatsavai@Sun.COM 	if (cp > bname && cp[-1] == '0')
1471*10491SRishi.Srivatsavai@Sun.COM 		cp[-1] = '\0';
1472*10491SRishi.Srivatsavai@Sun.COM 
1473*10491SRishi.Srivatsavai@Sun.COM 	if (args->name != NULL && strcmp(args->name, bname) != 0)
1474*10491SRishi.Srivatsavai@Sun.COM 		return (WALK_NEXT);
1475*10491SRishi.Srivatsavai@Sun.COM 
1476*10491SRishi.Srivatsavai@Sun.COM 	args->found = B_TRUE;
1477*10491SRishi.Srivatsavai@Sun.COM 	args->nlinks = args->nfwd = 0;
1478*10491SRishi.Srivatsavai@Sun.COM 
1479*10491SRishi.Srivatsavai@Sun.COM 	if (args->opt_l) {
1480*10491SRishi.Srivatsavai@Sun.COM 		mdb_printf("%-?s %-16s %-17s %3s %-4s ", "ADDR", "LINK",
1481*10491SRishi.Srivatsavai@Sun.COM 		    "MAC-ADDR", "FLG", "PVID");
1482*10491SRishi.Srivatsavai@Sun.COM 		if (bip->bi_trilldata == NULL)
1483*10491SRishi.Srivatsavai@Sun.COM 			mdb_printf("%-5s %s\n", "STATE", "VLANS");
1484*10491SRishi.Srivatsavai@Sun.COM 		else
1485*10491SRishi.Srivatsavai@Sun.COM 			mdb_printf("%s\n", "FWD-VLANS");
1486*10491SRishi.Srivatsavai@Sun.COM 	}
1487*10491SRishi.Srivatsavai@Sun.COM 
1488*10491SRishi.Srivatsavai@Sun.COM 	if (!args->opt_f && !args->opt_t &&
1489*10491SRishi.Srivatsavai@Sun.COM 	    mdb_pwalk("list", do_bridge_links, args,
1490*10491SRishi.Srivatsavai@Sun.COM 	    addr + offsetof(bridge_inst_t, bi_links)) != DCMD_OK)
1491*10491SRishi.Srivatsavai@Sun.COM 		return (WALK_ERR);
1492*10491SRishi.Srivatsavai@Sun.COM 
1493*10491SRishi.Srivatsavai@Sun.COM 	if (args->opt_f)
1494*10491SRishi.Srivatsavai@Sun.COM 		mdb_printf("%-?s %-17s %-7s %-7s %s\n", "ADDR", "DEST", "TIME",
1495*10491SRishi.Srivatsavai@Sun.COM 		    "REFS", "OUTPUT");
1496*10491SRishi.Srivatsavai@Sun.COM 
1497*10491SRishi.Srivatsavai@Sun.COM 	if (!args->opt_l && !args->opt_t &&
1498*10491SRishi.Srivatsavai@Sun.COM 	    mdb_pwalk("avl", do_bridge_fwd, args,
1499*10491SRishi.Srivatsavai@Sun.COM 	    addr + offsetof(bridge_inst_t, bi_fwd)) != DCMD_OK)
1500*10491SRishi.Srivatsavai@Sun.COM 		return (WALK_ERR);
1501*10491SRishi.Srivatsavai@Sun.COM 
1502*10491SRishi.Srivatsavai@Sun.COM 	nnicks = 0;
1503*10491SRishi.Srivatsavai@Sun.COM 	if (bip->bi_trilldata != NULL && !args->opt_l && !args->opt_f) {
1504*10491SRishi.Srivatsavai@Sun.COM 		if (mdb_vread(&args->ti, sizeof (args->ti),
1505*10491SRishi.Srivatsavai@Sun.COM 		    (uintptr_t)bip->bi_trilldata) == -1) {
1506*10491SRishi.Srivatsavai@Sun.COM 			mdb_warn("cannot read trill instance at %p",
1507*10491SRishi.Srivatsavai@Sun.COM 			    bip->bi_trilldata);
1508*10491SRishi.Srivatsavai@Sun.COM 			return (WALK_ERR);
1509*10491SRishi.Srivatsavai@Sun.COM 		}
1510*10491SRishi.Srivatsavai@Sun.COM 		if (args->opt_t)
1511*10491SRishi.Srivatsavai@Sun.COM 			mdb_printf("%-?s %-5s %-17s %s\n", "ADDR",
1512*10491SRishi.Srivatsavai@Sun.COM 			    "NICK", "NEXT-HOP", "LINK");
1513*10491SRishi.Srivatsavai@Sun.COM 		for (i = 0; i < RBRIDGE_NICKNAME_MAX; i++) {
1514*10491SRishi.Srivatsavai@Sun.COM 			if (args->ti.ti_nodes[i] == NULL)
1515*10491SRishi.Srivatsavai@Sun.COM 				continue;
1516*10491SRishi.Srivatsavai@Sun.COM 			if (args->opt_t) {
1517*10491SRishi.Srivatsavai@Sun.COM 				if (mdb_vread(&tn, sizeof (tn),
1518*10491SRishi.Srivatsavai@Sun.COM 				    (uintptr_t)args->ti.ti_nodes[i]) == -1) {
1519*10491SRishi.Srivatsavai@Sun.COM 					mdb_warn("cannot read trill node %d at "
1520*10491SRishi.Srivatsavai@Sun.COM 					    "%p", i, args->ti.ti_nodes[i]);
1521*10491SRishi.Srivatsavai@Sun.COM 					return (WALK_ERR);
1522*10491SRishi.Srivatsavai@Sun.COM 				}
1523*10491SRishi.Srivatsavai@Sun.COM 				if (mdb_vread(&tni, sizeof (tni),
1524*10491SRishi.Srivatsavai@Sun.COM 				    (uintptr_t)tn.tn_ni) == -1) {
1525*10491SRishi.Srivatsavai@Sun.COM 					mdb_warn("cannot read trill node info "
1526*10491SRishi.Srivatsavai@Sun.COM 					    "%d at %p", i, tn.tn_ni);
1527*10491SRishi.Srivatsavai@Sun.COM 					return (WALK_ERR);
1528*10491SRishi.Srivatsavai@Sun.COM 				}
1529*10491SRishi.Srivatsavai@Sun.COM 				mdb_mac_addr(tni.tni_adjsnpa, ETHERADDRL,
1530*10491SRishi.Srivatsavai@Sun.COM 				    macaddr, sizeof (macaddr));
1531*10491SRishi.Srivatsavai@Sun.COM 				if (tni.tni_nick == args->ti.ti_nick) {
1532*10491SRishi.Srivatsavai@Sun.COM 					(void) strcpy(macaddr, "[self]");
1533*10491SRishi.Srivatsavai@Sun.COM 				}
1534*10491SRishi.Srivatsavai@Sun.COM 				mdb_printf("%-?p %-5u %-17s ",
1535*10491SRishi.Srivatsavai@Sun.COM 				    args->ti.ti_nodes[i], tni.tni_nick,
1536*10491SRishi.Srivatsavai@Sun.COM 				    macaddr);
1537*10491SRishi.Srivatsavai@Sun.COM 				if (tn.tn_tsp != NULL) {
1538*10491SRishi.Srivatsavai@Sun.COM 					if (mdb_vread(&tsp, sizeof (tsp),
1539*10491SRishi.Srivatsavai@Sun.COM 					    (uintptr_t)tn.tn_tsp) == -1) {
1540*10491SRishi.Srivatsavai@Sun.COM 						mdb_warn("cannot read trill "
1541*10491SRishi.Srivatsavai@Sun.COM 						    "socket info at %p",
1542*10491SRishi.Srivatsavai@Sun.COM 						    tn.tn_tsp);
1543*10491SRishi.Srivatsavai@Sun.COM 						return (WALK_ERR);
1544*10491SRishi.Srivatsavai@Sun.COM 					}
1545*10491SRishi.Srivatsavai@Sun.COM 					if (tsp.ts_link != NULL) {
1546*10491SRishi.Srivatsavai@Sun.COM 						print_link_name(args,
1547*10491SRishi.Srivatsavai@Sun.COM 						    (uintptr_t)tsp.ts_link,
1548*10491SRishi.Srivatsavai@Sun.COM 						    '\n');
1549*10491SRishi.Srivatsavai@Sun.COM 						continue;
1550*10491SRishi.Srivatsavai@Sun.COM 					}
1551*10491SRishi.Srivatsavai@Sun.COM 				}
1552*10491SRishi.Srivatsavai@Sun.COM 				mdb_printf("--\n");
1553*10491SRishi.Srivatsavai@Sun.COM 			} else {
1554*10491SRishi.Srivatsavai@Sun.COM 				nnicks++;
1555*10491SRishi.Srivatsavai@Sun.COM 			}
1556*10491SRishi.Srivatsavai@Sun.COM 		}
1557*10491SRishi.Srivatsavai@Sun.COM 	} else {
1558*10491SRishi.Srivatsavai@Sun.COM 		if (args->opt_t)
1559*10491SRishi.Srivatsavai@Sun.COM 			mdb_printf("bridge is not running TRILL\n");
1560*10491SRishi.Srivatsavai@Sun.COM 	}
1561*10491SRishi.Srivatsavai@Sun.COM 
1562*10491SRishi.Srivatsavai@Sun.COM 	if (!args->opt_l && !args->opt_f && !args->opt_t) {
1563*10491SRishi.Srivatsavai@Sun.COM 		mdb_printf("%-?p %-7s %-16s %-7u %-7u", addr,
1564*10491SRishi.Srivatsavai@Sun.COM 		    bip->bi_trilldata == NULL ? "stp" : "trill", bname,
1565*10491SRishi.Srivatsavai@Sun.COM 		    args->nlinks, args->nfwd);
1566*10491SRishi.Srivatsavai@Sun.COM 		if (bip->bi_trilldata != NULL)
1567*10491SRishi.Srivatsavai@Sun.COM 			mdb_printf(" %-7u %u\n", nnicks, args->ti.ti_nick);
1568*10491SRishi.Srivatsavai@Sun.COM 		else
1569*10491SRishi.Srivatsavai@Sun.COM 			mdb_printf(" %-7s %s\n", "--", "--");
1570*10491SRishi.Srivatsavai@Sun.COM 	}
1571*10491SRishi.Srivatsavai@Sun.COM 	return (WALK_NEXT);
1572*10491SRishi.Srivatsavai@Sun.COM }
1573*10491SRishi.Srivatsavai@Sun.COM 
1574*10491SRishi.Srivatsavai@Sun.COM static int
1575*10491SRishi.Srivatsavai@Sun.COM dladm_show_bridge(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1576*10491SRishi.Srivatsavai@Sun.COM {
1577*10491SRishi.Srivatsavai@Sun.COM 	show_bridge_args_t *args;
1578*10491SRishi.Srivatsavai@Sun.COM 	GElf_Sym sym;
1579*10491SRishi.Srivatsavai@Sun.COM 	int i;
1580*10491SRishi.Srivatsavai@Sun.COM 
1581*10491SRishi.Srivatsavai@Sun.COM 	args = mdb_zalloc(sizeof (*args), UM_SLEEP);
1582*10491SRishi.Srivatsavai@Sun.COM 
1583*10491SRishi.Srivatsavai@Sun.COM 	i = mdb_getopts(argc, argv,
1584*10491SRishi.Srivatsavai@Sun.COM 	    'l', MDB_OPT_SETBITS, 1, &args->opt_l,
1585*10491SRishi.Srivatsavai@Sun.COM 	    'f', MDB_OPT_SETBITS, 1, &args->opt_f,
1586*10491SRishi.Srivatsavai@Sun.COM 	    't', MDB_OPT_SETBITS, 1, &args->opt_t,
1587*10491SRishi.Srivatsavai@Sun.COM 	    NULL);
1588*10491SRishi.Srivatsavai@Sun.COM 
1589*10491SRishi.Srivatsavai@Sun.COM 	argc -= i;
1590*10491SRishi.Srivatsavai@Sun.COM 	argv += i;
1591*10491SRishi.Srivatsavai@Sun.COM 
1592*10491SRishi.Srivatsavai@Sun.COM 	if (argc > 1 || (argc == 1 && argv[0].a_type != MDB_TYPE_STRING)) {
1593*10491SRishi.Srivatsavai@Sun.COM 		mdb_free(args, sizeof (*args));
1594*10491SRishi.Srivatsavai@Sun.COM 		return (DCMD_USAGE);
1595*10491SRishi.Srivatsavai@Sun.COM 	}
1596*10491SRishi.Srivatsavai@Sun.COM 	if (argc == 1)
1597*10491SRishi.Srivatsavai@Sun.COM 		args->name = argv[0].a_un.a_str;
1598*10491SRishi.Srivatsavai@Sun.COM 
1599*10491SRishi.Srivatsavai@Sun.COM 	if (mdb_readvar(&args->lbolt,
1600*10491SRishi.Srivatsavai@Sun.COM 	    mdb_prop_postmortem ? "panic_lbolt" : "lbolt") == -1) {
1601*10491SRishi.Srivatsavai@Sun.COM 		mdb_warn("failed to read lbolt");
1602*10491SRishi.Srivatsavai@Sun.COM 		goto err;
1603*10491SRishi.Srivatsavai@Sun.COM 	}
1604*10491SRishi.Srivatsavai@Sun.COM 
1605*10491SRishi.Srivatsavai@Sun.COM 	if (flags & DCMD_ADDRSPEC) {
1606*10491SRishi.Srivatsavai@Sun.COM 		if (args->name != NULL) {
1607*10491SRishi.Srivatsavai@Sun.COM 			mdb_printf("bridge name and address are mutually "
1608*10491SRishi.Srivatsavai@Sun.COM 			    "exclusive\n");
1609*10491SRishi.Srivatsavai@Sun.COM 			goto err;
1610*10491SRishi.Srivatsavai@Sun.COM 		}
1611*10491SRishi.Srivatsavai@Sun.COM 		if (!args->opt_l && !args->opt_f && !args->opt_t)
1612*10491SRishi.Srivatsavai@Sun.COM 			mdb_printf("%-?s %-7s %-16s %-7s %-7s\n", "ADDR",
1613*10491SRishi.Srivatsavai@Sun.COM 			    "PROTECT", "NAME", "NLINKS", "NFWD");
1614*10491SRishi.Srivatsavai@Sun.COM 		if (do_show_bridge(addr, NULL, args) != WALK_NEXT)
1615*10491SRishi.Srivatsavai@Sun.COM 			goto err;
1616*10491SRishi.Srivatsavai@Sun.COM 		mdb_free(args, sizeof (*args));
1617*10491SRishi.Srivatsavai@Sun.COM 		return (DCMD_OK);
1618*10491SRishi.Srivatsavai@Sun.COM 	} else {
1619*10491SRishi.Srivatsavai@Sun.COM 		if ((args->opt_l || args->opt_f || args->opt_t) &&
1620*10491SRishi.Srivatsavai@Sun.COM 		    args->name == NULL) {
1621*10491SRishi.Srivatsavai@Sun.COM 			mdb_printf("need bridge name or address with -[lft]\n");
1622*10491SRishi.Srivatsavai@Sun.COM 			goto err;
1623*10491SRishi.Srivatsavai@Sun.COM 		}
1624*10491SRishi.Srivatsavai@Sun.COM 		if (mdb_lookup_by_obj("bridge", "inst_list", &sym) == -1) {
1625*10491SRishi.Srivatsavai@Sun.COM 			mdb_warn("failed to find 'bridge`inst_list'");
1626*10491SRishi.Srivatsavai@Sun.COM 			goto err;
1627*10491SRishi.Srivatsavai@Sun.COM 		}
1628*10491SRishi.Srivatsavai@Sun.COM 		if (!args->opt_l && !args->opt_f && !args->opt_t)
1629*10491SRishi.Srivatsavai@Sun.COM 			mdb_printf("%-?s %-7s %-16s %-7s %-7s %-7s %s\n",
1630*10491SRishi.Srivatsavai@Sun.COM 			    "ADDR", "PROTECT", "NAME", "NLINKS", "NFWD",
1631*10491SRishi.Srivatsavai@Sun.COM 			    "NNICKS", "NICK");
1632*10491SRishi.Srivatsavai@Sun.COM 		if (mdb_pwalk("list", do_show_bridge, args,
1633*10491SRishi.Srivatsavai@Sun.COM 		    (uintptr_t)sym.st_value) != DCMD_OK)
1634*10491SRishi.Srivatsavai@Sun.COM 			goto err;
1635*10491SRishi.Srivatsavai@Sun.COM 		if (!args->found && args->name != NULL) {
1636*10491SRishi.Srivatsavai@Sun.COM 			mdb_printf("bridge instance %s not found\n",
1637*10491SRishi.Srivatsavai@Sun.COM 			    args->name);
1638*10491SRishi.Srivatsavai@Sun.COM 			goto err;
1639*10491SRishi.Srivatsavai@Sun.COM 		}
1640*10491SRishi.Srivatsavai@Sun.COM 		mdb_free(args, sizeof (*args));
1641*10491SRishi.Srivatsavai@Sun.COM 		return (DCMD_OK);
1642*10491SRishi.Srivatsavai@Sun.COM 	}
1643*10491SRishi.Srivatsavai@Sun.COM 
1644*10491SRishi.Srivatsavai@Sun.COM err:
1645*10491SRishi.Srivatsavai@Sun.COM 	mdb_free(args, sizeof (*args));
1646*10491SRishi.Srivatsavai@Sun.COM 	return (DCMD_ERR);
1647*10491SRishi.Srivatsavai@Sun.COM }
1648*10491SRishi.Srivatsavai@Sun.COM 
1649*10491SRishi.Srivatsavai@Sun.COM /*
1650*10491SRishi.Srivatsavai@Sun.COM  * Support for the "::dladm" dcmd
1651*10491SRishi.Srivatsavai@Sun.COM  */
1652*10491SRishi.Srivatsavai@Sun.COM int
1653*10491SRishi.Srivatsavai@Sun.COM dladm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1654*10491SRishi.Srivatsavai@Sun.COM {
1655*10491SRishi.Srivatsavai@Sun.COM 	if (argc < 1 || argv[0].a_type != MDB_TYPE_STRING)
1656*10491SRishi.Srivatsavai@Sun.COM 		return (DCMD_USAGE);
1657*10491SRishi.Srivatsavai@Sun.COM 
1658*10491SRishi.Srivatsavai@Sun.COM 	/*
1659*10491SRishi.Srivatsavai@Sun.COM 	 * This could be a bit more elaborate, once we support more of the
1660*10491SRishi.Srivatsavai@Sun.COM 	 * dladm show-* subcommands.
1661*10491SRishi.Srivatsavai@Sun.COM 	 */
1662*10491SRishi.Srivatsavai@Sun.COM 	argc--;
1663*10491SRishi.Srivatsavai@Sun.COM 	argv++;
1664*10491SRishi.Srivatsavai@Sun.COM 	if (strcmp(argv[-1].a_un.a_str, "show-bridge") == 0)
1665*10491SRishi.Srivatsavai@Sun.COM 		return (dladm_show_bridge(addr, flags, argc, argv));
1666*10491SRishi.Srivatsavai@Sun.COM 
1667*10491SRishi.Srivatsavai@Sun.COM 	return (DCMD_USAGE);
1668*10491SRishi.Srivatsavai@Sun.COM }
1669*10491SRishi.Srivatsavai@Sun.COM 
1670*10491SRishi.Srivatsavai@Sun.COM void
1671*10491SRishi.Srivatsavai@Sun.COM dladm_help(void)
1672*10491SRishi.Srivatsavai@Sun.COM {
1673*10491SRishi.Srivatsavai@Sun.COM 	mdb_printf("Subcommands:\n"
1674*10491SRishi.Srivatsavai@Sun.COM 	    "  show-bridge [-flt] [<name>]\n"
1675*10491SRishi.Srivatsavai@Sun.COM 	    "\t     Show bridge information; -l for links and -f for "
1676*10491SRishi.Srivatsavai@Sun.COM 	    "forwarding\n"
1677*10491SRishi.Srivatsavai@Sun.COM 	    "\t     entries, and -t for TRILL nicknames.  Address is required "
1678*10491SRishi.Srivatsavai@Sun.COM 	    "if name\n"
1679*10491SRishi.Srivatsavai@Sun.COM 	    "\t     is not specified.\n");
1680*10491SRishi.Srivatsavai@Sun.COM }
1681