xref: /onnv-gate/usr/src/cmd/mdb/common/modules/ip/ip.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/stropts.h>
31*0Sstevel@tonic-gate #include <sys/stream.h>
32*0Sstevel@tonic-gate #include <sys/socket.h>
33*0Sstevel@tonic-gate #include <sys/avl_impl.h>
34*0Sstevel@tonic-gate #include <net/if.h>
35*0Sstevel@tonic-gate #include <net/route.h>
36*0Sstevel@tonic-gate #include <netinet/in.h>
37*0Sstevel@tonic-gate #include <netinet/ip6.h>
38*0Sstevel@tonic-gate #include <netinet/udp.h>
39*0Sstevel@tonic-gate #include <netinet/sctp.h>
40*0Sstevel@tonic-gate #include <inet/mib2.h>
41*0Sstevel@tonic-gate #include <inet/common.h>
42*0Sstevel@tonic-gate #include <inet/ip.h>
43*0Sstevel@tonic-gate #include <inet/ip_ire.h>
44*0Sstevel@tonic-gate #include <inet/ip6.h>
45*0Sstevel@tonic-gate #include <inet/ipclassifier.h>
46*0Sstevel@tonic-gate #include <inet/mi.h>
47*0Sstevel@tonic-gate #include <sys/squeue_impl.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
50*0Sstevel@tonic-gate #include <mdb/mdb_ks.h>
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate #define	ADDR_WIDTH 11
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate typedef struct {
55*0Sstevel@tonic-gate 	const char *bit_name;	/* name of bit */
56*0Sstevel@tonic-gate 	const char *bit_descr;	/* description of bit's purpose */
57*0Sstevel@tonic-gate } bitname_t;
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate static const bitname_t squeue_states[] = {
60*0Sstevel@tonic-gate 	{ "SQS_PROC",		"being processed" },
61*0Sstevel@tonic-gate 	{ "SQS_WORKER",		"... by a worker thread" },
62*0Sstevel@tonic-gate 	{ "SQS_ENTER",		"... by an squeue_enter() thread" },
63*0Sstevel@tonic-gate 	{ "SQS_FAST",		"... in fast-path mode" },
64*0Sstevel@tonic-gate 	{ "SQS_USER", 		"A non interrupt user" },
65*0Sstevel@tonic-gate 	{ "SQS_BOUND",		"worker thread bound to CPU" },
66*0Sstevel@tonic-gate 	{ "SQS_PROFILE",	"profiling enabled" },
67*0Sstevel@tonic-gate 	{ "SQS_REENTER",	"re-entered thred" },
68*0Sstevel@tonic-gate 	{ NULL }
69*0Sstevel@tonic-gate };
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate typedef struct illif_walk_data {
72*0Sstevel@tonic-gate 	ill_g_head_t ill_g_heads[MAX_G_HEADS];
73*0Sstevel@tonic-gate 	int ill_list;
74*0Sstevel@tonic-gate 	ill_if_t ill_if;
75*0Sstevel@tonic-gate } illif_walk_data_t;
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate static int iphdr(uintptr_t, uint_t, int, const mdb_arg_t *);
78*0Sstevel@tonic-gate static int ip6hdr(uintptr_t, uint_t, int, const mdb_arg_t *);
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate int
81*0Sstevel@tonic-gate illif_walk_init(mdb_walk_state_t *wsp)
82*0Sstevel@tonic-gate {
83*0Sstevel@tonic-gate 	illif_walk_data_t *iw;
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	if (wsp->walk_addr != NULL) {
86*0Sstevel@tonic-gate 		mdb_warn("illif supports only global walks\n");
87*0Sstevel@tonic-gate 		return (WALK_ERR);
88*0Sstevel@tonic-gate 	}
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate 	iw = mdb_alloc(sizeof (illif_walk_data_t), UM_SLEEP);
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 	if (mdb_readsym(iw->ill_g_heads, MAX_G_HEADS * sizeof (ill_g_head_t),
93*0Sstevel@tonic-gate 	    "ill_g_heads") == -1) {
94*0Sstevel@tonic-gate 		mdb_warn("failed to read 'ill_g_heads'");
95*0Sstevel@tonic-gate 		mdb_free(iw, sizeof (illif_walk_data_t));
96*0Sstevel@tonic-gate 		return (WALK_ERR);
97*0Sstevel@tonic-gate 	}
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 	iw->ill_list = 0;
100*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)iw->IP_VX_ILL_G_LIST(0);
101*0Sstevel@tonic-gate 	wsp->walk_data = iw;
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 	return (WALK_NEXT);
104*0Sstevel@tonic-gate }
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate int
107*0Sstevel@tonic-gate illif_walk_step(mdb_walk_state_t *wsp)
108*0Sstevel@tonic-gate {
109*0Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
110*0Sstevel@tonic-gate 	illif_walk_data_t *iw = wsp->walk_data;
111*0Sstevel@tonic-gate 	int list = iw->ill_list;
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	if (mdb_vread(&iw->ill_if, sizeof (ill_if_t), addr) == -1) {
114*0Sstevel@tonic-gate 		mdb_warn("failed to read ill_if_t at %p", addr);
115*0Sstevel@tonic-gate 		return (WALK_ERR);
116*0Sstevel@tonic-gate 	}
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)iw->ill_if.illif_next;
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	if (wsp->walk_addr == (uintptr_t)iw->IP_VX_ILL_G_LIST(list)) {
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 		if (++list >= MAX_G_HEADS)
123*0Sstevel@tonic-gate 			return (WALK_DONE);
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 		iw->ill_list = list;
126*0Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)iw->IP_VX_ILL_G_LIST(list);
127*0Sstevel@tonic-gate 		return (WALK_NEXT);
128*0Sstevel@tonic-gate 	}
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	return (wsp->walk_callback(addr, iw, wsp->walk_cbdata));
131*0Sstevel@tonic-gate }
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate void
134*0Sstevel@tonic-gate illif_walk_fini(mdb_walk_state_t *wsp)
135*0Sstevel@tonic-gate {
136*0Sstevel@tonic-gate 	mdb_free(wsp->walk_data, sizeof (illif_walk_data_t));
137*0Sstevel@tonic-gate }
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate typedef struct illif_cbdata {
140*0Sstevel@tonic-gate 	uint_t ill_flags;
141*0Sstevel@tonic-gate 	uintptr_t ill_addr;
142*0Sstevel@tonic-gate 	int ill_printlist;	/* list to be printed (MAX_G_HEADS for all) */
143*0Sstevel@tonic-gate 	boolean_t ill_printed;
144*0Sstevel@tonic-gate } illif_cbdata_t;
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate static int
147*0Sstevel@tonic-gate illif_cb(uintptr_t addr, const illif_walk_data_t *iw, illif_cbdata_t *id)
148*0Sstevel@tonic-gate {
149*0Sstevel@tonic-gate 	const char *version;
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	if (id->ill_printlist < MAX_G_HEADS &&
152*0Sstevel@tonic-gate 	    id->ill_printlist != iw->ill_list)
153*0Sstevel@tonic-gate 		return (WALK_NEXT);
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate 	if (id->ill_flags & DCMD_ADDRSPEC && id->ill_addr != addr)
156*0Sstevel@tonic-gate 		return (WALK_NEXT);
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 	if (id->ill_flags & DCMD_PIPE_OUT) {
159*0Sstevel@tonic-gate 		mdb_printf("%p\n", addr);
160*0Sstevel@tonic-gate 		return (WALK_NEXT);
161*0Sstevel@tonic-gate 	}
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	switch (iw->ill_list) {
164*0Sstevel@tonic-gate 		case IP_V4_G_HEAD:	version = "v4";	break;
165*0Sstevel@tonic-gate 		case IP_V6_G_HEAD:	version = "v6";	break;
166*0Sstevel@tonic-gate 		default:		version = "??"; break;
167*0Sstevel@tonic-gate 	}
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	mdb_printf("%?p %2s %?p %10d %?p %s\n",
170*0Sstevel@tonic-gate 	    addr, version, addr + offsetof(ill_if_t, illif_avl_by_ppa),
171*0Sstevel@tonic-gate 	    iw->ill_if.illif_avl_by_ppa.avl_numnodes,
172*0Sstevel@tonic-gate 	    iw->ill_if.illif_ppa_arena, iw->ill_if.illif_name);
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 	id->ill_printed = TRUE;
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 	return (WALK_NEXT);
177*0Sstevel@tonic-gate }
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate int
180*0Sstevel@tonic-gate illif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
181*0Sstevel@tonic-gate {
182*0Sstevel@tonic-gate 	illif_cbdata_t id;
183*0Sstevel@tonic-gate 	ill_if_t ill_if;
184*0Sstevel@tonic-gate 	const char *opt_P = NULL;
185*0Sstevel@tonic-gate 	int printlist = MAX_G_HEADS;
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
188*0Sstevel@tonic-gate 	    'P', MDB_OPT_STR, &opt_P, NULL) != argc)
189*0Sstevel@tonic-gate 		return (DCMD_USAGE);
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 	if (opt_P != NULL) {
192*0Sstevel@tonic-gate 		if (strcmp("v4", opt_P) == 0) {
193*0Sstevel@tonic-gate 			printlist = IP_V4_G_HEAD;
194*0Sstevel@tonic-gate 		} else if (strcmp("v6", opt_P) == 0) {
195*0Sstevel@tonic-gate 			printlist = IP_V6_G_HEAD;
196*0Sstevel@tonic-gate 		} else {
197*0Sstevel@tonic-gate 			mdb_warn("invalid protocol '%s'\n", opt_P);
198*0Sstevel@tonic-gate 			return (DCMD_USAGE);
199*0Sstevel@tonic-gate 		}
200*0Sstevel@tonic-gate 	}
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) {
203*0Sstevel@tonic-gate 		mdb_printf("%<u>%?s %2s %?s %10s %?s %-10s%</u>\n",
204*0Sstevel@tonic-gate 		    "ADDR", "IP", "AVLADDR", "NUMNODES", "ARENA", "NAME");
205*0Sstevel@tonic-gate 	}
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 	id.ill_flags = flags;
208*0Sstevel@tonic-gate 	id.ill_addr = addr;
209*0Sstevel@tonic-gate 	id.ill_printlist = printlist;
210*0Sstevel@tonic-gate 	id.ill_printed = FALSE;
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	if (mdb_walk("illif", (mdb_walk_cb_t)illif_cb, &id) == -1) {
213*0Sstevel@tonic-gate 		mdb_warn("can't walk ill_if_t structures");
214*0Sstevel@tonic-gate 		return (DCMD_ERR);
215*0Sstevel@tonic-gate 	}
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || opt_P != NULL || id.ill_printed)
218*0Sstevel@tonic-gate 		return (DCMD_OK);
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	/*
221*0Sstevel@tonic-gate 	 * If an address is specified and the walk doesn't find it,
222*0Sstevel@tonic-gate 	 * print it anyway.
223*0Sstevel@tonic-gate 	 */
224*0Sstevel@tonic-gate 	if (mdb_vread(&ill_if, sizeof (ill_if_t), addr) == -1) {
225*0Sstevel@tonic-gate 		mdb_warn("failed to read ill_if_t at %p", addr);
226*0Sstevel@tonic-gate 		return (DCMD_ERR);
227*0Sstevel@tonic-gate 	}
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	mdb_printf("%?p %2s %?p %10d %?p %s\n",
230*0Sstevel@tonic-gate 	    addr, "??", addr + offsetof(ill_if_t, illif_avl_by_ppa),
231*0Sstevel@tonic-gate 	    ill_if.illif_avl_by_ppa.avl_numnodes,
232*0Sstevel@tonic-gate 	    ill_if.illif_ppa_arena, ill_if.illif_name);
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	return (DCMD_OK);
235*0Sstevel@tonic-gate }
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate static void
238*0Sstevel@tonic-gate illif_help(void)
239*0Sstevel@tonic-gate {
240*0Sstevel@tonic-gate 	mdb_printf("Options:\n");
241*0Sstevel@tonic-gate 	mdb_printf("\t-P v4 | v6"
242*0Sstevel@tonic-gate 	    "\tfilter interface structures for the specified protocol\n");
243*0Sstevel@tonic-gate }
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate int
246*0Sstevel@tonic-gate ire_walk_init(mdb_walk_state_t *wsp)
247*0Sstevel@tonic-gate {
248*0Sstevel@tonic-gate 	if (mdb_layered_walk("ire_cache", wsp) == -1) {
249*0Sstevel@tonic-gate 		mdb_warn("can't walk 'ire_cache'");
250*0Sstevel@tonic-gate 		return (WALK_ERR);
251*0Sstevel@tonic-gate 	}
252*0Sstevel@tonic-gate 
253*0Sstevel@tonic-gate 	return (WALK_NEXT);
254*0Sstevel@tonic-gate }
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate int
257*0Sstevel@tonic-gate ire_walk_step(mdb_walk_state_t *wsp)
258*0Sstevel@tonic-gate {
259*0Sstevel@tonic-gate 	ire_t ire;
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) {
262*0Sstevel@tonic-gate 		mdb_warn("can't read ire at %p", wsp->walk_addr);
263*0Sstevel@tonic-gate 		return (WALK_ERR);
264*0Sstevel@tonic-gate 	}
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	return (wsp->walk_callback(wsp->walk_addr, &ire, wsp->walk_cbdata));
267*0Sstevel@tonic-gate }
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate static int
270*0Sstevel@tonic-gate ire_format(uintptr_t addr, const ire_t *irep, uint_t *verbose)
271*0Sstevel@tonic-gate {
272*0Sstevel@tonic-gate 	static const mdb_bitmask_t tmasks[] = {
273*0Sstevel@tonic-gate 		{ "BROADCAST",	IRE_BROADCAST,		IRE_BROADCAST	},
274*0Sstevel@tonic-gate 		{ "DEFAULT",	IRE_DEFAULT,		IRE_DEFAULT	},
275*0Sstevel@tonic-gate 		{ "LOCAL",	IRE_LOCAL,		IRE_LOCAL	},
276*0Sstevel@tonic-gate 		{ "LOOPBACK",	IRE_LOOPBACK,		IRE_LOOPBACK	},
277*0Sstevel@tonic-gate 		{ "PREFIX",	IRE_PREFIX,		IRE_PREFIX	},
278*0Sstevel@tonic-gate 		{ "CACHE",	IRE_CACHE,		IRE_CACHE	},
279*0Sstevel@tonic-gate 		{ "IF_NORESOLVER", IRE_IF_NORESOLVER,	IRE_IF_NORESOLVER },
280*0Sstevel@tonic-gate 		{ "IF_RESOLVER", IRE_IF_RESOLVER,	IRE_IF_RESOLVER	},
281*0Sstevel@tonic-gate 		{ "HOST",	IRE_HOST,		IRE_HOST	},
282*0Sstevel@tonic-gate 		{ "HOST_REDIRECT", IRE_HOST_REDIRECT,	IRE_HOST_REDIRECT },
283*0Sstevel@tonic-gate 		{ "MIPRTUN",	IRE_MIPRTUN,		IRE_MIPRTUN	},
284*0Sstevel@tonic-gate 		{ NULL,		0,			0		}
285*0Sstevel@tonic-gate 	};
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	static const mdb_bitmask_t mmasks[] = {
288*0Sstevel@tonic-gate 		{ "CONDEMNED",	IRE_MARK_CONDEMNED,	IRE_MARK_CONDEMNED },
289*0Sstevel@tonic-gate 		{ "NORECV",	IRE_MARK_NORECV,	IRE_MARK_NORECV	},
290*0Sstevel@tonic-gate 		{ "HIDDEN",	IRE_MARK_HIDDEN,	IRE_MARK_HIDDEN	},
291*0Sstevel@tonic-gate 		{ "NOADD",	IRE_MARK_NOADD,		IRE_MARK_NOADD	},
292*0Sstevel@tonic-gate 		{ "TEMPORARY",	IRE_MARK_TEMPORARY,	IRE_MARK_TEMPORARY },
293*0Sstevel@tonic-gate 		{ NULL,		0,			0		}
294*0Sstevel@tonic-gate 	};
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	static const mdb_bitmask_t fmasks[] = {
297*0Sstevel@tonic-gate 		{ "UP",		RTF_UP,			RTF_UP		},
298*0Sstevel@tonic-gate 		{ "GATEWAY",	RTF_GATEWAY,		RTF_GATEWAY	},
299*0Sstevel@tonic-gate 		{ "HOST",	RTF_HOST,		RTF_HOST	},
300*0Sstevel@tonic-gate 		{ "REJECT",	RTF_REJECT,		RTF_REJECT	},
301*0Sstevel@tonic-gate 		{ "DYNAMIC",	RTF_DYNAMIC,		RTF_DYNAMIC	},
302*0Sstevel@tonic-gate 		{ "MODIFIED",	RTF_MODIFIED,		RTF_MODIFIED	},
303*0Sstevel@tonic-gate 		{ "DONE",	RTF_DONE,		RTF_DONE	},
304*0Sstevel@tonic-gate 		{ "MASK",	RTF_MASK,		RTF_MASK	},
305*0Sstevel@tonic-gate 		{ "CLONING",	RTF_CLONING,		RTF_CLONING	},
306*0Sstevel@tonic-gate 		{ "XRESOLVE",	RTF_XRESOLVE,		RTF_XRESOLVE	},
307*0Sstevel@tonic-gate 		{ "LLINFO",	RTF_LLINFO,		RTF_LLINFO	},
308*0Sstevel@tonic-gate 		{ "STATIC",	RTF_STATIC,		RTF_STATIC	},
309*0Sstevel@tonic-gate 		{ "BLACKHOLE",	RTF_BLACKHOLE,		RTF_BLACKHOLE	},
310*0Sstevel@tonic-gate 		{ "PRIVATE",	RTF_PRIVATE,		RTF_PRIVATE	},
311*0Sstevel@tonic-gate 		{ "PROTO2",	RTF_PROTO2,		RTF_PROTO2	},
312*0Sstevel@tonic-gate 		{ "PROTO1",	RTF_PROTO1,		RTF_PROTO1	},
313*0Sstevel@tonic-gate 		{ "MULTIRT",	RTF_MULTIRT,		RTF_MULTIRT	},
314*0Sstevel@tonic-gate 		{ "SETSRC",	RTF_SETSRC,		RTF_SETSRC	},
315*0Sstevel@tonic-gate 		{ NULL,		0,			0		}
316*0Sstevel@tonic-gate 	};
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	if (irep->ire_ipversion == 6 && *verbose) {
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 		mdb_printf("%<b>%?p%</b> %40N <%hb>\n"
321*0Sstevel@tonic-gate 		    "%?s %40N <%hb>\n"
322*0Sstevel@tonic-gate 		    "%?s %40d <%hb>\n",
323*0Sstevel@tonic-gate 		    addr, &irep->ire_src_addr_v6, irep->ire_type, tmasks,
324*0Sstevel@tonic-gate 		    "", &irep->ire_addr_v6, (ushort_t)irep->ire_marks, mmasks,
325*0Sstevel@tonic-gate 		    "", irep->ire_zoneid, irep->ire_flags, fmasks);
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate 	} else if (irep->ire_ipversion == 6) {
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 		mdb_printf("%?p %30N %30N %4d\n", addr, &irep->ire_src_addr_v6,
330*0Sstevel@tonic-gate 		    &irep->ire_addr_v6, irep->ire_zoneid);
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	} else if (*verbose) {
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 		mdb_printf("%<b>%?p%</b> %40I <%hb>\n"
335*0Sstevel@tonic-gate 		    "%?s %40I <%hb>\n"
336*0Sstevel@tonic-gate 		    "%?s %40d <%hb>\n",
337*0Sstevel@tonic-gate 		    addr, irep->ire_src_addr, irep->ire_type, tmasks,
338*0Sstevel@tonic-gate 		    "", irep->ire_addr, (ushort_t)irep->ire_marks, mmasks,
339*0Sstevel@tonic-gate 		    "", irep->ire_zoneid, irep->ire_flags, fmasks);
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 	} else {
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 		mdb_printf("%?p %30I %30I %4d\n", addr, irep->ire_src_addr,
344*0Sstevel@tonic-gate 		    irep->ire_addr, irep->ire_zoneid);
345*0Sstevel@tonic-gate 	}
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	return (WALK_NEXT);
348*0Sstevel@tonic-gate }
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate /*
351*0Sstevel@tonic-gate  * There are faster ways to do this.  Given the interactive nature of this
352*0Sstevel@tonic-gate  * use I don't think its worth much effort.
353*0Sstevel@tonic-gate  */
354*0Sstevel@tonic-gate static unsigned short
355*0Sstevel@tonic-gate ipcksum(void *p, int len)
356*0Sstevel@tonic-gate {
357*0Sstevel@tonic-gate 	int32_t	sum = 0;
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	while (len > 1) {
360*0Sstevel@tonic-gate 		/* alignment */
361*0Sstevel@tonic-gate 		sum += *(uint16_t *)p;
362*0Sstevel@tonic-gate 		p = (char *)p + sizeof (uint16_t);
363*0Sstevel@tonic-gate 		if (sum & 0x80000000)
364*0Sstevel@tonic-gate 			sum = (sum & 0xFFFF) + (sum >> 16);
365*0Sstevel@tonic-gate 		len -= 2;
366*0Sstevel@tonic-gate 	}
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	if (len)
369*0Sstevel@tonic-gate 		sum += (uint16_t)*(unsigned char *)p;
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	while (sum >> 16)
372*0Sstevel@tonic-gate 		sum = (sum & 0xFFFF) + (sum >> 16);
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 	return (~sum);
375*0Sstevel@tonic-gate }
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate static const mdb_bitmask_t tcp_flags[] = {
378*0Sstevel@tonic-gate 	{ "SYN",	TH_SYN,		TH_SYN	},
379*0Sstevel@tonic-gate 	{ "ACK",	TH_ACK,		TH_ACK	},
380*0Sstevel@tonic-gate 	{ "FIN",	TH_FIN,		TH_FIN	},
381*0Sstevel@tonic-gate 	{ "RST",	TH_RST,		TH_RST	},
382*0Sstevel@tonic-gate 	{ "PSH",	TH_PUSH,	TH_PUSH	},
383*0Sstevel@tonic-gate 	{ "ECE",	TH_ECE,		TH_ECE	},
384*0Sstevel@tonic-gate 	{ "CWR",	TH_CWR,		TH_CWR	},
385*0Sstevel@tonic-gate 	{ NULL,		0,		0	}
386*0Sstevel@tonic-gate };
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate static void
389*0Sstevel@tonic-gate tcphdr_print(struct tcphdr *tcph)
390*0Sstevel@tonic-gate {
391*0Sstevel@tonic-gate 	in_port_t	sport, dport;
392*0Sstevel@tonic-gate 	tcp_seq		seq, ack;
393*0Sstevel@tonic-gate 	uint16_t	win, urp;
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	mdb_printf("%<b>TCP header%</b>\n");
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	mdb_nhconvert(&sport, &tcph->th_sport, sizeof (sport));
398*0Sstevel@tonic-gate 	mdb_nhconvert(&dport, &tcph->th_dport, sizeof (dport));
399*0Sstevel@tonic-gate 	mdb_nhconvert(&seq, &tcph->th_seq, sizeof (seq));
400*0Sstevel@tonic-gate 	mdb_nhconvert(&ack, &tcph->th_ack, sizeof (ack));
401*0Sstevel@tonic-gate 	mdb_nhconvert(&win, &tcph->th_win, sizeof (win));
402*0Sstevel@tonic-gate 	mdb_nhconvert(&urp, &tcph->th_urp, sizeof (urp));
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	mdb_printf("%<u>%6s %6s %10s %10s %4s %5s %5s %5s %-15s%</u>\n",
405*0Sstevel@tonic-gate 	    "SPORT", "DPORT", "SEQ", "ACK", "HLEN", "WIN", "CSUM", "URP",
406*0Sstevel@tonic-gate 	    "FLAGS");
407*0Sstevel@tonic-gate 	mdb_printf("%6hu %6hu %10u %10u %4d %5hu %5hu %5hu <%b>\n",
408*0Sstevel@tonic-gate 	    sport, dport, seq, ack, tcph->th_off << 2, win,
409*0Sstevel@tonic-gate 	    tcph->th_sum, urp, tcph->th_flags, tcp_flags);
410*0Sstevel@tonic-gate 	mdb_printf("0x%04x 0x%04x 0x%08x 0x%08x\n\n",
411*0Sstevel@tonic-gate 	    sport, dport, seq, ack);
412*0Sstevel@tonic-gate }
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate /* ARGSUSED */
415*0Sstevel@tonic-gate static int
416*0Sstevel@tonic-gate tcphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
417*0Sstevel@tonic-gate {
418*0Sstevel@tonic-gate 	struct tcphdr	tcph;
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
421*0Sstevel@tonic-gate 		return (DCMD_USAGE);
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) {
424*0Sstevel@tonic-gate 		mdb_warn("failed to read TCP header at %p", addr);
425*0Sstevel@tonic-gate 		return (DCMD_ERR);
426*0Sstevel@tonic-gate 	}
427*0Sstevel@tonic-gate 	tcphdr_print(&tcph);
428*0Sstevel@tonic-gate 	return (DCMD_OK);
429*0Sstevel@tonic-gate }
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate static void
432*0Sstevel@tonic-gate udphdr_print(struct udphdr *udph)
433*0Sstevel@tonic-gate {
434*0Sstevel@tonic-gate 	in_port_t	sport, dport;
435*0Sstevel@tonic-gate 	uint16_t	hlen;
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	mdb_printf("%<b>UDP header%</b>\n");
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	mdb_nhconvert(&sport, &udph->uh_sport, sizeof (sport));
440*0Sstevel@tonic-gate 	mdb_nhconvert(&dport, &udph->uh_dport, sizeof (dport));
441*0Sstevel@tonic-gate 	mdb_nhconvert(&hlen, &udph->uh_ulen, sizeof (hlen));
442*0Sstevel@tonic-gate 
443*0Sstevel@tonic-gate 	mdb_printf("%<u>%14s %14s %5s %6s%</u>\n",
444*0Sstevel@tonic-gate 	    "SPORT", "DPORT", "LEN", "CSUM");
445*0Sstevel@tonic-gate 	mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %5hu 0x%04hx\n\n", sport, sport,
446*0Sstevel@tonic-gate 	    dport, dport, hlen, udph->uh_sum);
447*0Sstevel@tonic-gate }
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate /* ARGSUSED */
450*0Sstevel@tonic-gate static int
451*0Sstevel@tonic-gate udphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
452*0Sstevel@tonic-gate {
453*0Sstevel@tonic-gate 	struct udphdr	udph;
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
456*0Sstevel@tonic-gate 		return (DCMD_USAGE);
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	if (mdb_vread(&udph, sizeof (udph), addr) == -1) {
459*0Sstevel@tonic-gate 		mdb_warn("failed to read UDP header at %p", addr);
460*0Sstevel@tonic-gate 		return (DCMD_ERR);
461*0Sstevel@tonic-gate 	}
462*0Sstevel@tonic-gate 	udphdr_print(&udph);
463*0Sstevel@tonic-gate 	return (DCMD_OK);
464*0Sstevel@tonic-gate }
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate static void
467*0Sstevel@tonic-gate sctphdr_print(sctp_hdr_t *sctph)
468*0Sstevel@tonic-gate {
469*0Sstevel@tonic-gate 	in_port_t sport, dport;
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 	mdb_printf("%<b>SCTP header%</b>\n");
472*0Sstevel@tonic-gate 	mdb_nhconvert(&sport, &sctph->sh_sport, sizeof (sport));
473*0Sstevel@tonic-gate 	mdb_nhconvert(&dport, &sctph->sh_dport, sizeof (dport));
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 	mdb_printf("%<u>%14s %14s %10s %10s%</u>\n",
476*0Sstevel@tonic-gate 	    "SPORT", "DPORT", "VTAG", "CHKSUM");
477*0Sstevel@tonic-gate 	mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %10u 0x%08x\n\n", sport, sport,
478*0Sstevel@tonic-gate 	    dport, dport, sctph->sh_verf, sctph->sh_chksum);
479*0Sstevel@tonic-gate }
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate /* ARGSUSED */
482*0Sstevel@tonic-gate static int
483*0Sstevel@tonic-gate sctphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
484*0Sstevel@tonic-gate {
485*0Sstevel@tonic-gate 	sctp_hdr_t sctph;
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC))
488*0Sstevel@tonic-gate 		return (DCMD_USAGE);
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 	if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) {
491*0Sstevel@tonic-gate 		mdb_warn("failed to read SCTP header at %p", addr);
492*0Sstevel@tonic-gate 		return (DCMD_ERR);
493*0Sstevel@tonic-gate 	}
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 	sctphdr_print(&sctph);
496*0Sstevel@tonic-gate 	return (DCMD_OK);
497*0Sstevel@tonic-gate }
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate static int
500*0Sstevel@tonic-gate transport_hdr(int proto, uintptr_t addr)
501*0Sstevel@tonic-gate {
502*0Sstevel@tonic-gate 	mdb_printf("\n");
503*0Sstevel@tonic-gate 	switch (proto) {
504*0Sstevel@tonic-gate 	case IPPROTO_TCP: {
505*0Sstevel@tonic-gate 		struct tcphdr tcph;
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 		if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) {
508*0Sstevel@tonic-gate 			mdb_warn("failed to read TCP header at %p", addr);
509*0Sstevel@tonic-gate 			return (DCMD_ERR);
510*0Sstevel@tonic-gate 		}
511*0Sstevel@tonic-gate 		tcphdr_print(&tcph);
512*0Sstevel@tonic-gate 		break;
513*0Sstevel@tonic-gate 	}
514*0Sstevel@tonic-gate 	case IPPROTO_UDP:  {
515*0Sstevel@tonic-gate 		struct udphdr udph;
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 		if (mdb_vread(&udph, sizeof (udph), addr) == -1) {
518*0Sstevel@tonic-gate 			mdb_warn("failed to read UDP header at %p", addr);
519*0Sstevel@tonic-gate 			return (DCMD_ERR);
520*0Sstevel@tonic-gate 		}
521*0Sstevel@tonic-gate 		udphdr_print(&udph);
522*0Sstevel@tonic-gate 		break;
523*0Sstevel@tonic-gate 	}
524*0Sstevel@tonic-gate 	case IPPROTO_SCTP: {
525*0Sstevel@tonic-gate 		sctp_hdr_t sctph;
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 		if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) {
528*0Sstevel@tonic-gate 			mdb_warn("failed to read SCTP header at %p", addr);
529*0Sstevel@tonic-gate 			return (DCMD_ERR);
530*0Sstevel@tonic-gate 		}
531*0Sstevel@tonic-gate 		sctphdr_print(&sctph);
532*0Sstevel@tonic-gate 		break;
533*0Sstevel@tonic-gate 	}
534*0Sstevel@tonic-gate 	default:
535*0Sstevel@tonic-gate 		break;
536*0Sstevel@tonic-gate 	}
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 	return (DCMD_OK);
539*0Sstevel@tonic-gate }
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate static const mdb_bitmask_t ip_flags[] = {
542*0Sstevel@tonic-gate 	{ "DF",	IPH_DF, IPH_DF	},
543*0Sstevel@tonic-gate 	{ "MF", IPH_MF,	IPH_MF	},
544*0Sstevel@tonic-gate 	{ NULL, 0,	0	}
545*0Sstevel@tonic-gate };
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate /* ARGSUSED */
548*0Sstevel@tonic-gate static int
549*0Sstevel@tonic-gate iphdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
550*0Sstevel@tonic-gate {
551*0Sstevel@tonic-gate 	uint_t		verbose = FALSE, force = FALSE;
552*0Sstevel@tonic-gate 	ipha_t		iph[1];
553*0Sstevel@tonic-gate 	uint16_t	ver, totlen, hdrlen, ipid, off, csum;
554*0Sstevel@tonic-gate 	uintptr_t	nxt_proto;
555*0Sstevel@tonic-gate 	char		exp_csum[8];
556*0Sstevel@tonic-gate 
557*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
558*0Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
559*0Sstevel@tonic-gate 	    'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc)
560*0Sstevel@tonic-gate 		return (DCMD_USAGE);
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	if (mdb_vread(iph, sizeof (*iph), addr) == -1) {
563*0Sstevel@tonic-gate 		mdb_warn("failed to read IPv4 header at %p", addr);
564*0Sstevel@tonic-gate 		return (DCMD_ERR);
565*0Sstevel@tonic-gate 	}
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	ver = (iph->ipha_version_and_hdr_length & 0xf0) >> 4;
568*0Sstevel@tonic-gate 	if (ver != IPV4_VERSION) {
569*0Sstevel@tonic-gate 		if (ver == IPV6_VERSION) {
570*0Sstevel@tonic-gate 			return (ip6hdr(addr, flags, argc, argv));
571*0Sstevel@tonic-gate 		} else if (!force) {
572*0Sstevel@tonic-gate 			mdb_warn("unknown IP version: %d\n", ver);
573*0Sstevel@tonic-gate 			return (DCMD_ERR);
574*0Sstevel@tonic-gate 		}
575*0Sstevel@tonic-gate 	}
576*0Sstevel@tonic-gate 
577*0Sstevel@tonic-gate 	mdb_printf("%<b>IPv4 header%</b>\n");
578*0Sstevel@tonic-gate 	mdb_printf("%-34s %-34s\n"
579*0Sstevel@tonic-gate 	    "%<u>%-4s %-4s %-5s %-5s %-6s %-5s %-5s %-6s %-8s %-6s%</u>\n",
580*0Sstevel@tonic-gate 	    "SRC", "DST",
581*0Sstevel@tonic-gate 	    "HLEN", "TOS", "LEN", "ID", "OFFSET", "TTL", "PROTO", "CHKSUM",
582*0Sstevel@tonic-gate 	    "EXP-CSUM", "FLGS");
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	hdrlen = (iph->ipha_version_and_hdr_length & 0x0f) << 2;
585*0Sstevel@tonic-gate 	mdb_nhconvert(&totlen, &iph->ipha_length, sizeof (totlen));
586*0Sstevel@tonic-gate 	mdb_nhconvert(&ipid, &iph->ipha_ident, sizeof (ipid));
587*0Sstevel@tonic-gate 	mdb_nhconvert(&off, &iph->ipha_fragment_offset_and_flags, sizeof (off));
588*0Sstevel@tonic-gate 	if (hdrlen == IP_SIMPLE_HDR_LENGTH) {
589*0Sstevel@tonic-gate 		if ((csum = ipcksum(iph, sizeof (*iph))) != 0)
590*0Sstevel@tonic-gate 			csum = ~(~csum + ~iph->ipha_hdr_checksum);
591*0Sstevel@tonic-gate 		else
592*0Sstevel@tonic-gate 			csum = iph->ipha_hdr_checksum;
593*0Sstevel@tonic-gate 		mdb_snprintf(exp_csum, 8, "%u", csum);
594*0Sstevel@tonic-gate 	} else {
595*0Sstevel@tonic-gate 		mdb_snprintf(exp_csum, 8, "<n/a>");
596*0Sstevel@tonic-gate 	}
597*0Sstevel@tonic-gate 
598*0Sstevel@tonic-gate 	mdb_printf("%-34I %-34I%\n"
599*0Sstevel@tonic-gate 	    "%-4d %-4d %-5hu %-5hu %-6hu %-5hu %-5hu %-6u %-8s <%5hb>\n",
600*0Sstevel@tonic-gate 	    iph->ipha_src, iph->ipha_dst,
601*0Sstevel@tonic-gate 	    hdrlen, iph->ipha_type_of_service, totlen, ipid,
602*0Sstevel@tonic-gate 	    (off << 3) & 0xffff, iph->ipha_ttl, iph->ipha_protocol,
603*0Sstevel@tonic-gate 	    iph->ipha_hdr_checksum, exp_csum, off, ip_flags);
604*0Sstevel@tonic-gate 
605*0Sstevel@tonic-gate 	if (verbose) {
606*0Sstevel@tonic-gate 		nxt_proto = addr + hdrlen;
607*0Sstevel@tonic-gate 		return (transport_hdr(iph->ipha_protocol, nxt_proto));
608*0Sstevel@tonic-gate 	} else {
609*0Sstevel@tonic-gate 		return (DCMD_OK);
610*0Sstevel@tonic-gate 	}
611*0Sstevel@tonic-gate }
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate /* ARGSUSED */
614*0Sstevel@tonic-gate static int
615*0Sstevel@tonic-gate ip6hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
616*0Sstevel@tonic-gate {
617*0Sstevel@tonic-gate 	uint_t		verbose = FALSE, force = FALSE;
618*0Sstevel@tonic-gate 	ip6_t		iph[1];
619*0Sstevel@tonic-gate 	int		ver, class, flow;
620*0Sstevel@tonic-gate 	uint16_t	plen;
621*0Sstevel@tonic-gate 	uintptr_t	nxt_proto;
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
624*0Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
625*0Sstevel@tonic-gate 	    'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc)
626*0Sstevel@tonic-gate 		return (DCMD_USAGE);
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate 	if (mdb_vread(iph, sizeof (*iph), addr) == -1) {
629*0Sstevel@tonic-gate 		mdb_warn("failed to read IPv6 header at %p", addr);
630*0Sstevel@tonic-gate 		return (DCMD_ERR);
631*0Sstevel@tonic-gate 	}
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	ver = (iph->ip6_vfc & 0xf0) >> 4;
634*0Sstevel@tonic-gate 	if (ver != IPV6_VERSION) {
635*0Sstevel@tonic-gate 		if (ver == IPV4_VERSION) {
636*0Sstevel@tonic-gate 			return (iphdr(addr, flags, argc, argv));
637*0Sstevel@tonic-gate 		} else if (!force) {
638*0Sstevel@tonic-gate 			mdb_warn("unknown IP version: %d\n", ver);
639*0Sstevel@tonic-gate 			return (DCMD_ERR);
640*0Sstevel@tonic-gate 		}
641*0Sstevel@tonic-gate 	}
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 	mdb_printf("%<b>IPv6 header%</b>\n");
644*0Sstevel@tonic-gate 	mdb_printf("%<u>%-26s %-26s %4s %7s %5s %3s %3s%</u>\n",
645*0Sstevel@tonic-gate 	    "SRC", "DST", "TCLS", "FLOW-ID", "PLEN", "NXT", "HOP");
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate 	class = (iph->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20;
648*0Sstevel@tonic-gate 	mdb_nhconvert(&class, &class, sizeof (class));
649*0Sstevel@tonic-gate 	flow = iph->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL;
650*0Sstevel@tonic-gate 	mdb_nhconvert(&flow, &flow, sizeof (flow));
651*0Sstevel@tonic-gate 	mdb_nhconvert(&plen, &iph->ip6_plen, sizeof (plen));
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	mdb_printf("%-26N %-26N %4d %7d %5hu %3d %3d\n",
654*0Sstevel@tonic-gate 	    &iph->ip6_src, &iph->ip6_dst,
655*0Sstevel@tonic-gate 	    class, flow, plen, iph->ip6_nxt, iph->ip6_hlim);
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	if (verbose) {
658*0Sstevel@tonic-gate 		nxt_proto = addr + sizeof (ip6_t);
659*0Sstevel@tonic-gate 		return (transport_hdr(iph->ip6_nxt, nxt_proto));
660*0Sstevel@tonic-gate 	} else {
661*0Sstevel@tonic-gate 		return (DCMD_OK);
662*0Sstevel@tonic-gate 	}
663*0Sstevel@tonic-gate }
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate int
666*0Sstevel@tonic-gate ire(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
667*0Sstevel@tonic-gate {
668*0Sstevel@tonic-gate 	uint_t verbose = FALSE;
669*0Sstevel@tonic-gate 	ire_t ire;
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
672*0Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc)
673*0Sstevel@tonic-gate 		return (DCMD_USAGE);
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 	if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 		if (verbose) {
678*0Sstevel@tonic-gate 			mdb_printf("%?s %40s %-20s%\n"
679*0Sstevel@tonic-gate 			    "%?s %40s %-20s%\n"
680*0Sstevel@tonic-gate 			    "%<u>%?s %40s %-20s%</u>\n",
681*0Sstevel@tonic-gate 			    "ADDR", "SRC", "TYPE",
682*0Sstevel@tonic-gate 			    "", "DST", "MARKS",
683*0Sstevel@tonic-gate 			    "", "ZONE", "FLAGS");
684*0Sstevel@tonic-gate 		} else {
685*0Sstevel@tonic-gate 			mdb_printf("%<u>%?s %30s %30s %4s%</u>\n",
686*0Sstevel@tonic-gate 			    "ADDR", "SRC", "DST", "ZONE");
687*0Sstevel@tonic-gate 		}
688*0Sstevel@tonic-gate 	}
689*0Sstevel@tonic-gate 
690*0Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC) {
691*0Sstevel@tonic-gate 		(void) mdb_vread(&ire, sizeof (ire_t), addr);
692*0Sstevel@tonic-gate 		(void) ire_format(addr, &ire, &verbose);
693*0Sstevel@tonic-gate 	} else if (mdb_walk("ire", (mdb_walk_cb_t)ire_format, &verbose) == -1) {
694*0Sstevel@tonic-gate 		mdb_warn("failed to walk ire table");
695*0Sstevel@tonic-gate 		return (DCMD_ERR);
696*0Sstevel@tonic-gate 	}
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	return (DCMD_OK);
699*0Sstevel@tonic-gate }
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate static size_t
702*0Sstevel@tonic-gate mi_osize(const queue_t *q)
703*0Sstevel@tonic-gate {
704*0Sstevel@tonic-gate 	/*
705*0Sstevel@tonic-gate 	 * The code in common/inet/mi.c allocates an extra word to store the
706*0Sstevel@tonic-gate 	 * size of the allocation.  An mi_o_s is thus a size_t plus an mi_o_s.
707*0Sstevel@tonic-gate 	 */
708*0Sstevel@tonic-gate 	struct mi_block {
709*0Sstevel@tonic-gate 		size_t mi_nbytes;
710*0Sstevel@tonic-gate 		struct mi_o_s mi_o;
711*0Sstevel@tonic-gate 	} m;
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 	if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr -
714*0Sstevel@tonic-gate 	    sizeof (m)) == sizeof (m))
715*0Sstevel@tonic-gate 		return (m.mi_nbytes - sizeof (m));
716*0Sstevel@tonic-gate 
717*0Sstevel@tonic-gate 	return (0);
718*0Sstevel@tonic-gate }
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate static void
721*0Sstevel@tonic-gate ip_ill_qinfo(const queue_t *q, char *buf, size_t nbytes)
722*0Sstevel@tonic-gate {
723*0Sstevel@tonic-gate 	char name[32];
724*0Sstevel@tonic-gate 	ill_t ill;
725*0Sstevel@tonic-gate 
726*0Sstevel@tonic-gate 	if (mdb_vread(&ill, sizeof (ill),
727*0Sstevel@tonic-gate 	    (uintptr_t)q->q_ptr) == sizeof (ill) &&
728*0Sstevel@tonic-gate 	    mdb_readstr(name, sizeof (name), (uintptr_t)ill.ill_name) > 0)
729*0Sstevel@tonic-gate 		(void) mdb_snprintf(buf, nbytes, "if: %s", name);
730*0Sstevel@tonic-gate }
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate void
733*0Sstevel@tonic-gate ip_qinfo(const queue_t *q, char *buf, size_t nbytes)
734*0Sstevel@tonic-gate {
735*0Sstevel@tonic-gate 	size_t size = mi_osize(q);
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 	if (size == sizeof (ill_t))
738*0Sstevel@tonic-gate 		ip_ill_qinfo(q, buf, nbytes);
739*0Sstevel@tonic-gate }
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate uintptr_t
742*0Sstevel@tonic-gate ip_rnext(const queue_t *q)
743*0Sstevel@tonic-gate {
744*0Sstevel@tonic-gate 	size_t size = mi_osize(q);
745*0Sstevel@tonic-gate 	ill_t ill;
746*0Sstevel@tonic-gate 
747*0Sstevel@tonic-gate 	if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill),
748*0Sstevel@tonic-gate 	    (uintptr_t)q->q_ptr) == sizeof (ill))
749*0Sstevel@tonic-gate 		return ((uintptr_t)ill.ill_rq);
750*0Sstevel@tonic-gate 
751*0Sstevel@tonic-gate 	return (NULL);
752*0Sstevel@tonic-gate }
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate uintptr_t
755*0Sstevel@tonic-gate ip_wnext(const queue_t *q)
756*0Sstevel@tonic-gate {
757*0Sstevel@tonic-gate 	size_t size = mi_osize(q);
758*0Sstevel@tonic-gate 	ill_t ill;
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 	if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill),
761*0Sstevel@tonic-gate 	    (uintptr_t)q->q_ptr) == sizeof (ill))
762*0Sstevel@tonic-gate 		return ((uintptr_t)ill.ill_wq);
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate 	return (NULL);
765*0Sstevel@tonic-gate }
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate /*
768*0Sstevel@tonic-gate  * Print the core fields in an squeue_t.  With the "-v" argument,
769*0Sstevel@tonic-gate  * provide more verbose output.
770*0Sstevel@tonic-gate  */
771*0Sstevel@tonic-gate static int
772*0Sstevel@tonic-gate squeue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
773*0Sstevel@tonic-gate {
774*0Sstevel@tonic-gate 	unsigned int	i;
775*0Sstevel@tonic-gate 	unsigned int	verbose = FALSE;
776*0Sstevel@tonic-gate 	const int	SQUEUE_STATEDELT = (int)(sizeof (uintptr_t) + 9);
777*0Sstevel@tonic-gate 	boolean_t	arm;
778*0Sstevel@tonic-gate 	squeue_t	squeue;
779*0Sstevel@tonic-gate 
780*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
781*0Sstevel@tonic-gate 		if (mdb_walk_dcmd("genunix`squeue_cache", "ip`squeue",
782*0Sstevel@tonic-gate 		    argc, argv) == -1) {
783*0Sstevel@tonic-gate 			mdb_warn("failed to walk squeue cache");
784*0Sstevel@tonic-gate 			return (DCMD_ERR);
785*0Sstevel@tonic-gate 		}
786*0Sstevel@tonic-gate 		return (DCMD_OK);
787*0Sstevel@tonic-gate 	}
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL)
790*0Sstevel@tonic-gate 	    != argc)
791*0Sstevel@tonic-gate 		return (DCMD_USAGE);
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	if (!DCMD_HDRSPEC(flags) && verbose)
794*0Sstevel@tonic-gate 		mdb_printf("\n\n");
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) || verbose) {
797*0Sstevel@tonic-gate 		mdb_printf("%?s %-5s %-3s %?s %?s %?s\n",
798*0Sstevel@tonic-gate 		    "ADDR", "STATE", "CPU",
799*0Sstevel@tonic-gate 		    "FIRST", "LAST", "WORKER");
800*0Sstevel@tonic-gate 	}
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate 	if (mdb_vread(&squeue, sizeof (squeue_t), addr) == -1) {
803*0Sstevel@tonic-gate 		mdb_warn("cannot read squeue_t at %p", addr);
804*0Sstevel@tonic-gate 		return (DCMD_ERR);
805*0Sstevel@tonic-gate 	}
806*0Sstevel@tonic-gate 
807*0Sstevel@tonic-gate 	mdb_printf("%0?p %05x %3d %0?p %0?p %0?p\n",
808*0Sstevel@tonic-gate 	    addr, squeue.sq_state, squeue.sq_bind,
809*0Sstevel@tonic-gate 	    squeue.sq_first, squeue.sq_last, squeue.sq_worker);
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	if (!verbose)
812*0Sstevel@tonic-gate 		return (DCMD_OK);
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 	arm = B_TRUE;
815*0Sstevel@tonic-gate 	for (i = 0; squeue_states[i].bit_name != NULL; i++) {
816*0Sstevel@tonic-gate 		if (((squeue.sq_state) & (1 << i)) == 0)
817*0Sstevel@tonic-gate 			continue;
818*0Sstevel@tonic-gate 
819*0Sstevel@tonic-gate 		if (arm) {
820*0Sstevel@tonic-gate 			mdb_printf("%*s|\n", SQUEUE_STATEDELT, "");
821*0Sstevel@tonic-gate 			mdb_printf("%*s+-->  ", SQUEUE_STATEDELT, "");
822*0Sstevel@tonic-gate 			arm = B_FALSE;
823*0Sstevel@tonic-gate 		} else
824*0Sstevel@tonic-gate 			mdb_printf("%*s      ", SQUEUE_STATEDELT, "");
825*0Sstevel@tonic-gate 
826*0Sstevel@tonic-gate 		mdb_printf("%-12s %s\n", squeue_states[i].bit_name,
827*0Sstevel@tonic-gate 		    squeue_states[i].bit_descr);
828*0Sstevel@tonic-gate 	}
829*0Sstevel@tonic-gate 
830*0Sstevel@tonic-gate 	return (DCMD_OK);
831*0Sstevel@tonic-gate }
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate static void
834*0Sstevel@tonic-gate ip_squeue_help(void)
835*0Sstevel@tonic-gate {
836*0Sstevel@tonic-gate 	mdb_printf("Print the core information for a given NCA squeue_t.\n\n");
837*0Sstevel@tonic-gate 	mdb_printf("Options:\n");
838*0Sstevel@tonic-gate 	mdb_printf("\t-v\tbe verbose (more descriptive)\n");
839*0Sstevel@tonic-gate }
840*0Sstevel@tonic-gate 
841*0Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = {
842*0Sstevel@tonic-gate 	{ "illif", "?[-P v4 | v6]",
843*0Sstevel@tonic-gate 	    "display or filter IP Lower Level InterFace structures", illif,
844*0Sstevel@tonic-gate 	    illif_help },
845*0Sstevel@tonic-gate 	{ "iphdr", ":[-vf]", "display an IPv4 header", iphdr },
846*0Sstevel@tonic-gate 	{ "ip6hdr", ":[-vf]", "display an IPv6 header", ip6hdr },
847*0Sstevel@tonic-gate 	{ "ire", "?[-v]", "display Internet Route Entry structures", ire },
848*0Sstevel@tonic-gate 	{ "squeue", ":[-v]", "print core squeue_t info", squeue,
849*0Sstevel@tonic-gate 	    ip_squeue_help },
850*0Sstevel@tonic-gate 	{ "tcphdr", ":", "display a TCP header", tcphdr },
851*0Sstevel@tonic-gate 	{ "udphdr", ":", "display an UDP header", udphdr },
852*0Sstevel@tonic-gate 	{ "sctphdr", ":", "display an SCTP header", sctphdr },
853*0Sstevel@tonic-gate 	{ NULL }
854*0Sstevel@tonic-gate };
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate static const mdb_walker_t walkers[] = {
857*0Sstevel@tonic-gate 	{ "illif", "walk list of ill interface types",
858*0Sstevel@tonic-gate 		illif_walk_init, illif_walk_step, illif_walk_fini },
859*0Sstevel@tonic-gate 	{ "ire", "walk active ire_t structures",
860*0Sstevel@tonic-gate 		ire_walk_init, ire_walk_step, NULL },
861*0Sstevel@tonic-gate 	{ NULL }
862*0Sstevel@tonic-gate };
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate static const mdb_qops_t ip_qops = { ip_qinfo, ip_rnext, ip_wnext };
865*0Sstevel@tonic-gate static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate const mdb_modinfo_t *
868*0Sstevel@tonic-gate _mdb_init(void)
869*0Sstevel@tonic-gate {
870*0Sstevel@tonic-gate 	GElf_Sym sym;
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 	if (mdb_lookup_by_obj("ip", "winit", &sym) == 0)
873*0Sstevel@tonic-gate 		mdb_qops_install(&ip_qops, (uintptr_t)sym.st_value);
874*0Sstevel@tonic-gate 
875*0Sstevel@tonic-gate 	return (&modinfo);
876*0Sstevel@tonic-gate }
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate void
879*0Sstevel@tonic-gate _mdb_fini(void)
880*0Sstevel@tonic-gate {
881*0Sstevel@tonic-gate 	GElf_Sym sym;
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 	if (mdb_lookup_by_obj("ip", "winit", &sym) == 0)
884*0Sstevel@tonic-gate 		mdb_qops_remove(&ip_qops, (uintptr_t)sym.st_value);
885*0Sstevel@tonic-gate }
886