xref: /onnv-gate/usr/src/cmd/mdb/common/modules/ip/ip.c (revision 5940:7ecee203b824)
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
52546Scarlsonj  * Common Development and Distribution License (the "License").
62546Scarlsonj  * 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 /*
22*5940Ssowmini  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/stropts.h>
300Sstevel@tonic-gate #include <sys/stream.h>
310Sstevel@tonic-gate #include <sys/socket.h>
320Sstevel@tonic-gate #include <sys/avl_impl.h>
330Sstevel@tonic-gate #include <net/if.h>
340Sstevel@tonic-gate #include <net/route.h>
350Sstevel@tonic-gate #include <netinet/in.h>
360Sstevel@tonic-gate #include <netinet/ip6.h>
370Sstevel@tonic-gate #include <netinet/udp.h>
380Sstevel@tonic-gate #include <netinet/sctp.h>
390Sstevel@tonic-gate #include <inet/mib2.h>
400Sstevel@tonic-gate #include <inet/common.h>
410Sstevel@tonic-gate #include <inet/ip.h>
420Sstevel@tonic-gate #include <inet/ip_ire.h>
430Sstevel@tonic-gate #include <inet/ip6.h>
440Sstevel@tonic-gate #include <inet/ipclassifier.h>
450Sstevel@tonic-gate #include <inet/mi.h>
460Sstevel@tonic-gate #include <sys/squeue_impl.h>
475023Scarlsonj #include <sys/modhash_impl.h>
48*5940Ssowmini #include <inet/ip_ndp.h>
49*5940Ssowmini #include <inet/ip_if.h>
50*5940Ssowmini #include <sys/dlpi.h>
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
530Sstevel@tonic-gate #include <mdb/mdb_ks.h>
540Sstevel@tonic-gate 
550Sstevel@tonic-gate #define	ADDR_WIDTH 11
56*5940Ssowmini #define	L2MAXADDRSTRLEN	255
57*5940Ssowmini #define	MAX_SAP_LEN	255
580Sstevel@tonic-gate 
590Sstevel@tonic-gate typedef struct {
600Sstevel@tonic-gate 	const char *bit_name;	/* name of bit */
610Sstevel@tonic-gate 	const char *bit_descr;	/* description of bit's purpose */
620Sstevel@tonic-gate } bitname_t;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate static const bitname_t squeue_states[] = {
650Sstevel@tonic-gate 	{ "SQS_PROC",		"being processed" },
660Sstevel@tonic-gate 	{ "SQS_WORKER",		"... by a worker thread" },
670Sstevel@tonic-gate 	{ "SQS_ENTER",		"... by an squeue_enter() thread" },
680Sstevel@tonic-gate 	{ "SQS_FAST",		"... in fast-path mode" },
690Sstevel@tonic-gate 	{ "SQS_USER", 		"A non interrupt user" },
700Sstevel@tonic-gate 	{ "SQS_BOUND",		"worker thread bound to CPU" },
710Sstevel@tonic-gate 	{ "SQS_PROFILE",	"profiling enabled" },
720Sstevel@tonic-gate 	{ "SQS_REENTER",	"re-entered thred" },
730Sstevel@tonic-gate 	{ NULL }
740Sstevel@tonic-gate };
750Sstevel@tonic-gate 
760Sstevel@tonic-gate typedef struct illif_walk_data {
770Sstevel@tonic-gate 	ill_g_head_t ill_g_heads[MAX_G_HEADS];
780Sstevel@tonic-gate 	int ill_list;
790Sstevel@tonic-gate 	ill_if_t ill_if;
800Sstevel@tonic-gate } illif_walk_data_t;
810Sstevel@tonic-gate 
82*5940Ssowmini typedef struct nce_walk_data_s {
83*5940Ssowmini 	struct ndp_g_s	nce_ip_ndp;
84*5940Ssowmini 	int		nce_hash_tbl_index;
85*5940Ssowmini 	nce_t 		nce;
86*5940Ssowmini } nce_walk_data_t;
87*5940Ssowmini 
88*5940Ssowmini typedef struct nce_cbdata_s {
89*5940Ssowmini 	uintptr_t nce_addr;
90*5940Ssowmini 	int	  nce_ipversion;
91*5940Ssowmini } nce_cbdata_t;
92*5940Ssowmini 
93*5940Ssowmini typedef struct ire_cbdata_s {
94*5940Ssowmini 	int		ire_ipversion;
95*5940Ssowmini 	boolean_t	verbose;
96*5940Ssowmini } ire_cbdata_t;
97*5940Ssowmini 
985023Scarlsonj typedef struct th_walk_data {
995023Scarlsonj 	uint_t		thw_non_zero_only;
1005023Scarlsonj 	boolean_t	thw_match;
1015023Scarlsonj 	uintptr_t	thw_matchkey;
1025023Scarlsonj 	uintptr_t	thw_ipst;
1035023Scarlsonj 	clock_t		thw_lbolt;
1045023Scarlsonj } th_walk_data_t;
1055023Scarlsonj 
1060Sstevel@tonic-gate static int iphdr(uintptr_t, uint_t, int, const mdb_arg_t *);
1070Sstevel@tonic-gate static int ip6hdr(uintptr_t, uint_t, int, const mdb_arg_t *);
1080Sstevel@tonic-gate 
109*5940Ssowmini static int ire_format(uintptr_t addr, const void *, void *);
110*5940Ssowmini static int nce_format(uintptr_t addr, const nce_t *nce, int ipversion);
111*5940Ssowmini static int nce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv);
112*5940Ssowmini static int nce_walk_step(mdb_walk_state_t *wsp);
113*5940Ssowmini static int nce_stack_walk_init(mdb_walk_state_t *wsp);
114*5940Ssowmini static int nce_stack_walk_step(mdb_walk_state_t *wsp);
115*5940Ssowmini static void nce_stack_walk_fini(mdb_walk_state_t *wsp);
116*5940Ssowmini static int nce_cb(uintptr_t addr, const nce_walk_data_t *iw, nce_cbdata_t *id);
1173448Sdh155122 
1183448Sdh155122 /*
1193448Sdh155122  * Given the kernel address of an ip_stack_t, return the stackid
1203448Sdh155122  */
1213448Sdh155122 static int
1223448Sdh155122 ips_to_stackid(uintptr_t kaddr)
1233448Sdh155122 {
1243448Sdh155122 	ip_stack_t ipss;
1253448Sdh155122 	netstack_t nss;
1263448Sdh155122 
1273448Sdh155122 	if (mdb_vread(&ipss, sizeof (ipss), kaddr) == -1) {
1283448Sdh155122 		mdb_warn("failed to read ip_stack_t %p", kaddr);
1293448Sdh155122 		return (0);
1303448Sdh155122 	}
1313448Sdh155122 	kaddr = (uintptr_t)ipss.ips_netstack;
1323448Sdh155122 	if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
1333448Sdh155122 		mdb_warn("failed to read netstack_t %p", kaddr);
1343448Sdh155122 		return (0);
1353448Sdh155122 	}
1363448Sdh155122 	return (nss.netstack_stackid);
1373448Sdh155122 }
1383448Sdh155122 
1390Sstevel@tonic-gate int
1403448Sdh155122 ip_stacks_walk_init(mdb_walk_state_t *wsp)
1413448Sdh155122 {
1423448Sdh155122 	if (mdb_layered_walk("netstack", wsp) == -1) {
1433448Sdh155122 		mdb_warn("can't walk 'netstack'");
1443448Sdh155122 		return (WALK_ERR);
1453448Sdh155122 	}
1463448Sdh155122 	return (WALK_NEXT);
1473448Sdh155122 }
1483448Sdh155122 
1493448Sdh155122 int
1503448Sdh155122 ip_stacks_walk_step(mdb_walk_state_t *wsp)
1513448Sdh155122 {
1523448Sdh155122 	uintptr_t kaddr;
1533448Sdh155122 	netstack_t nss;
1543448Sdh155122 
1553448Sdh155122 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
1563448Sdh155122 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
1573448Sdh155122 		return (WALK_ERR);
1583448Sdh155122 	}
1593448Sdh155122 	kaddr = (uintptr_t)nss.netstack_modules[NS_IP];
1603448Sdh155122 
1613448Sdh155122 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
1623448Sdh155122 }
1633448Sdh155122 
1645023Scarlsonj int
1655023Scarlsonj th_hash_walk_init(mdb_walk_state_t *wsp)
1665023Scarlsonj {
1675023Scarlsonj 	GElf_Sym sym;
1685023Scarlsonj 	list_node_t *next;
1695023Scarlsonj 
1705023Scarlsonj 	if (wsp->walk_addr == NULL) {
1715023Scarlsonj 		if (mdb_lookup_by_obj("ip", "ip_thread_list", &sym) == 0) {
1725023Scarlsonj 			wsp->walk_addr = sym.st_value;
1735023Scarlsonj 		} else {
1745023Scarlsonj 			mdb_warn("unable to locate ip_thread_list\n");
1755023Scarlsonj 			return (WALK_ERR);
1765023Scarlsonj 		}
1775023Scarlsonj 	}
1785023Scarlsonj 
1795023Scarlsonj 	if (mdb_vread(&next, sizeof (next),
1805023Scarlsonj 	    wsp->walk_addr + offsetof(list_t, list_head) +
1815023Scarlsonj 	    offsetof(list_node_t, list_next)) == -1 ||
1825023Scarlsonj 	    next == NULL) {
1835023Scarlsonj 		mdb_warn("non-DEBUG image; cannot walk th_hash list\n");
1845023Scarlsonj 		return (WALK_ERR);
1855023Scarlsonj 	}
1865023Scarlsonj 
1875023Scarlsonj 	if (mdb_layered_walk("list", wsp) == -1) {
1885023Scarlsonj 		mdb_warn("can't walk 'list'");
1895023Scarlsonj 		return (WALK_ERR);
1905023Scarlsonj 	} else {
1915023Scarlsonj 		return (WALK_NEXT);
1925023Scarlsonj 	}
1935023Scarlsonj }
1945023Scarlsonj 
1955023Scarlsonj int
1965023Scarlsonj th_hash_walk_step(mdb_walk_state_t *wsp)
1975023Scarlsonj {
1985023Scarlsonj 	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
1995023Scarlsonj 	    wsp->walk_cbdata));
2005023Scarlsonj }
2015023Scarlsonj 
2023448Sdh155122 /*
2033448Sdh155122  * Called with walk_addr being the address of ips_ill_g_heads
2043448Sdh155122  */
2053448Sdh155122 int
2063448Sdh155122 illif_stack_walk_init(mdb_walk_state_t *wsp)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate 	illif_walk_data_t *iw;
2090Sstevel@tonic-gate 
2103448Sdh155122 	if (wsp->walk_addr == NULL) {
2113448Sdh155122 		mdb_warn("illif_stack supports only local walks\n");
2120Sstevel@tonic-gate 		return (WALK_ERR);
2130Sstevel@tonic-gate 	}
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	iw = mdb_alloc(sizeof (illif_walk_data_t), UM_SLEEP);
2160Sstevel@tonic-gate 
2173448Sdh155122 	if (mdb_vread(iw->ill_g_heads, MAX_G_HEADS * sizeof (ill_g_head_t),
2183448Sdh155122 	    wsp->walk_addr) == -1) {
2193448Sdh155122 		mdb_warn("failed to read 'ips_ill_g_heads' at %p",
2203448Sdh155122 		    wsp->walk_addr);
2210Sstevel@tonic-gate 		mdb_free(iw, sizeof (illif_walk_data_t));
2220Sstevel@tonic-gate 		return (WALK_ERR);
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	iw->ill_list = 0;
2263448Sdh155122 	wsp->walk_addr = (uintptr_t)iw->ill_g_heads[0].ill_g_list_head;
2270Sstevel@tonic-gate 	wsp->walk_data = iw;
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	return (WALK_NEXT);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate int
2333448Sdh155122 illif_stack_walk_step(mdb_walk_state_t *wsp)
2340Sstevel@tonic-gate {
2350Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
2360Sstevel@tonic-gate 	illif_walk_data_t *iw = wsp->walk_data;
2370Sstevel@tonic-gate 	int list = iw->ill_list;
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	if (mdb_vread(&iw->ill_if, sizeof (ill_if_t), addr) == -1) {
2400Sstevel@tonic-gate 		mdb_warn("failed to read ill_if_t at %p", addr);
2410Sstevel@tonic-gate 		return (WALK_ERR);
2420Sstevel@tonic-gate 	}
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)iw->ill_if.illif_next;
2450Sstevel@tonic-gate 
2463448Sdh155122 	if (wsp->walk_addr ==
2473448Sdh155122 	    (uintptr_t)iw->ill_g_heads[list].ill_g_list_head) {
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 		if (++list >= MAX_G_HEADS)
2500Sstevel@tonic-gate 			return (WALK_DONE);
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 		iw->ill_list = list;
2533448Sdh155122 		wsp->walk_addr =
2543448Sdh155122 		    (uintptr_t)iw->ill_g_heads[list].ill_g_list_head;
2550Sstevel@tonic-gate 		return (WALK_NEXT);
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	return (wsp->walk_callback(addr, iw, wsp->walk_cbdata));
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate void
2623448Sdh155122 illif_stack_walk_fini(mdb_walk_state_t *wsp)
2630Sstevel@tonic-gate {
2640Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (illif_walk_data_t));
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate typedef struct illif_cbdata {
2680Sstevel@tonic-gate 	uint_t ill_flags;
2690Sstevel@tonic-gate 	uintptr_t ill_addr;
2700Sstevel@tonic-gate 	int ill_printlist;	/* list to be printed (MAX_G_HEADS for all) */
2710Sstevel@tonic-gate 	boolean_t ill_printed;
2720Sstevel@tonic-gate } illif_cbdata_t;
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate static int
2750Sstevel@tonic-gate illif_cb(uintptr_t addr, const illif_walk_data_t *iw, illif_cbdata_t *id)
2760Sstevel@tonic-gate {
2770Sstevel@tonic-gate 	const char *version;
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	if (id->ill_printlist < MAX_G_HEADS &&
2800Sstevel@tonic-gate 	    id->ill_printlist != iw->ill_list)
2810Sstevel@tonic-gate 		return (WALK_NEXT);
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	if (id->ill_flags & DCMD_ADDRSPEC && id->ill_addr != addr)
2840Sstevel@tonic-gate 		return (WALK_NEXT);
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	if (id->ill_flags & DCMD_PIPE_OUT) {
2870Sstevel@tonic-gate 		mdb_printf("%p\n", addr);
2880Sstevel@tonic-gate 		return (WALK_NEXT);
2890Sstevel@tonic-gate 	}
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	switch (iw->ill_list) {
2920Sstevel@tonic-gate 		case IP_V4_G_HEAD:	version = "v4";	break;
2930Sstevel@tonic-gate 		case IP_V6_G_HEAD:	version = "v6";	break;
2940Sstevel@tonic-gate 		default:		version = "??"; break;
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	mdb_printf("%?p %2s %?p %10d %?p %s\n",
2980Sstevel@tonic-gate 	    addr, version, addr + offsetof(ill_if_t, illif_avl_by_ppa),
2990Sstevel@tonic-gate 	    iw->ill_if.illif_avl_by_ppa.avl_numnodes,
3000Sstevel@tonic-gate 	    iw->ill_if.illif_ppa_arena, iw->ill_if.illif_name);
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	id->ill_printed = TRUE;
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	return (WALK_NEXT);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate int
308*5940Ssowmini ip_stacks_common_walk_init(mdb_walk_state_t *wsp)
3093448Sdh155122 {
3103448Sdh155122 	if (mdb_layered_walk("ip_stacks", wsp) == -1) {
3113448Sdh155122 		mdb_warn("can't walk 'ip_stacks'");
3123448Sdh155122 		return (WALK_ERR);
3133448Sdh155122 	}
3143448Sdh155122 
3153448Sdh155122 	return (WALK_NEXT);
3163448Sdh155122 }
3173448Sdh155122 
3183448Sdh155122 int
3193448Sdh155122 illif_walk_step(mdb_walk_state_t *wsp)
3203448Sdh155122 {
3213448Sdh155122 	uintptr_t kaddr;
3223448Sdh155122 
3233448Sdh155122 	kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ill_g_heads);
3243448Sdh155122 
3253448Sdh155122 	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
3263448Sdh155122 		mdb_warn("can't read ips_ip_cache_table at %p", kaddr);
3273448Sdh155122 		return (WALK_ERR);
3283448Sdh155122 	}
3293448Sdh155122 
3303448Sdh155122 	if (mdb_pwalk("illif_stack", wsp->walk_callback,
3315023Scarlsonj 	    wsp->walk_cbdata, kaddr) == -1) {
3323448Sdh155122 		mdb_warn("couldn't walk 'illif_stack' for ips_ill_g_heads %p",
3333448Sdh155122 		    kaddr);
3343448Sdh155122 		return (WALK_ERR);
3353448Sdh155122 	}
3363448Sdh155122 	return (WALK_NEXT);
3373448Sdh155122 }
3383448Sdh155122 
3393448Sdh155122 int
3400Sstevel@tonic-gate illif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3410Sstevel@tonic-gate {
3420Sstevel@tonic-gate 	illif_cbdata_t id;
3430Sstevel@tonic-gate 	ill_if_t ill_if;
3440Sstevel@tonic-gate 	const char *opt_P = NULL;
3450Sstevel@tonic-gate 	int printlist = MAX_G_HEADS;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
3480Sstevel@tonic-gate 	    'P', MDB_OPT_STR, &opt_P, NULL) != argc)
3490Sstevel@tonic-gate 		return (DCMD_USAGE);
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	if (opt_P != NULL) {
3520Sstevel@tonic-gate 		if (strcmp("v4", opt_P) == 0) {
3530Sstevel@tonic-gate 			printlist = IP_V4_G_HEAD;
3540Sstevel@tonic-gate 		} else if (strcmp("v6", opt_P) == 0) {
3550Sstevel@tonic-gate 			printlist = IP_V6_G_HEAD;
3560Sstevel@tonic-gate 		} else {
3570Sstevel@tonic-gate 			mdb_warn("invalid protocol '%s'\n", opt_P);
3580Sstevel@tonic-gate 			return (DCMD_USAGE);
3590Sstevel@tonic-gate 		}
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) {
3630Sstevel@tonic-gate 		mdb_printf("%<u>%?s %2s %?s %10s %?s %-10s%</u>\n",
3640Sstevel@tonic-gate 		    "ADDR", "IP", "AVLADDR", "NUMNODES", "ARENA", "NAME");
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	id.ill_flags = flags;
3680Sstevel@tonic-gate 	id.ill_addr = addr;
3690Sstevel@tonic-gate 	id.ill_printlist = printlist;
3700Sstevel@tonic-gate 	id.ill_printed = FALSE;
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	if (mdb_walk("illif", (mdb_walk_cb_t)illif_cb, &id) == -1) {
3730Sstevel@tonic-gate 		mdb_warn("can't walk ill_if_t structures");
3740Sstevel@tonic-gate 		return (DCMD_ERR);
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || opt_P != NULL || id.ill_printed)
3780Sstevel@tonic-gate 		return (DCMD_OK);
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	/*
3810Sstevel@tonic-gate 	 * If an address is specified and the walk doesn't find it,
3820Sstevel@tonic-gate 	 * print it anyway.
3830Sstevel@tonic-gate 	 */
3840Sstevel@tonic-gate 	if (mdb_vread(&ill_if, sizeof (ill_if_t), addr) == -1) {
3850Sstevel@tonic-gate 		mdb_warn("failed to read ill_if_t at %p", addr);
3860Sstevel@tonic-gate 		return (DCMD_ERR);
3870Sstevel@tonic-gate 	}
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	mdb_printf("%?p %2s %?p %10d %?p %s\n",
3900Sstevel@tonic-gate 	    addr, "??", addr + offsetof(ill_if_t, illif_avl_by_ppa),
3910Sstevel@tonic-gate 	    ill_if.illif_avl_by_ppa.avl_numnodes,
3920Sstevel@tonic-gate 	    ill_if.illif_ppa_arena, ill_if.illif_name);
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	return (DCMD_OK);
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate static void
3980Sstevel@tonic-gate illif_help(void)
3990Sstevel@tonic-gate {
4000Sstevel@tonic-gate 	mdb_printf("Options:\n");
4010Sstevel@tonic-gate 	mdb_printf("\t-P v4 | v6"
4020Sstevel@tonic-gate 	    "\tfilter interface structures for the specified protocol\n");
4030Sstevel@tonic-gate }
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate int
4060Sstevel@tonic-gate ire_walk_init(mdb_walk_state_t *wsp)
4070Sstevel@tonic-gate {
4080Sstevel@tonic-gate 	if (mdb_layered_walk("ire_cache", wsp) == -1) {
4090Sstevel@tonic-gate 		mdb_warn("can't walk 'ire_cache'");
4100Sstevel@tonic-gate 		return (WALK_ERR);
4110Sstevel@tonic-gate 	}
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	return (WALK_NEXT);
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate int
4170Sstevel@tonic-gate ire_walk_step(mdb_walk_state_t *wsp)
4180Sstevel@tonic-gate {
4190Sstevel@tonic-gate 	ire_t ire;
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) {
4220Sstevel@tonic-gate 		mdb_warn("can't read ire at %p", wsp->walk_addr);
4230Sstevel@tonic-gate 		return (WALK_ERR);
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	return (wsp->walk_callback(wsp->walk_addr, &ire, wsp->walk_cbdata));
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate 
4293448Sdh155122 
4303448Sdh155122 int
4313448Sdh155122 ire_ctable_walk_step(mdb_walk_state_t *wsp)
4323448Sdh155122 {
4333448Sdh155122 	uintptr_t kaddr;
4343448Sdh155122 	irb_t *irb;
4353448Sdh155122 	uint32_t cache_table_size;
4363448Sdh155122 	int i;
437*5940Ssowmini 	ire_cbdata_t ire_cb;
4383448Sdh155122 
439*5940Ssowmini 	ire_cb.verbose = B_FALSE;
440*5940Ssowmini 	ire_cb.ire_ipversion = 0;
441*5940Ssowmini 
4423448Sdh155122 
4433448Sdh155122 	kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ip_cache_table_size);
4443448Sdh155122 
4453448Sdh155122 	if (mdb_vread(&cache_table_size, sizeof (uint32_t), kaddr) == -1) {
4463448Sdh155122 		mdb_warn("can't read ips_ip_cache_table at %p", kaddr);
4473448Sdh155122 		return (WALK_ERR);
4483448Sdh155122 	}
4493448Sdh155122 
4503448Sdh155122 	kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ip_cache_table);
4513448Sdh155122 	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
4523448Sdh155122 		mdb_warn("can't read ips_ip_cache_table at %p", kaddr);
4533448Sdh155122 		return (WALK_ERR);
4543448Sdh155122 	}
4553448Sdh155122 
4563448Sdh155122 	irb = mdb_alloc(sizeof (irb_t) * cache_table_size, UM_SLEEP|UM_GC);
4573448Sdh155122 	if (mdb_vread(irb, sizeof (irb_t) * cache_table_size, kaddr) == -1) {
4583448Sdh155122 		mdb_warn("can't read irb at %p", kaddr);
4593448Sdh155122 		return (WALK_ERR);
4603448Sdh155122 	}
4613448Sdh155122 	for (i = 0; i < cache_table_size; i++) {
4623448Sdh155122 		kaddr = (uintptr_t)irb[i].irb_ire;
4633448Sdh155122 
464*5940Ssowmini 		if (mdb_pwalk("ire_next", ire_format, &ire_cb,
4655023Scarlsonj 		    kaddr) == -1) {
4663448Sdh155122 			mdb_warn("can't walk 'ire_next' for ire %p", kaddr);
4673448Sdh155122 			return (WALK_ERR);
4683448Sdh155122 		}
4693448Sdh155122 	}
4703448Sdh155122 	return (WALK_NEXT);
4713448Sdh155122 }
4723448Sdh155122 
4733448Sdh155122 /* ARGSUSED */
4743448Sdh155122 int
4753448Sdh155122 ire_next_walk_init(mdb_walk_state_t *wsp)
4763448Sdh155122 {
4773448Sdh155122 	return (WALK_NEXT);
4783448Sdh155122 }
4793448Sdh155122 
4803448Sdh155122 int
4813448Sdh155122 ire_next_walk_step(mdb_walk_state_t *wsp)
4823448Sdh155122 {
4833448Sdh155122 	ire_t ire;
4843448Sdh155122 	int status;
4853448Sdh155122 
4863448Sdh155122 
4873448Sdh155122 	if (wsp->walk_addr == NULL)
4883448Sdh155122 		return (WALK_DONE);
4893448Sdh155122 
4903448Sdh155122 	if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) {
4913448Sdh155122 		mdb_warn("can't read ire at %p", wsp->walk_addr);
4923448Sdh155122 		return (WALK_ERR);
4933448Sdh155122 	}
4943448Sdh155122 	status = wsp->walk_callback(wsp->walk_addr, &ire,
4953448Sdh155122 	    wsp->walk_cbdata);
4963448Sdh155122 
4973448Sdh155122 	if (status != WALK_NEXT)
4983448Sdh155122 		return (status);
4993448Sdh155122 
5003448Sdh155122 	wsp->walk_addr = (uintptr_t)ire.ire_next;
5013448Sdh155122 	return (status);
5023448Sdh155122 }
5033448Sdh155122 
5040Sstevel@tonic-gate static int
505*5940Ssowmini ire_format(uintptr_t addr, const void *ire_arg, void *ire_cb_arg)
5060Sstevel@tonic-gate {
507*5940Ssowmini 	const ire_t *irep = ire_arg;
508*5940Ssowmini 	ire_cbdata_t *ire_cb = ire_cb_arg;
509*5940Ssowmini 	boolean_t verbose = ire_cb->verbose;
510*5940Ssowmini 
5110Sstevel@tonic-gate 	static const mdb_bitmask_t tmasks[] = {
5120Sstevel@tonic-gate 		{ "BROADCAST",	IRE_BROADCAST,		IRE_BROADCAST	},
5130Sstevel@tonic-gate 		{ "DEFAULT",	IRE_DEFAULT,		IRE_DEFAULT	},
5140Sstevel@tonic-gate 		{ "LOCAL",	IRE_LOCAL,		IRE_LOCAL	},
5150Sstevel@tonic-gate 		{ "LOOPBACK",	IRE_LOOPBACK,		IRE_LOOPBACK	},
5160Sstevel@tonic-gate 		{ "PREFIX",	IRE_PREFIX,		IRE_PREFIX	},
5170Sstevel@tonic-gate 		{ "CACHE",	IRE_CACHE,		IRE_CACHE	},
5180Sstevel@tonic-gate 		{ "IF_NORESOLVER", IRE_IF_NORESOLVER,	IRE_IF_NORESOLVER },
5190Sstevel@tonic-gate 		{ "IF_RESOLVER", IRE_IF_RESOLVER,	IRE_IF_RESOLVER	},
5200Sstevel@tonic-gate 		{ "HOST",	IRE_HOST,		IRE_HOST	},
5210Sstevel@tonic-gate 		{ "HOST_REDIRECT", IRE_HOST_REDIRECT,	IRE_HOST_REDIRECT },
5220Sstevel@tonic-gate 		{ NULL,		0,			0		}
5230Sstevel@tonic-gate 	};
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	static const mdb_bitmask_t mmasks[] = {
5260Sstevel@tonic-gate 		{ "CONDEMNED",	IRE_MARK_CONDEMNED,	IRE_MARK_CONDEMNED },
5270Sstevel@tonic-gate 		{ "NORECV",	IRE_MARK_NORECV,	IRE_MARK_NORECV	},
5280Sstevel@tonic-gate 		{ "HIDDEN",	IRE_MARK_HIDDEN,	IRE_MARK_HIDDEN	},
5290Sstevel@tonic-gate 		{ "NOADD",	IRE_MARK_NOADD,		IRE_MARK_NOADD	},
5300Sstevel@tonic-gate 		{ "TEMPORARY",	IRE_MARK_TEMPORARY,	IRE_MARK_TEMPORARY },
531*5940Ssowmini 		{ "USESRC",	IRE_MARK_USESRC_CHECK,	IRE_MARK_USESRC_CHECK },
532*5940Ssowmini 		{ "PRIVATE",	IRE_MARK_PRIVATE_ADDR,	IRE_MARK_PRIVATE_ADDR },
533*5940Ssowmini 		{ "UNCACHED",	IRE_MARK_UNCACHED,	IRE_MARK_UNCACHED },
5340Sstevel@tonic-gate 		{ NULL,		0,			0		}
5350Sstevel@tonic-gate 	};
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	static const mdb_bitmask_t fmasks[] = {
5380Sstevel@tonic-gate 		{ "UP",		RTF_UP,			RTF_UP		},
5390Sstevel@tonic-gate 		{ "GATEWAY",	RTF_GATEWAY,		RTF_GATEWAY	},
5400Sstevel@tonic-gate 		{ "HOST",	RTF_HOST,		RTF_HOST	},
5410Sstevel@tonic-gate 		{ "REJECT",	RTF_REJECT,		RTF_REJECT	},
5420Sstevel@tonic-gate 		{ "DYNAMIC",	RTF_DYNAMIC,		RTF_DYNAMIC	},
5430Sstevel@tonic-gate 		{ "MODIFIED",	RTF_MODIFIED,		RTF_MODIFIED	},
5440Sstevel@tonic-gate 		{ "DONE",	RTF_DONE,		RTF_DONE	},
5450Sstevel@tonic-gate 		{ "MASK",	RTF_MASK,		RTF_MASK	},
5460Sstevel@tonic-gate 		{ "CLONING",	RTF_CLONING,		RTF_CLONING	},
5470Sstevel@tonic-gate 		{ "XRESOLVE",	RTF_XRESOLVE,		RTF_XRESOLVE	},
5480Sstevel@tonic-gate 		{ "LLINFO",	RTF_LLINFO,		RTF_LLINFO	},
5490Sstevel@tonic-gate 		{ "STATIC",	RTF_STATIC,		RTF_STATIC	},
5500Sstevel@tonic-gate 		{ "BLACKHOLE",	RTF_BLACKHOLE,		RTF_BLACKHOLE	},
5510Sstevel@tonic-gate 		{ "PRIVATE",	RTF_PRIVATE,		RTF_PRIVATE	},
5520Sstevel@tonic-gate 		{ "PROTO2",	RTF_PROTO2,		RTF_PROTO2	},
5530Sstevel@tonic-gate 		{ "PROTO1",	RTF_PROTO1,		RTF_PROTO1	},
5540Sstevel@tonic-gate 		{ "MULTIRT",	RTF_MULTIRT,		RTF_MULTIRT	},
5550Sstevel@tonic-gate 		{ "SETSRC",	RTF_SETSRC,		RTF_SETSRC	},
5560Sstevel@tonic-gate 		{ NULL,		0,			0		}
5570Sstevel@tonic-gate 	};
5580Sstevel@tonic-gate 
559*5940Ssowmini 	if (ire_cb->ire_ipversion != 0 &&
560*5940Ssowmini 	    irep->ire_ipversion != ire_cb->ire_ipversion)
561*5940Ssowmini 		return (WALK_NEXT);
562*5940Ssowmini 
563*5940Ssowmini 	if (irep->ire_ipversion == IPV6_VERSION && verbose) {
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 		mdb_printf("%<b>%?p%</b> %40N <%hb>\n"
5660Sstevel@tonic-gate 		    "%?s %40N <%hb>\n"
5673448Sdh155122 		    "%?s %40d %4d <%hb>\n",
5680Sstevel@tonic-gate 		    addr, &irep->ire_src_addr_v6, irep->ire_type, tmasks,
5690Sstevel@tonic-gate 		    "", &irep->ire_addr_v6, (ushort_t)irep->ire_marks, mmasks,
5703448Sdh155122 		    "", ips_to_stackid((uintptr_t)irep->ire_ipst),
5713448Sdh155122 		    irep->ire_zoneid,
5723448Sdh155122 		    irep->ire_flags, fmasks);
5730Sstevel@tonic-gate 
574*5940Ssowmini 	} else if (irep->ire_ipversion == IPV6_VERSION) {
5750Sstevel@tonic-gate 
5763448Sdh155122 		mdb_printf("%?p %30N %30N %5d %4d\n",
5773448Sdh155122 		    addr, &irep->ire_src_addr_v6,
5783448Sdh155122 		    &irep->ire_addr_v6,
5793448Sdh155122 		    ips_to_stackid((uintptr_t)irep->ire_ipst),
5803448Sdh155122 		    irep->ire_zoneid);
5810Sstevel@tonic-gate 
582*5940Ssowmini 	} else if (verbose) {
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 		mdb_printf("%<b>%?p%</b> %40I <%hb>\n"
5850Sstevel@tonic-gate 		    "%?s %40I <%hb>\n"
586*5940Ssowmini 		    "%?s %40d %4d <%hb>\n",
5870Sstevel@tonic-gate 		    addr, irep->ire_src_addr, irep->ire_type, tmasks,
5880Sstevel@tonic-gate 		    "", irep->ire_addr, (ushort_t)irep->ire_marks, mmasks,
5893448Sdh155122 		    "", ips_to_stackid((uintptr_t)irep->ire_ipst),
5903448Sdh155122 		    irep->ire_zoneid, irep->ire_flags, fmasks);
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	} else {
5930Sstevel@tonic-gate 
5943448Sdh155122 		mdb_printf("%?p %30I %30I %5d %4d\n", addr, irep->ire_src_addr,
5953448Sdh155122 		    irep->ire_addr, ips_to_stackid((uintptr_t)irep->ire_ipst),
5963448Sdh155122 		    irep->ire_zoneid);
5970Sstevel@tonic-gate 	}
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	return (WALK_NEXT);
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate /*
6030Sstevel@tonic-gate  * There are faster ways to do this.  Given the interactive nature of this
6040Sstevel@tonic-gate  * use I don't think its worth much effort.
6050Sstevel@tonic-gate  */
6060Sstevel@tonic-gate static unsigned short
6070Sstevel@tonic-gate ipcksum(void *p, int len)
6080Sstevel@tonic-gate {
6090Sstevel@tonic-gate 	int32_t	sum = 0;
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	while (len > 1) {
6120Sstevel@tonic-gate 		/* alignment */
6130Sstevel@tonic-gate 		sum += *(uint16_t *)p;
6140Sstevel@tonic-gate 		p = (char *)p + sizeof (uint16_t);
6150Sstevel@tonic-gate 		if (sum & 0x80000000)
6160Sstevel@tonic-gate 			sum = (sum & 0xFFFF) + (sum >> 16);
6170Sstevel@tonic-gate 		len -= 2;
6180Sstevel@tonic-gate 	}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	if (len)
6210Sstevel@tonic-gate 		sum += (uint16_t)*(unsigned char *)p;
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	while (sum >> 16)
6240Sstevel@tonic-gate 		sum = (sum & 0xFFFF) + (sum >> 16);
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	return (~sum);
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate static const mdb_bitmask_t tcp_flags[] = {
6300Sstevel@tonic-gate 	{ "SYN",	TH_SYN,		TH_SYN	},
6310Sstevel@tonic-gate 	{ "ACK",	TH_ACK,		TH_ACK	},
6320Sstevel@tonic-gate 	{ "FIN",	TH_FIN,		TH_FIN	},
6330Sstevel@tonic-gate 	{ "RST",	TH_RST,		TH_RST	},
6340Sstevel@tonic-gate 	{ "PSH",	TH_PUSH,	TH_PUSH	},
6350Sstevel@tonic-gate 	{ "ECE",	TH_ECE,		TH_ECE	},
6360Sstevel@tonic-gate 	{ "CWR",	TH_CWR,		TH_CWR	},
6370Sstevel@tonic-gate 	{ NULL,		0,		0	}
6380Sstevel@tonic-gate };
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate static void
6410Sstevel@tonic-gate tcphdr_print(struct tcphdr *tcph)
6420Sstevel@tonic-gate {
6430Sstevel@tonic-gate 	in_port_t	sport, dport;
6440Sstevel@tonic-gate 	tcp_seq		seq, ack;
6450Sstevel@tonic-gate 	uint16_t	win, urp;
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	mdb_printf("%<b>TCP header%</b>\n");
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	mdb_nhconvert(&sport, &tcph->th_sport, sizeof (sport));
6500Sstevel@tonic-gate 	mdb_nhconvert(&dport, &tcph->th_dport, sizeof (dport));
6510Sstevel@tonic-gate 	mdb_nhconvert(&seq, &tcph->th_seq, sizeof (seq));
6520Sstevel@tonic-gate 	mdb_nhconvert(&ack, &tcph->th_ack, sizeof (ack));
6530Sstevel@tonic-gate 	mdb_nhconvert(&win, &tcph->th_win, sizeof (win));
6540Sstevel@tonic-gate 	mdb_nhconvert(&urp, &tcph->th_urp, sizeof (urp));
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	mdb_printf("%<u>%6s %6s %10s %10s %4s %5s %5s %5s %-15s%</u>\n",
6570Sstevel@tonic-gate 	    "SPORT", "DPORT", "SEQ", "ACK", "HLEN", "WIN", "CSUM", "URP",
6580Sstevel@tonic-gate 	    "FLAGS");
6590Sstevel@tonic-gate 	mdb_printf("%6hu %6hu %10u %10u %4d %5hu %5hu %5hu <%b>\n",
6600Sstevel@tonic-gate 	    sport, dport, seq, ack, tcph->th_off << 2, win,
6610Sstevel@tonic-gate 	    tcph->th_sum, urp, tcph->th_flags, tcp_flags);
6620Sstevel@tonic-gate 	mdb_printf("0x%04x 0x%04x 0x%08x 0x%08x\n\n",
6630Sstevel@tonic-gate 	    sport, dport, seq, ack);
6640Sstevel@tonic-gate }
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate /* ARGSUSED */
6670Sstevel@tonic-gate static int
6680Sstevel@tonic-gate tcphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
6690Sstevel@tonic-gate {
6700Sstevel@tonic-gate 	struct tcphdr	tcph;
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
6730Sstevel@tonic-gate 		return (DCMD_USAGE);
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) {
6760Sstevel@tonic-gate 		mdb_warn("failed to read TCP header at %p", addr);
6770Sstevel@tonic-gate 		return (DCMD_ERR);
6780Sstevel@tonic-gate 	}
6790Sstevel@tonic-gate 	tcphdr_print(&tcph);
6800Sstevel@tonic-gate 	return (DCMD_OK);
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate static void
6840Sstevel@tonic-gate udphdr_print(struct udphdr *udph)
6850Sstevel@tonic-gate {
6860Sstevel@tonic-gate 	in_port_t	sport, dport;
6870Sstevel@tonic-gate 	uint16_t	hlen;
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	mdb_printf("%<b>UDP header%</b>\n");
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	mdb_nhconvert(&sport, &udph->uh_sport, sizeof (sport));
6920Sstevel@tonic-gate 	mdb_nhconvert(&dport, &udph->uh_dport, sizeof (dport));
6930Sstevel@tonic-gate 	mdb_nhconvert(&hlen, &udph->uh_ulen, sizeof (hlen));
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	mdb_printf("%<u>%14s %14s %5s %6s%</u>\n",
6960Sstevel@tonic-gate 	    "SPORT", "DPORT", "LEN", "CSUM");
6970Sstevel@tonic-gate 	mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %5hu 0x%04hx\n\n", sport, sport,
6980Sstevel@tonic-gate 	    dport, dport, hlen, udph->uh_sum);
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate /* ARGSUSED */
7020Sstevel@tonic-gate static int
7030Sstevel@tonic-gate udphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
7040Sstevel@tonic-gate {
7050Sstevel@tonic-gate 	struct udphdr	udph;
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
7080Sstevel@tonic-gate 		return (DCMD_USAGE);
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	if (mdb_vread(&udph, sizeof (udph), addr) == -1) {
7110Sstevel@tonic-gate 		mdb_warn("failed to read UDP header at %p", addr);
7120Sstevel@tonic-gate 		return (DCMD_ERR);
7130Sstevel@tonic-gate 	}
7140Sstevel@tonic-gate 	udphdr_print(&udph);
7150Sstevel@tonic-gate 	return (DCMD_OK);
7160Sstevel@tonic-gate }
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate static void
7190Sstevel@tonic-gate sctphdr_print(sctp_hdr_t *sctph)
7200Sstevel@tonic-gate {
7210Sstevel@tonic-gate 	in_port_t sport, dport;
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	mdb_printf("%<b>SCTP header%</b>\n");
7240Sstevel@tonic-gate 	mdb_nhconvert(&sport, &sctph->sh_sport, sizeof (sport));
7250Sstevel@tonic-gate 	mdb_nhconvert(&dport, &sctph->sh_dport, sizeof (dport));
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	mdb_printf("%<u>%14s %14s %10s %10s%</u>\n",
7280Sstevel@tonic-gate 	    "SPORT", "DPORT", "VTAG", "CHKSUM");
7290Sstevel@tonic-gate 	mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %10u 0x%08x\n\n", sport, sport,
7300Sstevel@tonic-gate 	    dport, dport, sctph->sh_verf, sctph->sh_chksum);
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate /* ARGSUSED */
7340Sstevel@tonic-gate static int
7350Sstevel@tonic-gate sctphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
7360Sstevel@tonic-gate {
7370Sstevel@tonic-gate 	sctp_hdr_t sctph;
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
7400Sstevel@tonic-gate 		return (DCMD_USAGE);
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 	if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) {
7430Sstevel@tonic-gate 		mdb_warn("failed to read SCTP header at %p", addr);
7440Sstevel@tonic-gate 		return (DCMD_ERR);
7450Sstevel@tonic-gate 	}
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	sctphdr_print(&sctph);
7480Sstevel@tonic-gate 	return (DCMD_OK);
7490Sstevel@tonic-gate }
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate static int
7520Sstevel@tonic-gate transport_hdr(int proto, uintptr_t addr)
7530Sstevel@tonic-gate {
7540Sstevel@tonic-gate 	mdb_printf("\n");
7550Sstevel@tonic-gate 	switch (proto) {
7560Sstevel@tonic-gate 	case IPPROTO_TCP: {
7570Sstevel@tonic-gate 		struct tcphdr tcph;
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 		if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) {
7600Sstevel@tonic-gate 			mdb_warn("failed to read TCP header at %p", addr);
7610Sstevel@tonic-gate 			return (DCMD_ERR);
7620Sstevel@tonic-gate 		}
7630Sstevel@tonic-gate 		tcphdr_print(&tcph);
7640Sstevel@tonic-gate 		break;
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate 	case IPPROTO_UDP:  {
7670Sstevel@tonic-gate 		struct udphdr udph;
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 		if (mdb_vread(&udph, sizeof (udph), addr) == -1) {
7700Sstevel@tonic-gate 			mdb_warn("failed to read UDP header at %p", addr);
7710Sstevel@tonic-gate 			return (DCMD_ERR);
7720Sstevel@tonic-gate 		}
7730Sstevel@tonic-gate 		udphdr_print(&udph);
7740Sstevel@tonic-gate 		break;
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate 	case IPPROTO_SCTP: {
7770Sstevel@tonic-gate 		sctp_hdr_t sctph;
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate 		if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) {
7800Sstevel@tonic-gate 			mdb_warn("failed to read SCTP header at %p", addr);
7810Sstevel@tonic-gate 			return (DCMD_ERR);
7820Sstevel@tonic-gate 		}
7830Sstevel@tonic-gate 		sctphdr_print(&sctph);
7840Sstevel@tonic-gate 		break;
7850Sstevel@tonic-gate 	}
7860Sstevel@tonic-gate 	default:
7870Sstevel@tonic-gate 		break;
7880Sstevel@tonic-gate 	}
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	return (DCMD_OK);
7910Sstevel@tonic-gate }
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate static const mdb_bitmask_t ip_flags[] = {
7940Sstevel@tonic-gate 	{ "DF",	IPH_DF, IPH_DF	},
7950Sstevel@tonic-gate 	{ "MF", IPH_MF,	IPH_MF	},
7960Sstevel@tonic-gate 	{ NULL, 0,	0	}
7970Sstevel@tonic-gate };
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate /* ARGSUSED */
8000Sstevel@tonic-gate static int
8010Sstevel@tonic-gate iphdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
8020Sstevel@tonic-gate {
8030Sstevel@tonic-gate 	uint_t		verbose = FALSE, force = FALSE;
8040Sstevel@tonic-gate 	ipha_t		iph[1];
8050Sstevel@tonic-gate 	uint16_t	ver, totlen, hdrlen, ipid, off, csum;
8060Sstevel@tonic-gate 	uintptr_t	nxt_proto;
8070Sstevel@tonic-gate 	char		exp_csum[8];
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
8100Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
8110Sstevel@tonic-gate 	    'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc)
8120Sstevel@tonic-gate 		return (DCMD_USAGE);
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	if (mdb_vread(iph, sizeof (*iph), addr) == -1) {
8150Sstevel@tonic-gate 		mdb_warn("failed to read IPv4 header at %p", addr);
8160Sstevel@tonic-gate 		return (DCMD_ERR);
8170Sstevel@tonic-gate 	}
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	ver = (iph->ipha_version_and_hdr_length & 0xf0) >> 4;
8200Sstevel@tonic-gate 	if (ver != IPV4_VERSION) {
8210Sstevel@tonic-gate 		if (ver == IPV6_VERSION) {
8220Sstevel@tonic-gate 			return (ip6hdr(addr, flags, argc, argv));
8230Sstevel@tonic-gate 		} else if (!force) {
8240Sstevel@tonic-gate 			mdb_warn("unknown IP version: %d\n", ver);
8250Sstevel@tonic-gate 			return (DCMD_ERR);
8260Sstevel@tonic-gate 		}
8270Sstevel@tonic-gate 	}
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	mdb_printf("%<b>IPv4 header%</b>\n");
8300Sstevel@tonic-gate 	mdb_printf("%-34s %-34s\n"
8310Sstevel@tonic-gate 	    "%<u>%-4s %-4s %-5s %-5s %-6s %-5s %-5s %-6s %-8s %-6s%</u>\n",
8320Sstevel@tonic-gate 	    "SRC", "DST",
8330Sstevel@tonic-gate 	    "HLEN", "TOS", "LEN", "ID", "OFFSET", "TTL", "PROTO", "CHKSUM",
8340Sstevel@tonic-gate 	    "EXP-CSUM", "FLGS");
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	hdrlen = (iph->ipha_version_and_hdr_length & 0x0f) << 2;
8370Sstevel@tonic-gate 	mdb_nhconvert(&totlen, &iph->ipha_length, sizeof (totlen));
8380Sstevel@tonic-gate 	mdb_nhconvert(&ipid, &iph->ipha_ident, sizeof (ipid));
8390Sstevel@tonic-gate 	mdb_nhconvert(&off, &iph->ipha_fragment_offset_and_flags, sizeof (off));
8400Sstevel@tonic-gate 	if (hdrlen == IP_SIMPLE_HDR_LENGTH) {
8410Sstevel@tonic-gate 		if ((csum = ipcksum(iph, sizeof (*iph))) != 0)
8420Sstevel@tonic-gate 			csum = ~(~csum + ~iph->ipha_hdr_checksum);
8430Sstevel@tonic-gate 		else
8440Sstevel@tonic-gate 			csum = iph->ipha_hdr_checksum;
8450Sstevel@tonic-gate 		mdb_snprintf(exp_csum, 8, "%u", csum);
8460Sstevel@tonic-gate 	} else {
8470Sstevel@tonic-gate 		mdb_snprintf(exp_csum, 8, "<n/a>");
8480Sstevel@tonic-gate 	}
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	mdb_printf("%-34I %-34I%\n"
8510Sstevel@tonic-gate 	    "%-4d %-4d %-5hu %-5hu %-6hu %-5hu %-5hu %-6u %-8s <%5hb>\n",
8520Sstevel@tonic-gate 	    iph->ipha_src, iph->ipha_dst,
8530Sstevel@tonic-gate 	    hdrlen, iph->ipha_type_of_service, totlen, ipid,
8540Sstevel@tonic-gate 	    (off << 3) & 0xffff, iph->ipha_ttl, iph->ipha_protocol,
8550Sstevel@tonic-gate 	    iph->ipha_hdr_checksum, exp_csum, off, ip_flags);
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	if (verbose) {
8580Sstevel@tonic-gate 		nxt_proto = addr + hdrlen;
8590Sstevel@tonic-gate 		return (transport_hdr(iph->ipha_protocol, nxt_proto));
8600Sstevel@tonic-gate 	} else {
8610Sstevel@tonic-gate 		return (DCMD_OK);
8620Sstevel@tonic-gate 	}
8630Sstevel@tonic-gate }
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate /* ARGSUSED */
8660Sstevel@tonic-gate static int
8670Sstevel@tonic-gate ip6hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
8680Sstevel@tonic-gate {
8690Sstevel@tonic-gate 	uint_t		verbose = FALSE, force = FALSE;
8700Sstevel@tonic-gate 	ip6_t		iph[1];
8710Sstevel@tonic-gate 	int		ver, class, flow;
8720Sstevel@tonic-gate 	uint16_t	plen;
8730Sstevel@tonic-gate 	uintptr_t	nxt_proto;
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
8760Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
8770Sstevel@tonic-gate 	    'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc)
8780Sstevel@tonic-gate 		return (DCMD_USAGE);
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	if (mdb_vread(iph, sizeof (*iph), addr) == -1) {
8810Sstevel@tonic-gate 		mdb_warn("failed to read IPv6 header at %p", addr);
8820Sstevel@tonic-gate 		return (DCMD_ERR);
8830Sstevel@tonic-gate 	}
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	ver = (iph->ip6_vfc & 0xf0) >> 4;
8860Sstevel@tonic-gate 	if (ver != IPV6_VERSION) {
8870Sstevel@tonic-gate 		if (ver == IPV4_VERSION) {
8880Sstevel@tonic-gate 			return (iphdr(addr, flags, argc, argv));
8890Sstevel@tonic-gate 		} else if (!force) {
8900Sstevel@tonic-gate 			mdb_warn("unknown IP version: %d\n", ver);
8910Sstevel@tonic-gate 			return (DCMD_ERR);
8920Sstevel@tonic-gate 		}
8930Sstevel@tonic-gate 	}
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	mdb_printf("%<b>IPv6 header%</b>\n");
8960Sstevel@tonic-gate 	mdb_printf("%<u>%-26s %-26s %4s %7s %5s %3s %3s%</u>\n",
8970Sstevel@tonic-gate 	    "SRC", "DST", "TCLS", "FLOW-ID", "PLEN", "NXT", "HOP");
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	class = (iph->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20;
9000Sstevel@tonic-gate 	mdb_nhconvert(&class, &class, sizeof (class));
9010Sstevel@tonic-gate 	flow = iph->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL;
9020Sstevel@tonic-gate 	mdb_nhconvert(&flow, &flow, sizeof (flow));
9030Sstevel@tonic-gate 	mdb_nhconvert(&plen, &iph->ip6_plen, sizeof (plen));
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 	mdb_printf("%-26N %-26N %4d %7d %5hu %3d %3d\n",
9060Sstevel@tonic-gate 	    &iph->ip6_src, &iph->ip6_dst,
9070Sstevel@tonic-gate 	    class, flow, plen, iph->ip6_nxt, iph->ip6_hlim);
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	if (verbose) {
9100Sstevel@tonic-gate 		nxt_proto = addr + sizeof (ip6_t);
9110Sstevel@tonic-gate 		return (transport_hdr(iph->ip6_nxt, nxt_proto));
9120Sstevel@tonic-gate 	} else {
9130Sstevel@tonic-gate 		return (DCMD_OK);
9140Sstevel@tonic-gate 	}
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate int
9180Sstevel@tonic-gate ire(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
9190Sstevel@tonic-gate {
9200Sstevel@tonic-gate 	uint_t verbose = FALSE;
9210Sstevel@tonic-gate 	ire_t ire;
922*5940Ssowmini 	ire_cbdata_t ire_cb;
923*5940Ssowmini 	int ipversion = 0;
924*5940Ssowmini 	const char *opt_P = NULL;
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
927*5940Ssowmini 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
928*5940Ssowmini 	    'P', MDB_OPT_STR, &opt_P, NULL) != argc)
9290Sstevel@tonic-gate 		return (DCMD_USAGE);
9300Sstevel@tonic-gate 
931*5940Ssowmini 	if (opt_P != NULL) {
932*5940Ssowmini 		if (strcmp("v4", opt_P) == 0) {
933*5940Ssowmini 			ipversion = IPV4_VERSION;
934*5940Ssowmini 		} else if (strcmp("v6", opt_P) == 0) {
935*5940Ssowmini 			ipversion = IPV6_VERSION;
936*5940Ssowmini 		} else {
937*5940Ssowmini 			mdb_warn("invalid protocol '%s'\n", opt_P);
938*5940Ssowmini 			return (DCMD_USAGE);
939*5940Ssowmini 		}
940*5940Ssowmini 	}
941*5940Ssowmini 
9420Sstevel@tonic-gate 	if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 		if (verbose) {
9450Sstevel@tonic-gate 			mdb_printf("%?s %40s %-20s%\n"
9460Sstevel@tonic-gate 			    "%?s %40s %-20s%\n"
9473448Sdh155122 			    "%<u>%?s %40s %4s %-20s%</u>\n",
9480Sstevel@tonic-gate 			    "ADDR", "SRC", "TYPE",
9490Sstevel@tonic-gate 			    "", "DST", "MARKS",
9503448Sdh155122 			    "", "STACK", "ZONE", "FLAGS");
9510Sstevel@tonic-gate 		} else {
9523448Sdh155122 			mdb_printf("%<u>%?s %30s %30s %5s %4s%</u>\n",
9533448Sdh155122 			    "ADDR", "SRC", "DST", "STACK", "ZONE");
9540Sstevel@tonic-gate 		}
9550Sstevel@tonic-gate 	}
9560Sstevel@tonic-gate 
957*5940Ssowmini 	ire_cb.verbose = (verbose == TRUE);
958*5940Ssowmini 	ire_cb.ire_ipversion = ipversion;
959*5940Ssowmini 
9600Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC) {
9610Sstevel@tonic-gate 		(void) mdb_vread(&ire, sizeof (ire_t), addr);
962*5940Ssowmini 		(void) ire_format(addr, &ire, &ire_cb);
963*5940Ssowmini 	} else if (mdb_walk("ire", (mdb_walk_cb_t)ire_format, &ire_cb) == -1) {
9640Sstevel@tonic-gate 		mdb_warn("failed to walk ire table");
9650Sstevel@tonic-gate 		return (DCMD_ERR);
9660Sstevel@tonic-gate 	}
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	return (DCMD_OK);
9690Sstevel@tonic-gate }
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate static size_t
9720Sstevel@tonic-gate mi_osize(const queue_t *q)
9730Sstevel@tonic-gate {
9740Sstevel@tonic-gate 	/*
9750Sstevel@tonic-gate 	 * The code in common/inet/mi.c allocates an extra word to store the
9760Sstevel@tonic-gate 	 * size of the allocation.  An mi_o_s is thus a size_t plus an mi_o_s.
9770Sstevel@tonic-gate 	 */
9780Sstevel@tonic-gate 	struct mi_block {
9790Sstevel@tonic-gate 		size_t mi_nbytes;
9800Sstevel@tonic-gate 		struct mi_o_s mi_o;
9810Sstevel@tonic-gate 	} m;
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr -
9840Sstevel@tonic-gate 	    sizeof (m)) == sizeof (m))
9850Sstevel@tonic-gate 		return (m.mi_nbytes - sizeof (m));
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	return (0);
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate static void
9910Sstevel@tonic-gate ip_ill_qinfo(const queue_t *q, char *buf, size_t nbytes)
9920Sstevel@tonic-gate {
9930Sstevel@tonic-gate 	char name[32];
9940Sstevel@tonic-gate 	ill_t ill;
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	if (mdb_vread(&ill, sizeof (ill),
9970Sstevel@tonic-gate 	    (uintptr_t)q->q_ptr) == sizeof (ill) &&
9980Sstevel@tonic-gate 	    mdb_readstr(name, sizeof (name), (uintptr_t)ill.ill_name) > 0)
9990Sstevel@tonic-gate 		(void) mdb_snprintf(buf, nbytes, "if: %s", name);
10000Sstevel@tonic-gate }
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate void
10030Sstevel@tonic-gate ip_qinfo(const queue_t *q, char *buf, size_t nbytes)
10040Sstevel@tonic-gate {
10050Sstevel@tonic-gate 	size_t size = mi_osize(q);
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	if (size == sizeof (ill_t))
10080Sstevel@tonic-gate 		ip_ill_qinfo(q, buf, nbytes);
10090Sstevel@tonic-gate }
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate uintptr_t
10120Sstevel@tonic-gate ip_rnext(const queue_t *q)
10130Sstevel@tonic-gate {
10140Sstevel@tonic-gate 	size_t size = mi_osize(q);
10150Sstevel@tonic-gate 	ill_t ill;
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill),
10180Sstevel@tonic-gate 	    (uintptr_t)q->q_ptr) == sizeof (ill))
10190Sstevel@tonic-gate 		return ((uintptr_t)ill.ill_rq);
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	return (NULL);
10220Sstevel@tonic-gate }
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate uintptr_t
10250Sstevel@tonic-gate ip_wnext(const queue_t *q)
10260Sstevel@tonic-gate {
10270Sstevel@tonic-gate 	size_t size = mi_osize(q);
10280Sstevel@tonic-gate 	ill_t ill;
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 	if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill),
10310Sstevel@tonic-gate 	    (uintptr_t)q->q_ptr) == sizeof (ill))
10320Sstevel@tonic-gate 		return ((uintptr_t)ill.ill_wq);
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	return (NULL);
10350Sstevel@tonic-gate }
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate /*
10380Sstevel@tonic-gate  * Print the core fields in an squeue_t.  With the "-v" argument,
10390Sstevel@tonic-gate  * provide more verbose output.
10400Sstevel@tonic-gate  */
10410Sstevel@tonic-gate static int
10420Sstevel@tonic-gate squeue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
10430Sstevel@tonic-gate {
10440Sstevel@tonic-gate 	unsigned int	i;
10450Sstevel@tonic-gate 	unsigned int	verbose = FALSE;
10460Sstevel@tonic-gate 	const int	SQUEUE_STATEDELT = (int)(sizeof (uintptr_t) + 9);
10470Sstevel@tonic-gate 	boolean_t	arm;
10480Sstevel@tonic-gate 	squeue_t	squeue;
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
10510Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`squeue_cache", "ip`squeue",
10520Sstevel@tonic-gate 		    argc, argv) == -1) {
10530Sstevel@tonic-gate 			mdb_warn("failed to walk squeue cache");
10540Sstevel@tonic-gate 			return (DCMD_ERR);
10550Sstevel@tonic-gate 		}
10560Sstevel@tonic-gate 		return (DCMD_OK);
10570Sstevel@tonic-gate 	}
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL)
10600Sstevel@tonic-gate 	    != argc)
10610Sstevel@tonic-gate 		return (DCMD_USAGE);
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	if (!DCMD_HDRSPEC(flags) && verbose)
10640Sstevel@tonic-gate 		mdb_printf("\n\n");
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) || verbose) {
10670Sstevel@tonic-gate 		mdb_printf("%?s %-5s %-3s %?s %?s %?s\n",
10680Sstevel@tonic-gate 		    "ADDR", "STATE", "CPU",
10690Sstevel@tonic-gate 		    "FIRST", "LAST", "WORKER");
10700Sstevel@tonic-gate 	}
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	if (mdb_vread(&squeue, sizeof (squeue_t), addr) == -1) {
10730Sstevel@tonic-gate 		mdb_warn("cannot read squeue_t at %p", addr);
10740Sstevel@tonic-gate 		return (DCMD_ERR);
10750Sstevel@tonic-gate 	}
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 	mdb_printf("%0?p %05x %3d %0?p %0?p %0?p\n",
10780Sstevel@tonic-gate 	    addr, squeue.sq_state, squeue.sq_bind,
10790Sstevel@tonic-gate 	    squeue.sq_first, squeue.sq_last, squeue.sq_worker);
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	if (!verbose)
10820Sstevel@tonic-gate 		return (DCMD_OK);
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	arm = B_TRUE;
10850Sstevel@tonic-gate 	for (i = 0; squeue_states[i].bit_name != NULL; i++) {
10860Sstevel@tonic-gate 		if (((squeue.sq_state) & (1 << i)) == 0)
10870Sstevel@tonic-gate 			continue;
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 		if (arm) {
10900Sstevel@tonic-gate 			mdb_printf("%*s|\n", SQUEUE_STATEDELT, "");
10910Sstevel@tonic-gate 			mdb_printf("%*s+-->  ", SQUEUE_STATEDELT, "");
10920Sstevel@tonic-gate 			arm = B_FALSE;
10930Sstevel@tonic-gate 		} else
10940Sstevel@tonic-gate 			mdb_printf("%*s      ", SQUEUE_STATEDELT, "");
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 		mdb_printf("%-12s %s\n", squeue_states[i].bit_name,
10970Sstevel@tonic-gate 		    squeue_states[i].bit_descr);
10980Sstevel@tonic-gate 	}
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	return (DCMD_OK);
11010Sstevel@tonic-gate }
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate static void
11040Sstevel@tonic-gate ip_squeue_help(void)
11050Sstevel@tonic-gate {
11060Sstevel@tonic-gate 	mdb_printf("Print the core information for a given NCA squeue_t.\n\n");
11070Sstevel@tonic-gate 	mdb_printf("Options:\n");
11080Sstevel@tonic-gate 	mdb_printf("\t-v\tbe verbose (more descriptive)\n");
11090Sstevel@tonic-gate }
11100Sstevel@tonic-gate 
11115023Scarlsonj /*
11125023Scarlsonj  * This is called by ::th_trace (via a callback) when walking the th_hash
11135023Scarlsonj  * list.  It calls modent to find the entries.
11145023Scarlsonj  */
11155023Scarlsonj /* ARGSUSED */
11165023Scarlsonj static int
11175023Scarlsonj modent_summary(uintptr_t addr, const void *data, void *private)
11185023Scarlsonj {
11195023Scarlsonj 	th_walk_data_t *thw = private;
11205023Scarlsonj 	const struct mod_hash_entry *mhe = data;
11215023Scarlsonj 	th_trace_t th;
11225023Scarlsonj 
11235023Scarlsonj 	if (mdb_vread(&th, sizeof (th), (uintptr_t)mhe->mhe_val) == -1) {
11245023Scarlsonj 		mdb_warn("failed to read th_trace_t %p", mhe->mhe_val);
11255023Scarlsonj 		return (WALK_ERR);
11265023Scarlsonj 	}
11275023Scarlsonj 
11285023Scarlsonj 	if (th.th_refcnt == 0 && thw->thw_non_zero_only)
11295023Scarlsonj 		return (WALK_NEXT);
11305023Scarlsonj 
11315023Scarlsonj 	if (!thw->thw_match) {
11325023Scarlsonj 		mdb_printf("%?p %?p %?p %8d %?p\n", thw->thw_ipst, mhe->mhe_key,
11335023Scarlsonj 		    mhe->mhe_val, th.th_refcnt, th.th_id);
11345023Scarlsonj 	} else if (thw->thw_matchkey == (uintptr_t)mhe->mhe_key) {
11355023Scarlsonj 		int i, j, k;
11365023Scarlsonj 		tr_buf_t *tr;
11375023Scarlsonj 
11385023Scarlsonj 		mdb_printf("Object %p in IP stack %p:\n", mhe->mhe_key,
11395023Scarlsonj 		    thw->thw_ipst);
11405023Scarlsonj 		i = th.th_trace_lastref;
11415023Scarlsonj 		mdb_printf("\tThread %p refcnt %d:\n", th.th_id,
11425023Scarlsonj 		    th.th_refcnt);
11435023Scarlsonj 		for (j = TR_BUF_MAX; j > 0; j--) {
11445023Scarlsonj 			tr = th.th_trbuf + i;
11455023Scarlsonj 			if (tr->tr_depth == 0 || tr->tr_depth > TR_STACK_DEPTH)
11465023Scarlsonj 				break;
11475023Scarlsonj 			mdb_printf("\t  T%+ld:\n", tr->tr_time -
11485023Scarlsonj 			    thw->thw_lbolt);
11495023Scarlsonj 			for (k = 0; k < tr->tr_depth; k++)
11505023Scarlsonj 				mdb_printf("\t\t%a\n", tr->tr_stack[k]);
11515023Scarlsonj 			if (--i < 0)
11525023Scarlsonj 				i = TR_BUF_MAX - 1;
11535023Scarlsonj 		}
11545023Scarlsonj 	}
11555023Scarlsonj 	return (WALK_NEXT);
11565023Scarlsonj }
11575023Scarlsonj 
11585023Scarlsonj /*
11595023Scarlsonj  * This is called by ::th_trace (via a callback) when walking the th_hash
11605023Scarlsonj  * list.  It calls modent to find the entries.
11615023Scarlsonj  */
11625023Scarlsonj /* ARGSUSED */
11635023Scarlsonj static int
11645023Scarlsonj th_hash_summary(uintptr_t addr, const void *data, void *private)
11655023Scarlsonj {
11665023Scarlsonj 	const th_hash_t *thh = data;
11675023Scarlsonj 	th_walk_data_t *thw = private;
11685023Scarlsonj 
11695023Scarlsonj 	thw->thw_ipst = (uintptr_t)thh->thh_ipst;
11705023Scarlsonj 	return (mdb_pwalk("modent", modent_summary, private,
11715023Scarlsonj 	    (uintptr_t)thh->thh_hash));
11725023Scarlsonj }
11735023Scarlsonj 
11745023Scarlsonj /*
11755023Scarlsonj  * Print or summarize the th_trace_t structures.
11765023Scarlsonj  */
11775023Scarlsonj static int
11785023Scarlsonj th_trace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
11795023Scarlsonj {
11805023Scarlsonj 	th_walk_data_t thw;
11815023Scarlsonj 
11825023Scarlsonj 	(void) memset(&thw, 0, sizeof (thw));
11835023Scarlsonj 
11845023Scarlsonj 	if (mdb_getopts(argc, argv,
11855023Scarlsonj 	    'n', MDB_OPT_SETBITS, TRUE, &thw.thw_non_zero_only,
11865023Scarlsonj 	    NULL) != argc)
11875023Scarlsonj 		return (DCMD_USAGE);
11885023Scarlsonj 
11895023Scarlsonj 	if (!(flags & DCMD_ADDRSPEC)) {
11905023Scarlsonj 		/*
11915023Scarlsonj 		 * No address specified.  Walk all of the th_hash_t in the
11925023Scarlsonj 		 * system, and summarize the th_trace_t entries in each.
11935023Scarlsonj 		 */
11945023Scarlsonj 		mdb_printf("%?s %?s %?s %8s %?s\n",
11955023Scarlsonj 		    "IPSTACK", "OBJECT", "TRACE", "REFCNT", "THREAD");
11965023Scarlsonj 		thw.thw_match = B_FALSE;
11975023Scarlsonj 	} else {
11985023Scarlsonj 		thw.thw_match = B_TRUE;
11995023Scarlsonj 		thw.thw_matchkey = addr;
12005023Scarlsonj 		if (mdb_readvar(&thw.thw_lbolt,
12015023Scarlsonj 		    mdb_prop_postmortem ? "panic_lbolt" : "lbolt") == -1) {
12025023Scarlsonj 			mdb_warn("failed to read lbolt");
12035023Scarlsonj 			return (DCMD_ERR);
12045023Scarlsonj 		}
12055023Scarlsonj 	}
12065023Scarlsonj 	if (mdb_pwalk("th_hash", th_hash_summary, &thw, NULL) == -1) {
12075023Scarlsonj 		mdb_warn("can't walk th_hash entries");
12085023Scarlsonj 		return (DCMD_ERR);
12095023Scarlsonj 	}
12105023Scarlsonj 	return (DCMD_OK);
12115023Scarlsonj }
12125023Scarlsonj 
12135023Scarlsonj static void
12145023Scarlsonj th_trace_help(void)
12155023Scarlsonj {
12165023Scarlsonj 	mdb_printf("If given an address of an ill_t, ipif_t, ire_t, or nce_t, "
12175023Scarlsonj 	    "print the\n"
12185023Scarlsonj 	    "corresponding th_trace_t structure in detail.  Otherwise, if no "
12195023Scarlsonj 	    "address is\n"
12205023Scarlsonj 	    "given, then summarize all th_trace_t structures.\n\n");
12215023Scarlsonj 	mdb_printf("Options:\n"
12225023Scarlsonj 	    "\t-n\tdisplay only entries with non-zero th_refcnt\n");
12235023Scarlsonj }
12245023Scarlsonj 
12250Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = {
12260Sstevel@tonic-gate 	{ "illif", "?[-P v4 | v6]",
12270Sstevel@tonic-gate 	    "display or filter IP Lower Level InterFace structures", illif,
12280Sstevel@tonic-gate 	    illif_help },
12290Sstevel@tonic-gate 	{ "iphdr", ":[-vf]", "display an IPv4 header", iphdr },
12300Sstevel@tonic-gate 	{ "ip6hdr", ":[-vf]", "display an IPv6 header", ip6hdr },
1231*5940Ssowmini 	{ "ire", "?[-v] [-P v4|v6]",
1232*5940Ssowmini 	    "display Internet Route Entry structures", ire },
1233*5940Ssowmini 	{ "nce", "?[-P v4 | v6]", "display Neighbor Cache Entry structures",
1234*5940Ssowmini 	    nce },
12350Sstevel@tonic-gate 	{ "squeue", ":[-v]", "print core squeue_t info", squeue,
12360Sstevel@tonic-gate 	    ip_squeue_help },
12370Sstevel@tonic-gate 	{ "tcphdr", ":", "display a TCP header", tcphdr },
12380Sstevel@tonic-gate 	{ "udphdr", ":", "display an UDP header", udphdr },
12390Sstevel@tonic-gate 	{ "sctphdr", ":", "display an SCTP header", sctphdr },
12405023Scarlsonj 	{ "th_trace", "?[-n]", "display th_trace_t structures", th_trace,
12415023Scarlsonj 	    th_trace_help },
12420Sstevel@tonic-gate 	{ NULL }
12430Sstevel@tonic-gate };
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate static const mdb_walker_t walkers[] = {
12463448Sdh155122 	{ "illif", "walk list of ill interface types for all stacks",
1247*5940Ssowmini 		ip_stacks_common_walk_init, illif_walk_step, NULL },
12483448Sdh155122 	{ "illif_stack", "walk list of ill interface types",
12493448Sdh155122 		illif_stack_walk_init, illif_stack_walk_step,
12503448Sdh155122 		illif_stack_walk_fini },
12510Sstevel@tonic-gate 	{ "ire", "walk active ire_t structures",
12520Sstevel@tonic-gate 		ire_walk_init, ire_walk_step, NULL },
12533448Sdh155122 	{ "ire_ctable", "walk ire_t structures in the ctable",
1254*5940Ssowmini 		ip_stacks_common_walk_init, ire_ctable_walk_step, NULL },
12553448Sdh155122 	{ "ire_next", "walk ire_t structures in the ctable",
12563448Sdh155122 		ire_next_walk_init, ire_next_walk_step, NULL },
12573448Sdh155122 	{ "ip_stacks", "walk all the ip_stack_t",
12583448Sdh155122 		ip_stacks_walk_init, ip_stacks_walk_step, NULL },
12595023Scarlsonj 	{ "th_hash", "walk all the th_hash_t entries",
12605023Scarlsonj 		th_hash_walk_init, th_hash_walk_step, NULL },
1261*5940Ssowmini 	{ "nce", "walk list of nce structures for all stacks",
1262*5940Ssowmini 		ip_stacks_common_walk_init, nce_walk_step, NULL },
1263*5940Ssowmini 	{ "nce_stack", "walk list of nce structures",
1264*5940Ssowmini 		nce_stack_walk_init, nce_stack_walk_step,
1265*5940Ssowmini 		nce_stack_walk_fini},
12660Sstevel@tonic-gate 	{ NULL }
12670Sstevel@tonic-gate };
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate static const mdb_qops_t ip_qops = { ip_qinfo, ip_rnext, ip_wnext };
12700Sstevel@tonic-gate static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate const mdb_modinfo_t *
12730Sstevel@tonic-gate _mdb_init(void)
12740Sstevel@tonic-gate {
12750Sstevel@tonic-gate 	GElf_Sym sym;
12760Sstevel@tonic-gate 
12772546Scarlsonj 	if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0)
12780Sstevel@tonic-gate 		mdb_qops_install(&ip_qops, (uintptr_t)sym.st_value);
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate 	return (&modinfo);
12810Sstevel@tonic-gate }
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate void
12840Sstevel@tonic-gate _mdb_fini(void)
12850Sstevel@tonic-gate {
12860Sstevel@tonic-gate 	GElf_Sym sym;
12870Sstevel@tonic-gate 
12882546Scarlsonj 	if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0)
12890Sstevel@tonic-gate 		mdb_qops_remove(&ip_qops, (uintptr_t)sym.st_value);
12900Sstevel@tonic-gate }
1291*5940Ssowmini 
1292*5940Ssowmini static char *
1293*5940Ssowmini nce_state(int nce_state)
1294*5940Ssowmini {
1295*5940Ssowmini 	switch (nce_state) {
1296*5940Ssowmini 	case ND_UNCHANGED:
1297*5940Ssowmini 		return ("unchanged");
1298*5940Ssowmini 	case ND_INCOMPLETE:
1299*5940Ssowmini 		return ("incomplete");
1300*5940Ssowmini 	case ND_REACHABLE:
1301*5940Ssowmini 		return ("reachable");
1302*5940Ssowmini 	case ND_STALE:
1303*5940Ssowmini 		return ("stale");
1304*5940Ssowmini 	case ND_DELAY:
1305*5940Ssowmini 		return ("delay");
1306*5940Ssowmini 	case ND_PROBE:
1307*5940Ssowmini 		return ("probe");
1308*5940Ssowmini 	case ND_UNREACHABLE:
1309*5940Ssowmini 		return ("unreach");
1310*5940Ssowmini 	case ND_INITIAL:
1311*5940Ssowmini 		return ("initial");
1312*5940Ssowmini 	default:
1313*5940Ssowmini 		return ("??");
1314*5940Ssowmini 	}
1315*5940Ssowmini }
1316*5940Ssowmini 
1317*5940Ssowmini static char *
1318*5940Ssowmini nce_l2_addr(const nce_t *nce, const ill_t *ill)
1319*5940Ssowmini {
1320*5940Ssowmini 	uchar_t *h;
1321*5940Ssowmini 	static char addr_buf[L2MAXADDRSTRLEN];
1322*5940Ssowmini 	mblk_t mp;
1323*5940Ssowmini 	size_t mblen;
1324*5940Ssowmini 
1325*5940Ssowmini 	if (ill->ill_flags & ILLF_XRESOLV) {
1326*5940Ssowmini 		return ("XRESOLV");
1327*5940Ssowmini 	}
1328*5940Ssowmini 
1329*5940Ssowmini 	if (nce->nce_res_mp == NULL) {
1330*5940Ssowmini 		return ("None");
1331*5940Ssowmini 	}
1332*5940Ssowmini 
1333*5940Ssowmini 	if (ill->ill_net_type == IRE_IF_RESOLVER) {
1334*5940Ssowmini 
1335*5940Ssowmini 		if (mdb_vread(&mp, sizeof (mblk_t),
1336*5940Ssowmini 		    (uintptr_t)nce->nce_res_mp) == -1) {
1337*5940Ssowmini 			mdb_warn("failed to read nce_res_mp at %p",
1338*5940Ssowmini 			    nce->nce_res_mp);
1339*5940Ssowmini 		}
1340*5940Ssowmini 
1341*5940Ssowmini 		if (ill->ill_nd_lla_len == 0)
1342*5940Ssowmini 			return ("None");
1343*5940Ssowmini 		mblen = mp.b_wptr - mp.b_rptr;
1344*5940Ssowmini 		if (mblen > (sizeof (dl_unitdata_req_t) + MAX_SAP_LEN) ||
1345*5940Ssowmini 		    ill->ill_nd_lla_len > MAX_SAP_LEN ||
1346*5940Ssowmini 		    NCE_LL_ADDR_OFFSET(ill) + ill->ill_nd_lla_len > mblen) {
1347*5940Ssowmini 			return ("Truncated");
1348*5940Ssowmini 		}
1349*5940Ssowmini 		h = mdb_zalloc(mblen, UM_SLEEP);
1350*5940Ssowmini 		if (mdb_vread(h, mblen, (uintptr_t)(mp.b_rptr)) == -1) {
1351*5940Ssowmini 			mdb_warn("failed to read hwaddr at %p",
1352*5940Ssowmini 			    mp.b_rptr + NCE_LL_ADDR_OFFSET(ill));
1353*5940Ssowmini 			return ("Unknown");
1354*5940Ssowmini 		}
1355*5940Ssowmini 		mdb_mac_addr(h + NCE_LL_ADDR_OFFSET(ill), ill->ill_nd_lla_len,
1356*5940Ssowmini 		    addr_buf, sizeof (addr_buf));
1357*5940Ssowmini 	} else {
1358*5940Ssowmini 		return ("None");
1359*5940Ssowmini 	}
1360*5940Ssowmini 	mdb_free(h, mblen);
1361*5940Ssowmini 	return (addr_buf);
1362*5940Ssowmini }
1363*5940Ssowmini 
1364*5940Ssowmini static void
1365*5940Ssowmini nce_header(uint_t flags)
1366*5940Ssowmini {
1367*5940Ssowmini 	if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
1368*5940Ssowmini 
1369*5940Ssowmini 		mdb_printf("%<u>%?s %-20s %-10s %-8s %-5s %s%</u>\n",
1370*5940Ssowmini 		    "ADDR", "HW_ADDR", "STATE", "FLAGS", "ILL", "IP ADDR");
1371*5940Ssowmini 	}
1372*5940Ssowmini }
1373*5940Ssowmini 
1374*5940Ssowmini int
1375*5940Ssowmini nce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1376*5940Ssowmini {
1377*5940Ssowmini 	nce_t nce;
1378*5940Ssowmini 	nce_cbdata_t id;
1379*5940Ssowmini 	int ipversion = 0;
1380*5940Ssowmini 	const char *opt_P = NULL;
1381*5940Ssowmini 
1382*5940Ssowmini 	if (mdb_getopts(argc, argv,
1383*5940Ssowmini 	    'P', MDB_OPT_STR, &opt_P, NULL) != argc)
1384*5940Ssowmini 		return (DCMD_USAGE);
1385*5940Ssowmini 
1386*5940Ssowmini 	if (opt_P != NULL) {
1387*5940Ssowmini 		if (strcmp("v4", opt_P) == 0) {
1388*5940Ssowmini 			ipversion = IPV4_VERSION;
1389*5940Ssowmini 		} else if (strcmp("v6", opt_P) == 0) {
1390*5940Ssowmini 			ipversion = IPV6_VERSION;
1391*5940Ssowmini 		} else {
1392*5940Ssowmini 			mdb_warn("invalid protocol '%s'\n", opt_P);
1393*5940Ssowmini 			return (DCMD_USAGE);
1394*5940Ssowmini 		}
1395*5940Ssowmini 	}
1396*5940Ssowmini 
1397*5940Ssowmini 	if (flags & DCMD_ADDRSPEC) {
1398*5940Ssowmini 
1399*5940Ssowmini 		if (mdb_vread(&nce, sizeof (nce_t), addr) == -1) {
1400*5940Ssowmini 			mdb_warn("failed to read nce at %p\n", addr);
1401*5940Ssowmini 			return (DCMD_ERR);
1402*5940Ssowmini 		}
1403*5940Ssowmini 		if (ipversion != 0 && nce.nce_ipversion != ipversion) {
1404*5940Ssowmini 			mdb_printf("IP Version mismatch\n");
1405*5940Ssowmini 			return (DCMD_ERR);
1406*5940Ssowmini 		}
1407*5940Ssowmini 		nce_header(flags);
1408*5940Ssowmini 		return (nce_format(addr, &nce, ipversion));
1409*5940Ssowmini 
1410*5940Ssowmini 	} else {
1411*5940Ssowmini 		id.nce_addr = addr;
1412*5940Ssowmini 		id.nce_ipversion = ipversion;
1413*5940Ssowmini 		nce_header(flags);
1414*5940Ssowmini 		if (mdb_walk("nce", (mdb_walk_cb_t)nce_cb, &id) == -1) {
1415*5940Ssowmini 			mdb_warn("failed to walk nce table\n");
1416*5940Ssowmini 			return (DCMD_ERR);
1417*5940Ssowmini 		}
1418*5940Ssowmini 	}
1419*5940Ssowmini 	return (DCMD_OK);
1420*5940Ssowmini }
1421*5940Ssowmini 
1422*5940Ssowmini static int
1423*5940Ssowmini nce_format(uintptr_t addr, const nce_t *nce, int ipversion)
1424*5940Ssowmini {
1425*5940Ssowmini 	static const mdb_bitmask_t nce_flags[] = {
1426*5940Ssowmini 		{ "P",	NCE_F_PERMANENT,	NCE_F_PERMANENT },
1427*5940Ssowmini 		{ "R",	NCE_F_ISROUTER,		NCE_F_ISROUTER	},
1428*5940Ssowmini 		{ "N",	NCE_F_NONUD,		NCE_F_NONUD	},
1429*5940Ssowmini 		{ "A",	NCE_F_ANYCAST,		NCE_F_ANYCAST	},
1430*5940Ssowmini 		{ "C",	NCE_F_CONDEMNED,	NCE_F_CONDEMNED	},
1431*5940Ssowmini 		{ "U",	NCE_F_UNSOL_ADV,	NCE_F_UNSOL_ADV },
1432*5940Ssowmini 		{ "B",	NCE_F_BCAST,		NCE_F_BCAST	},
1433*5940Ssowmini 		{ NULL,	0,			0		}
1434*5940Ssowmini 	};
1435*5940Ssowmini #define	NCE_MAX_FLAGS	(sizeof (nce_flags) / sizeof (mdb_bitmask_t))
1436*5940Ssowmini 	struct in_addr nceaddr;
1437*5940Ssowmini 	ill_t ill;
1438*5940Ssowmini 	char ill_name[LIFNAMSIZ];
1439*5940Ssowmini 	char flagsbuf[NCE_MAX_FLAGS];
1440*5940Ssowmini 
1441*5940Ssowmini 	if (mdb_vread(&ill, sizeof (ill), (uintptr_t)nce->nce_ill) == -1) {
1442*5940Ssowmini 		mdb_warn("failed to read nce_ill at %p",
1443*5940Ssowmini 		    nce->nce_ill);
1444*5940Ssowmini 		return (DCMD_ERR);
1445*5940Ssowmini 	}
1446*5940Ssowmini 
1447*5940Ssowmini 	(void) mdb_readstr(ill_name, MIN(LIFNAMSIZ, ill.ill_name_length),
1448*5940Ssowmini 	    (uintptr_t)ill.ill_name);
1449*5940Ssowmini 
1450*5940Ssowmini 	mdb_snprintf(flagsbuf, sizeof (flagsbuf), "%hb",
1451*5940Ssowmini 	    nce->nce_flags, nce_flags);
1452*5940Ssowmini 
1453*5940Ssowmini 	if (ipversion != 0 && nce->nce_ipversion != ipversion)
1454*5940Ssowmini 		return (DCMD_OK);
1455*5940Ssowmini 
1456*5940Ssowmini 	if (nce->nce_ipversion == IPV4_VERSION) {
1457*5940Ssowmini 		IN6_V4MAPPED_TO_INADDR(&nce->nce_addr, &nceaddr);
1458*5940Ssowmini 		mdb_printf("%?p %-20s %-10s "
1459*5940Ssowmini 		    "%-8s "
1460*5940Ssowmini 		    "%-5s %I\n",
1461*5940Ssowmini 		    addr, nce_l2_addr(nce, &ill),
1462*5940Ssowmini 		    nce_state(nce->nce_state),
1463*5940Ssowmini 		    flagsbuf,
1464*5940Ssowmini 		    ill_name, nceaddr.s_addr);
1465*5940Ssowmini 	} else {
1466*5940Ssowmini 		mdb_printf("%?p %-20s %-10s %-8s %-5s %N\n",
1467*5940Ssowmini 		    addr,  nce_l2_addr(nce, &ill),
1468*5940Ssowmini 		    nce_state(nce->nce_state),
1469*5940Ssowmini 		    flagsbuf,
1470*5940Ssowmini 		    ill_name, &nce->nce_addr);
1471*5940Ssowmini 	}
1472*5940Ssowmini 
1473*5940Ssowmini 	return (DCMD_OK);
1474*5940Ssowmini }
1475*5940Ssowmini 
1476*5940Ssowmini static uintptr_t
1477*5940Ssowmini nce_get_next_hash_tbl(uintptr_t start, int *index, struct ndp_g_s ndp)
1478*5940Ssowmini {
1479*5940Ssowmini 	uintptr_t addr = start;
1480*5940Ssowmini 	int i = *index;
1481*5940Ssowmini 
1482*5940Ssowmini 	while (addr == NULL) {
1483*5940Ssowmini 
1484*5940Ssowmini 		if (++i >= NCE_TABLE_SIZE)
1485*5940Ssowmini 			break;
1486*5940Ssowmini 		addr = (uintptr_t)ndp.nce_hash_tbl[i];
1487*5940Ssowmini 	}
1488*5940Ssowmini 	*index = i;
1489*5940Ssowmini 	return (addr);
1490*5940Ssowmini }
1491*5940Ssowmini 
1492*5940Ssowmini static int
1493*5940Ssowmini nce_walk_step(mdb_walk_state_t *wsp)
1494*5940Ssowmini {
1495*5940Ssowmini 	uintptr_t kaddr4, kaddr6;
1496*5940Ssowmini 
1497*5940Ssowmini 	kaddr4 = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ndp4);
1498*5940Ssowmini 	kaddr6 = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ndp6);
1499*5940Ssowmini 
1500*5940Ssowmini 	if (mdb_vread(&kaddr4, sizeof (kaddr4), kaddr4) == -1) {
1501*5940Ssowmini 		mdb_warn("can't read ips_ip_cache_table at %p", kaddr4);
1502*5940Ssowmini 		return (WALK_ERR);
1503*5940Ssowmini 	}
1504*5940Ssowmini 	if (mdb_vread(&kaddr6, sizeof (kaddr6), kaddr6) == -1) {
1505*5940Ssowmini 		mdb_warn("can't read ips_ip_cache_table at %p", kaddr6);
1506*5940Ssowmini 		return (WALK_ERR);
1507*5940Ssowmini 	}
1508*5940Ssowmini 	if (mdb_pwalk("nce_stack", wsp->walk_callback, wsp->walk_cbdata,
1509*5940Ssowmini 	    kaddr4) == -1) {
1510*5940Ssowmini 		mdb_warn("couldn't walk 'nce_stack' for ips_ndp4 %p",
1511*5940Ssowmini 		    kaddr4);
1512*5940Ssowmini 		return (WALK_ERR);
1513*5940Ssowmini 	}
1514*5940Ssowmini 	if (mdb_pwalk("nce_stack", wsp->walk_callback,
1515*5940Ssowmini 	    wsp->walk_cbdata, kaddr6) == -1) {
1516*5940Ssowmini 		mdb_warn("couldn't walk 'nce_stack' for ips_ndp6 %p",
1517*5940Ssowmini 		    kaddr6);
1518*5940Ssowmini 		return (WALK_ERR);
1519*5940Ssowmini 	}
1520*5940Ssowmini 	return (WALK_NEXT);
1521*5940Ssowmini }
1522*5940Ssowmini 
1523*5940Ssowmini /*
1524*5940Ssowmini  * Called with walk_addr being the address of ips_ndp{4,6}
1525*5940Ssowmini  */
1526*5940Ssowmini static int
1527*5940Ssowmini nce_stack_walk_init(mdb_walk_state_t *wsp)
1528*5940Ssowmini {
1529*5940Ssowmini 	nce_walk_data_t *nw;
1530*5940Ssowmini 
1531*5940Ssowmini 	if (wsp->walk_addr == NULL) {
1532*5940Ssowmini 		mdb_warn("nce_stack requires ndp_g_s address\n");
1533*5940Ssowmini 		return (WALK_ERR);
1534*5940Ssowmini 	}
1535*5940Ssowmini 
1536*5940Ssowmini 	nw = mdb_alloc(sizeof (nce_walk_data_t), UM_SLEEP);
1537*5940Ssowmini 
1538*5940Ssowmini 	if (mdb_vread(&nw->nce_ip_ndp, sizeof (struct ndp_g_s),
1539*5940Ssowmini 	    wsp->walk_addr) == -1) {
1540*5940Ssowmini 		mdb_warn("failed to read 'ip_ndp' at %p",
1541*5940Ssowmini 		    wsp->walk_addr);
1542*5940Ssowmini 		mdb_free(nw, sizeof (nce_walk_data_t));
1543*5940Ssowmini 		return (WALK_ERR);
1544*5940Ssowmini 	}
1545*5940Ssowmini 
1546*5940Ssowmini 	nw->nce_hash_tbl_index = 0;
1547*5940Ssowmini 	wsp->walk_addr = nce_get_next_hash_tbl(NULL,
1548*5940Ssowmini 	    &nw->nce_hash_tbl_index, nw->nce_ip_ndp);
1549*5940Ssowmini 	wsp->walk_data = nw;
1550*5940Ssowmini 
1551*5940Ssowmini 	return (WALK_NEXT);
1552*5940Ssowmini }
1553*5940Ssowmini 
1554*5940Ssowmini static int
1555*5940Ssowmini nce_stack_walk_step(mdb_walk_state_t *wsp)
1556*5940Ssowmini {
1557*5940Ssowmini 	uintptr_t addr = wsp->walk_addr;
1558*5940Ssowmini 	nce_walk_data_t *nw = wsp->walk_data;
1559*5940Ssowmini 
1560*5940Ssowmini 	if (addr == NULL)
1561*5940Ssowmini 		return (WALK_DONE);
1562*5940Ssowmini 
1563*5940Ssowmini 	if (mdb_vread(&nw->nce, sizeof (nce_t), addr) == -1) {
1564*5940Ssowmini 		mdb_warn("failed to read nce_t at %p", addr);
1565*5940Ssowmini 		return (WALK_ERR);
1566*5940Ssowmini 	}
1567*5940Ssowmini 
1568*5940Ssowmini 	wsp->walk_addr = (uintptr_t)nw->nce.nce_next;
1569*5940Ssowmini 
1570*5940Ssowmini 	wsp->walk_addr = nce_get_next_hash_tbl(wsp->walk_addr,
1571*5940Ssowmini 	    &nw->nce_hash_tbl_index, nw->nce_ip_ndp);
1572*5940Ssowmini 
1573*5940Ssowmini 	return (wsp->walk_callback(addr, nw, wsp->walk_cbdata));
1574*5940Ssowmini }
1575*5940Ssowmini 
1576*5940Ssowmini static void
1577*5940Ssowmini nce_stack_walk_fini(mdb_walk_state_t *wsp)
1578*5940Ssowmini {
1579*5940Ssowmini 	mdb_free(wsp->walk_data, sizeof (nce_walk_data_t));
1580*5940Ssowmini }
1581*5940Ssowmini 
1582*5940Ssowmini /* ARGSUSED */
1583*5940Ssowmini static int
1584*5940Ssowmini nce_cb(uintptr_t addr, const nce_walk_data_t *iw, nce_cbdata_t *id)
1585*5940Ssowmini {
1586*5940Ssowmini 	nce_t nce;
1587*5940Ssowmini 
1588*5940Ssowmini 	if (mdb_vread(&nce, sizeof (nce_t), addr) == -1) {
1589*5940Ssowmini 		mdb_warn("failed to read nce at %p", addr);
1590*5940Ssowmini 		return (WALK_NEXT);
1591*5940Ssowmini 	}
1592*5940Ssowmini 	(void) nce_format(addr, &nce, id->nce_ipversion);
1593*5940Ssowmini 	return (WALK_NEXT);
1594*5940Ssowmini }
1595