xref: /illumos-gate/usr/src/cmd/mdb/common/modules/sctp/sctp.c (revision b02637af6dc592eb1f43cb4c74f06268648dbd2d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/stream.h>
31 #include <sys/mdb_modapi.h>
32 #include <sys/socket.h>
33 #include <sys/list.h>
34 #include <sys/strsun.h>
35 
36 #include <mdb/mdb_stdlib.h>
37 
38 #include <netinet/in.h>
39 #include <netinet/ip6.h>
40 #include <netinet/sctp.h>
41 
42 #include <inet/common.h>
43 #include <inet/ip.h>
44 #include <inet/ip6.h>
45 #include <inet/ipclassifier.h>
46 
47 #include <sctp/sctp_impl.h>
48 #include <sctp/sctp_addr.h>
49 
50 #define	MDB_SCTP_SHOW_FLAGS	0x1
51 #define	MDB_SCTP_DUMP_ADDRS	0x2
52 #define	MDB_SCTP_SHOW_HASH	0x4
53 #define	MDB_SCTP_SHOW_OUT	0x8
54 #define	MDB_SCTP_SHOW_IN	0x10
55 #define	MDB_SCTP_SHOW_MISC	0x20
56 #define	MDB_SCTP_SHOW_RTT	0x40
57 #define	MDB_SCTP_SHOW_STATS	0x80
58 #define	MDB_SCTP_SHOW_FLOW	0x100
59 #define	MDB_SCTP_SHOW_HDR	0x200
60 #define	MDB_SCTP_SHOW_PMTUD	0x400
61 #define	MDB_SCTP_SHOW_RXT	0x800
62 #define	MDB_SCTP_SHOW_CONN	0x1000
63 #define	MDB_SCTP_SHOW_CLOSE	0x2000
64 #define	MDB_SCTP_SHOW_EXT	0x4000
65 
66 #define	MDB_SCTP_SHOW_ALL	0xffffffff
67 
68 /*
69  * Copy from usr/src/uts/common/os/list.c.  Should we have a generic
70  * mdb list walker?
71  */
72 #define	list_object(a, node) ((void *)(((char *)node) - (a)->list_offset))
73 
74 static int
75 ns_to_stackid(uintptr_t kaddr)
76 {
77 	netstack_t nss;
78 
79 	if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
80 		mdb_warn("failed to read netdstack info %p", kaddr);
81 		return (0);
82 	}
83 	return (nss.netstack_stackid);
84 }
85 
86 int
87 sctp_stacks_walk_init(mdb_walk_state_t *wsp)
88 {
89 	if (mdb_layered_walk("netstack", wsp) == -1) {
90 		mdb_warn("can't walk 'netstack'");
91 		return (WALK_ERR);
92 	}
93 	return (WALK_NEXT);
94 }
95 
96 int
97 sctp_stacks_walk_step(mdb_walk_state_t *wsp)
98 {
99 	uintptr_t kaddr;
100 	netstack_t nss;
101 
102 	if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
103 		mdb_warn("can't read netstack at %p", wsp->walk_addr);
104 		return (WALK_ERR);
105 	}
106 	kaddr = (uintptr_t)nss.netstack_modules[NS_SCTP];
107 	return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
108 }
109 
110 static char *
111 sctp_faddr_state(int state)
112 {
113 	char *statestr;
114 
115 	switch (state) {
116 	case SCTP_FADDRS_UNREACH:
117 		statestr = "Unreachable";
118 		break;
119 	case SCTP_FADDRS_DOWN:
120 		statestr = "Down";
121 		break;
122 	case SCTP_FADDRS_ALIVE:
123 		statestr = "Alive";
124 		break;
125 	case SCTP_FADDRS_UNCONFIRMED:
126 		statestr = "Unconfirmed";
127 		break;
128 	default:
129 		statestr = "Unknown";
130 		break;
131 	}
132 	return (statestr);
133 }
134 
135 /* ARGSUSED */
136 static int
137 sctp_faddr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
138 {
139 	sctp_faddr_t fa[1];
140 	char *statestr;
141 
142 	if (!(flags & DCMD_ADDRSPEC))
143 		return (DCMD_USAGE);
144 
145 	if (mdb_vread(fa, sizeof (*fa), addr) == -1) {
146 		mdb_warn("cannot read fadder at %p", addr);
147 		return (DCMD_ERR);
148 	}
149 
150 	statestr = sctp_faddr_state(fa->state);
151 	mdb_printf("%<u>%p\t%<b>%N%</b>\t%s%</u>\n", addr, &fa->faddr,
152 	    statestr);
153 	mdb_printf("next\t\t%?p\tsaddr\t%N\n", fa->next, &fa->saddr);
154 	mdb_printf("rto\t\t%?d\tsrtt\t\t%?d\n", fa->rto, fa->srtt);
155 	mdb_printf("rttvar\t\t%?d\trtt_updates\t%?u\n", fa->rttvar,
156 	    fa->rtt_updates);
157 	mdb_printf("strikes\t\t%?d\tmax_retr\t%?d\n", fa->strikes,
158 	    fa->max_retr);
159 	mdb_printf("hb_expiry\t%?ld\thb_interval\t%?u\n", fa->hb_expiry,
160 	    fa->hb_interval);
161 	mdb_printf("pmss\t\t%?u\tcwnd\t\t%?u\n", fa->sfa_pmss, fa->cwnd);
162 	mdb_printf("ssthresh\t%?u\tsuna\t\t%?u\n", fa->ssthresh, fa->suna);
163 	mdb_printf("pba\t\t%?u\tacked\t\t%?u\n", fa->pba, fa->acked);
164 	mdb_printf("lastactive\t%?ld\thb_secret\t%?#lx\n", fa->lastactive,
165 	    fa->hb_secret);
166 	mdb_printf("rxt_unacked\t%?u\n", fa->rxt_unacked);
167 	mdb_printf("timer_mp\t%?p\tire\t\t%?p\n", fa->timer_mp, fa->ire);
168 	mdb_printf("hb_enabled\t%?d\thb_pending\t%?d\n"
169 	    "timer_running\t%?d\tdf\t\t%?d\n"
170 	    "pmtu_discovered\t%?d\tisv4\t\t%?d\n"
171 	    "retransmissions\t%?u\n",
172 	    fa->hb_enabled, fa->hb_pending, fa->timer_running, fa->df,
173 	    fa->pmtu_discovered, fa->isv4, fa->T3expire);
174 
175 	return (DCMD_OK);
176 }
177 
178 static void
179 print_set(sctp_set_t *sp)
180 {
181 	mdb_printf("\tbegin\t%<b>%?x%</b>\t\tend\t%<b>%?x%</b>\n",
182 	    sp->begin, sp->end);
183 	mdb_printf("\tnext\t%?p\tprev\t%?p\n", sp->next, sp->prev);
184 }
185 
186 /* ARGSUSED */
187 static int
188 sctp_set(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
189 {
190 	sctp_set_t sp[1];
191 
192 	if (!(flags & DCMD_ADDRSPEC))
193 		return (DCMD_USAGE);
194 
195 	if (mdb_vread(sp, sizeof (*sp), addr) == -1)
196 		return (DCMD_ERR);
197 
198 	print_set(sp);
199 
200 	return (DCMD_OK);
201 }
202 
203 static void
204 dump_sack_info(uintptr_t addr)
205 {
206 	sctp_set_t sp[1];
207 
208 	while (addr != 0) {
209 		if (mdb_vread(sp, sizeof (*sp), addr) == -1) {
210 			mdb_warn("failed to read sctp_set at %p", addr);
211 			return;
212 		}
213 
214 		addr = (uintptr_t)sp->next;
215 		print_set(sp);
216 	}
217 }
218 
219 static int
220 dump_msghdr(mblk_t *meta)
221 {
222 	sctp_msg_hdr_t smh;
223 
224 	if (mdb_vread(&smh, sizeof (smh), (uintptr_t)meta->b_rptr) == -1)
225 		return (-1);
226 
227 	mdb_printf("%<u>msg_hdr_t at \t%?p\tsentto\t%?p%</u>\n",
228 	    meta->b_rptr, SCTP_CHUNK_DEST(meta));
229 	mdb_printf("\tttl\t%?ld\ttob\t%?ld\n", smh.smh_ttl, smh.smh_tob);
230 	mdb_printf("\tsid\t%?u\tssn\t%?u\n", smh.smh_sid, smh.smh_ssn);
231 	mdb_printf("\tppid\t%?u\tflags\t%?s\n", smh.smh_ppid,
232 	    smh.smh_flags & MSG_UNORDERED ? "unordered" : " ");
233 	mdb_printf("\tcontext\t%?u\tmsglen\t%?d\n", smh.smh_context,
234 	    smh.smh_msglen);
235 
236 	return (0);
237 }
238 
239 static int
240 dump_datahdr(mblk_t *mp)
241 {
242 	sctp_data_hdr_t	sdc;
243 	uint16_t		sdh_int16;
244 	uint32_t		sdh_int32;
245 
246 	if (mdb_vread(&sdc, sizeof (sdc), (uintptr_t)mp->b_rptr) == -1)
247 		return (-1);
248 
249 	mdb_printf("%<u>data_chunk_t \t%?p\tsentto\t%?p%</u>\n",
250 	    mp->b_rptr, SCTP_CHUNK_DEST(mp));
251 	mdb_printf("\tsent\t%?d\t", SCTP_CHUNK_ISSENT(mp)?1:0);
252 	mdb_printf("retrans\t%?d\n", SCTP_CHUNK_WANT_REXMIT(mp)?1:0);
253 	mdb_printf("\tacked\t%?d\t", SCTP_CHUNK_ISACKED(mp)?1:0);
254 	mdb_printf("sackcnt\t%?u\n", SCTP_CHUNK_SACKCNT(mp));
255 
256 	mdb_nhconvert(&sdh_int16, &sdc.sdh_len, sizeof (sdc.sdh_len));
257 	mdb_printf("\tlen\t%?d\t", sdh_int16);
258 	mdb_printf("BBIT=%d", SCTP_DATA_GET_BBIT(&sdc) == 0 ? 0 : 1);
259 	mdb_printf("EBIT=%d", SCTP_DATA_GET_EBIT(&sdc) == 0 ? 0 : 1);
260 
261 	mdb_nhconvert(&sdh_int32, &sdc.sdh_tsn, sizeof (sdc.sdh_tsn));
262 	mdb_nhconvert(&sdh_int16, &sdc.sdh_sid, sizeof (sdc.sdh_sid));
263 	mdb_printf("\ttsn\t%?x\tsid\t%?hu\n", sdh_int32, sdh_int16);
264 
265 	mdb_nhconvert(&sdh_int16, &sdc.sdh_ssn, sizeof (sdc.sdh_ssn));
266 	mdb_nhconvert(&sdh_int32, &sdc.sdh_payload_id,
267 	    sizeof (sdc.sdh_payload_id));
268 	mdb_printf("\tssn\t%?hu\tppid\t%?d\n", sdh_int16, sdh_int32);
269 
270 	return (0);
271 }
272 
273 static int
274 sctp_sent_list(mblk_t *addr)
275 {
276 	mblk_t meta, mp;
277 
278 	if (!addr)
279 		return (0);
280 
281 	if (mdb_vread(&meta, sizeof (meta), (uintptr_t)addr) == -1)
282 		return (-1);
283 
284 	for (;;) {
285 		dump_msghdr(&meta);
286 
287 		if (meta.b_cont == NULL) {
288 			mdb_printf("No data chunks with message header!\n");
289 			return (-1);
290 		}
291 		if (mdb_vread(&mp, sizeof (mp),
292 		    (uintptr_t)meta.b_cont) == -1) {
293 			return (-1);
294 		}
295 		for (;;) {
296 			dump_datahdr(&mp);
297 			if (!mp.b_next)
298 				break;
299 
300 			if (mdb_vread(&mp, sizeof (mp),
301 			    (uintptr_t)(mp.b_next)) == -1)
302 				return (-1);
303 		}
304 		if (meta.b_next == NULL)
305 			break;
306 		if (mdb_vread(&meta, sizeof (meta),
307 		    (uintptr_t)meta.b_next) == -1)
308 			return (-1);
309 	}
310 
311 	return (0);
312 }
313 
314 static int
315 sctp_unsent_list(mblk_t *addr)
316 {
317 	mblk_t meta;
318 
319 	if (!addr)
320 		return (0);
321 
322 	if (mdb_vread(&meta, sizeof (meta), (uintptr_t)addr) == -1)
323 		return (-1);
324 
325 	for (;;) {
326 		dump_msghdr(&meta);
327 
328 		if (meta.b_next == NULL)
329 			break;
330 
331 		if (mdb_vread(&meta, sizeof (meta),
332 		    (uintptr_t)meta.b_next) == -1)
333 			return (-1);
334 	}
335 
336 	return (0);
337 }
338 
339 /* ARGSUSED */
340 static int
341 sctp_xmit_list(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
342 {
343 	sctp_t sctp;
344 
345 	if (!(flags & DCMD_ADDRSPEC))
346 		return (DCMD_USAGE);
347 
348 	if (mdb_vread(&sctp, sizeof (sctp), addr) == -1)
349 		return (DCMD_ERR);
350 
351 	mdb_printf("%<b>Chunkified TX list%</b>\n");
352 	if (sctp_sent_list(sctp.sctp_xmit_head) < 0)
353 		return (DCMD_ERR);
354 
355 	mdb_printf("%<b>Unchunkified TX list%</b>\n");
356 	if (sctp_unsent_list(sctp.sctp_xmit_unsent) < 0)
357 		return (DCMD_ERR);
358 
359 	return (DCMD_OK);
360 }
361 
362 /* ARGSUSED */
363 static int
364 sctp_mdata_chunk(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
365 {
366 	sctp_data_hdr_t dc;
367 	mblk_t mp;
368 
369 	if (!(flags & DCMD_ADDRSPEC))
370 		return (DCMD_USAGE);
371 
372 	if (mdb_vread(&mp, sizeof (mp), addr) == -1)
373 		return (DCMD_ERR);
374 
375 	if (mdb_vread(&dc, sizeof (dc), (uintptr_t)mp.b_rptr) == -1)
376 		return (DCMD_ERR);
377 
378 	mdb_printf("%<b>%-?p%</b>tsn\t%?x\tsid\t%?hu\n", addr,
379 	    dc.sdh_tsn, dc.sdh_sid);
380 	mdb_printf("%-?sssn\t%?hu\tppid\t%?x\n", "", dc.sdh_ssn,
381 	    dc.sdh_payload_id);
382 
383 	return (DCMD_OK);
384 }
385 
386 /* ARGSUSED */
387 static int
388 sctp_istr_msgs(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
389 {
390 	mblk_t			istrmp;
391 	mblk_t			dmp;
392 	sctp_data_hdr_t 	dp;
393 	uintptr_t		daddr;
394 	uintptr_t		chaddr;
395 	boolean_t		bbit;
396 	boolean_t		ebit;
397 
398 	if (!(flags & DCMD_ADDRSPEC))
399 		return (DCMD_USAGE);
400 
401 	do {
402 		if (mdb_vread(&istrmp, sizeof (istrmp), addr) == -1)
403 			return (DCMD_ERR);
404 
405 		mdb_printf("\tistr mblk at %p: next: %?p\n"
406 		    "\t\tprev: %?p\tcont: %?p\n", addr, istrmp.b_next,
407 		    istrmp.b_prev, istrmp.b_cont);
408 		daddr = (uintptr_t)&istrmp;
409 		do {
410 			if (mdb_vread(&dmp, sizeof (dmp), daddr) == -1)
411 				break;
412 			chaddr = (uintptr_t)dmp.b_rptr;
413 			if (mdb_vread(&dp, sizeof (dp), chaddr) == -1)
414 				break;
415 
416 			bbit = (SCTP_DATA_GET_BBIT(&dp) != 0);
417 			ebit = (SCTP_DATA_GET_EBIT(&dp) != 0);
418 
419 			mdb_printf("\t\t\ttsn: %x  bbit: %d  ebit: %d\n",
420 			    dp.sdh_tsn, bbit, ebit);
421 
422 
423 			daddr = (uintptr_t)dmp.b_cont;
424 		} while (daddr != NULL);
425 
426 		addr = (uintptr_t)istrmp.b_next;
427 	} while (addr != NULL);
428 
429 	return (DCMD_OK);
430 }
431 
432 /* ARGSUSED */
433 static int
434 sctp_reass_list(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
435 {
436 	sctp_reass_t srp;
437 	mblk_t srpmp;
438 	sctp_data_hdr_t dp;
439 	mblk_t dmp;
440 	uintptr_t daddr;
441 	uintptr_t chaddr;
442 	boolean_t bbit, ebit;
443 
444 	if (!(flags & DCMD_ADDRSPEC))
445 		return (DCMD_USAGE);
446 
447 	do {
448 		if (mdb_vread(&srpmp, sizeof (srpmp), addr) == -1)
449 			return (DCMD_ERR);
450 
451 		if (mdb_vread(&srp, sizeof (srp),
452 		    (uintptr_t)srpmp.b_datap->db_base) == -1)
453 			return (DCMD_ERR);
454 
455 		mdb_printf("\treassembly mblk at %p: next: %?p\n"
456 		    "\t\tprev: %?p\tcont: %?p\n", addr, srpmp.b_next,
457 		    srpmp.b_prev, srpmp.b_cont);
458 		mdb_printf("\t\tssn: %hu\tneeded: %hu\tgot: %hu\ttail: %?p\n"
459 		    "\t\tpartial_delivered: %s\n", srp.ssn, srp.needed,
460 		    srp.got, srp.tail, srp.partial_delivered ? "TRUE" :
461 		    "FALSE");
462 
463 		/* display the contents of this ssn's reassemby list */
464 		daddr = DB_TYPE(&srpmp) == M_CTL ? (uintptr_t)srpmp.b_cont :
465 		    (uintptr_t)&srpmp;
466 		do {
467 			if (mdb_vread(&dmp, sizeof (dmp), daddr) == -1)
468 				break;
469 			chaddr = (uintptr_t)dmp.b_rptr;
470 			if (mdb_vread(&dp, sizeof (dp), chaddr) == -1)
471 				break;
472 
473 			bbit = (SCTP_DATA_GET_BBIT(&dp) != 0);
474 			ebit = (SCTP_DATA_GET_EBIT(&dp) != 0);
475 
476 			mdb_printf("\t\t\ttsn: %x  bbit: %d  ebit: %d\n",
477 			    dp.sdh_tsn, bbit, ebit);
478 
479 			daddr = (uintptr_t)dmp.b_cont;
480 		} while (daddr != NULL);
481 
482 		addr = (uintptr_t)srpmp.b_next;
483 	} while (addr != NULL);
484 
485 	return (DCMD_OK);
486 }
487 
488 /* ARGSUSED */
489 static int
490 sctp_uo_reass_list(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
491 {
492 	sctp_data_hdr_t	dp;
493 	mblk_t		dmp;
494 	uintptr_t	chaddr;
495 	boolean_t	bbit;
496 	boolean_t	ebit;
497 	boolean_t	ubit;
498 
499 	if (!(flags & DCMD_ADDRSPEC))
500 		return (DCMD_USAGE);
501 
502 	do {
503 		if (mdb_vread(&dmp, sizeof (dmp), addr) == -1)
504 			return (DCMD_ERR);
505 
506 		mdb_printf("\treassembly mblk at %p: next: %?p\n"
507 		    "\t\tprev: %?p\n", addr, dmp.b_next, dmp.b_prev);
508 
509 		chaddr = (uintptr_t)dmp.b_rptr;
510 		if (mdb_vread(&dp, sizeof (dp), chaddr) == -1)
511 			break;
512 
513 		bbit = (SCTP_DATA_GET_BBIT(&dp) != 0);
514 		ebit = (SCTP_DATA_GET_EBIT(&dp) != 0);
515 		ubit = (SCTP_DATA_GET_UBIT(&dp) != 0);
516 
517 		mdb_printf("\t\t\tsid: %hu ssn: %hu tsn: %x "
518 		    "flags: %x (U=%d B=%d E=%d)\n", dp.sdh_sid, dp.sdh_ssn,
519 		    dp.sdh_tsn, dp.sdh_flags, ubit, bbit, ebit);
520 
521 		addr = (uintptr_t)dmp.b_next;
522 	} while (addr != NULL);
523 
524 	return (DCMD_OK);
525 }
526 
527 static int
528 sctp_instr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
529 {
530 	sctp_instr_t sip;
531 
532 	if (!(flags & DCMD_ADDRSPEC))
533 		return (DCMD_USAGE);
534 
535 	if (mdb_vread(&sip, sizeof (sip), addr) == -1)
536 		return (DCMD_ERR);
537 
538 	mdb_printf("%<b>%-?p%</b>\n\tmsglist\t%?p\tnmsgs\t%?d\n"
539 	    "\tnextseq\t%?d\treass\t%?p\n", addr, sip.istr_msgs,
540 	    sip.istr_nmsgs, sip.nextseq, sip.istr_reass);
541 	mdb_set_dot(addr + sizeof (sip));
542 
543 	return (sctp_reass_list((uintptr_t)sip.istr_reass, flags, ac, av));
544 }
545 
546 static const char *
547 state2str(sctp_t *sctp)
548 {
549 	switch (sctp->sctp_state) {
550 	case SCTPS_IDLE:		return ("SCTPS_IDLE");
551 	case SCTPS_BOUND:		return ("SCTPS_BOUND");
552 	case SCTPS_LISTEN:		return ("SCTPS_LISTEN");
553 	case SCTPS_COOKIE_WAIT:		return ("SCTPS_COOKIE_WAIT");
554 	case SCTPS_COOKIE_ECHOED:	return ("SCTPS_COOKIE_ECHOED");
555 	case SCTPS_ESTABLISHED:		return ("SCTPS_ESTABLISHED");
556 	case SCTPS_SHUTDOWN_PENDING:	return ("SCTPS_SHUTDOWN_PENDING");
557 	case SCTPS_SHUTDOWN_SENT:	return ("SCTPS_SHUTDOWN_SENT");
558 	case SCTPS_SHUTDOWN_RECEIVED:	return ("SCTPS_SHUTDOWN_RECEIVED");
559 	case SCTPS_SHUTDOWN_ACK_SENT:	return ("SCTPS_SHUTDOWN_ACK_SENT");
560 	default:			return ("UNKNOWN STATE");
561 	}
562 }
563 
564 static void
565 show_sctp_flags(sctp_t *sctp)
566 {
567 	mdb_printf("\tunderstands_asconf\t%d\n",
568 	    sctp->sctp_understands_asconf);
569 	mdb_printf("\tdebug\t\t\t%d\n", sctp->sctp_debug);
570 	mdb_printf("\tcchunk_pend\t\t%d\n", sctp->sctp_cchunk_pend);
571 	mdb_printf("\tdgram_errind\t\t%d\n", sctp->sctp_dgram_errind);
572 
573 	mdb_printf("\tlinger\t\t\t%d\n", sctp->sctp_linger);
574 	if (sctp->sctp_lingering)
575 		return;
576 	mdb_printf("\tlingering\t\t%d\n", sctp->sctp_lingering);
577 	mdb_printf("\tloopback\t\t%d\n", sctp->sctp_loopback);
578 	mdb_printf("\tforce_sack\t\t%d\n", sctp->sctp_force_sack);
579 
580 	mdb_printf("\tack_timer_runing\t%d\n", sctp->sctp_ack_timer_running);
581 	mdb_printf("\trecvdstaddr\t\t%d\n", sctp->sctp_recvdstaddr);
582 	mdb_printf("\thwcksum\t\t\t%d\n", sctp->sctp_hwcksum);
583 	mdb_printf("\tunderstands_addip\t%d\n", sctp->sctp_understands_addip);
584 
585 	mdb_printf("\tbound_to_all\t\t%d\n", sctp->sctp_bound_to_all);
586 	mdb_printf("\tcansleep\t\t%d\n", sctp->sctp_cansleep);
587 	mdb_printf("\tdetached\t\t%d\n", sctp->sctp_detached);
588 	mdb_printf("\tsend_adaption\t\t%d\n", sctp->sctp_send_adaption);
589 
590 	mdb_printf("\trecv_adaption\t\t%d\n", sctp->sctp_recv_adaption);
591 	mdb_printf("\tndelay\t\t\t%d\n", sctp->sctp_ndelay);
592 	mdb_printf("\tcondemned\t\t%d\n", sctp->sctp_condemned);
593 	mdb_printf("\tchk_fast_rexmit\t\t%d\n", sctp->sctp_chk_fast_rexmit);
594 
595 	mdb_printf("\tprsctp_aware\t\t%d\n", sctp->sctp_prsctp_aware);
596 	mdb_printf("\tlinklocal\t\t%d\n", sctp->sctp_linklocal);
597 	mdb_printf("\trexmitting\t\t%d\n", sctp->sctp_rexmitting);
598 	mdb_printf("\tzero_win_probe\t\t%d\n", sctp->sctp_zero_win_probe);
599 
600 	mdb_printf("\trecvsndrcvinfo\t\t%d\n", sctp->sctp_recvsndrcvinfo);
601 	mdb_printf("\trecvassocevnt\t\t%d\n", sctp->sctp_recvassocevnt);
602 	mdb_printf("\trecvpathevnt\t\t%d\n", sctp->sctp_recvpathevnt);
603 	mdb_printf("\trecvsendfailevnt\t%d\n", sctp->sctp_recvsendfailevnt);
604 
605 	mdb_printf("\trecvpeerevnt\t\t%d\n", sctp->sctp_recvpeererr);
606 	mdb_printf("\trecvchutdownevnt\t%d\n", sctp->sctp_recvshutdownevnt);
607 	mdb_printf("\trecvcpdnevnt\t\t%d\n", sctp->sctp_recvpdevnt);
608 	mdb_printf("\trecvcalevnt\t\t%d\n\n", sctp->sctp_recvalevnt);
609 }
610 
611 /*
612  * Given a sctp_saddr_ipif_t, print out its address.  This assumes
613  * that addr contains the sctp_addr_ipif_t structure already and this
614  * function does not need to read it in.
615  */
616 /* ARGSUSED */
617 static int
618 print_saddr(uintptr_t ptr, const void *addr, void *cbdata)
619 {
620 	sctp_saddr_ipif_t *saddr = (sctp_saddr_ipif_t *)addr;
621 	sctp_ipif_t ipif;
622 	char *statestr;
623 
624 	/* Read in the sctp_ipif object */
625 	if (mdb_vread(&ipif, sizeof (ipif), (uintptr_t)saddr->saddr_ipifp) ==
626 	    -1) {
627 		mdb_warn("cannot read ipif at %p", saddr->saddr_ipifp);
628 		return (WALK_ERR);
629 	}
630 
631 	switch (ipif.sctp_ipif_state) {
632 	case SCTP_IPIFS_CONDEMNED:
633 		statestr = "Condemned";
634 		break;
635 	case SCTP_IPIFS_INVALID:
636 		statestr = "Invalid";
637 		break;
638 	case SCTP_IPIFS_DOWN:
639 		statestr = "Down";
640 		break;
641 	case SCTP_IPIFS_UP:
642 		statestr = "Up";
643 		break;
644 	default:
645 		statestr = "Unknown";
646 		break;
647 	}
648 	mdb_printf("\t%p\t%N% (%s", saddr->saddr_ipifp, &ipif.sctp_ipif_saddr,
649 	    statestr);
650 	if (saddr->saddr_ipif_dontsrc == 1)
651 		mdb_printf("/Dontsrc");
652 	if (saddr->saddr_ipif_unconfirmed == 1)
653 		mdb_printf("/Unconfirmed");
654 	if (saddr->saddr_ipif_delete_pending == 1)
655 		mdb_printf("/DeletePending");
656 	mdb_printf(")\n");
657 	mdb_printf("\t\t\tMTU %d id %d zoneid %d IPIF flags %x\n",
658 	    ipif.sctp_ipif_mtu, ipif.sctp_ipif_id,
659 	    ipif.sctp_ipif_zoneid, ipif.sctp_ipif_flags);
660 	return (WALK_NEXT);
661 }
662 
663 /*
664  * Given a sctp_faddr_t, print out its address.  This assumes that
665  * addr contains the sctp_faddr_t structure already and this function
666  * does not need to read it in.
667  */
668 static int
669 print_faddr(uintptr_t ptr, const void *addr, void *cbdata)
670 {
671 	char	*statestr;
672 	sctp_faddr_t *faddr = (sctp_faddr_t *)addr;
673 	int *i = cbdata;
674 
675 	statestr = sctp_faddr_state(faddr->state);
676 
677 	mdb_printf("\t%d:\t%N\t%?p (%s)\n", (*i)++, &faddr->faddr, ptr,
678 	    statestr);
679 	return (WALK_NEXT);
680 }
681 
682 int
683 sctp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
684 {
685 	sctp_t sctp;
686 	conn_t connp;
687 	int i;
688 	uint_t opts = 0;
689 	uint_t paddr = 0;
690 	in_port_t lport, fport;
691 
692 	if (!(flags & DCMD_ADDRSPEC))
693 		return (DCMD_USAGE);
694 
695 	if (mdb_vread(&sctp, sizeof (sctp), addr) == -1) {
696 		mdb_warn("failed to read sctp_t at: %p\n", addr);
697 		return (DCMD_ERR);
698 	}
699 	if (mdb_vread(&connp, sizeof (connp),
700 	    (uintptr_t)sctp.sctp_connp) == -1) {
701 		mdb_warn("failed to read conn_t at: %p\n", sctp.sctp_connp);
702 		return (DCMD_ERR);
703 	}
704 
705 	if (mdb_getopts(argc, argv,
706 	    'a', MDB_OPT_SETBITS, MDB_SCTP_SHOW_ALL, &opts,
707 	    'f', MDB_OPT_SETBITS, MDB_SCTP_SHOW_FLAGS, &opts,
708 	    'h', MDB_OPT_SETBITS, MDB_SCTP_SHOW_HASH, &opts,
709 	    'o', MDB_OPT_SETBITS, MDB_SCTP_SHOW_OUT, &opts,
710 	    'i', MDB_OPT_SETBITS, MDB_SCTP_SHOW_IN, &opts,
711 	    'm', MDB_OPT_SETBITS, MDB_SCTP_SHOW_MISC, &opts,
712 	    'r', MDB_OPT_SETBITS, MDB_SCTP_SHOW_RTT, &opts,
713 	    'S', MDB_OPT_SETBITS, MDB_SCTP_SHOW_STATS, &opts,
714 	    'F', MDB_OPT_SETBITS, MDB_SCTP_SHOW_FLOW, &opts,
715 	    'H', MDB_OPT_SETBITS, MDB_SCTP_SHOW_HDR, &opts,
716 	    'p', MDB_OPT_SETBITS, MDB_SCTP_SHOW_PMTUD, &opts,
717 	    'R', MDB_OPT_SETBITS, MDB_SCTP_SHOW_RXT, &opts,
718 	    'C', MDB_OPT_SETBITS, MDB_SCTP_SHOW_CONN, &opts,
719 	    'c', MDB_OPT_SETBITS, MDB_SCTP_SHOW_CLOSE, &opts,
720 	    'e', MDB_OPT_SETBITS, MDB_SCTP_SHOW_EXT, &opts,
721 	    'P', MDB_OPT_SETBITS, 1, &paddr,
722 	    'd', MDB_OPT_SETBITS, MDB_SCTP_DUMP_ADDRS, &opts) != argc) {
723 		return (DCMD_USAGE);
724 	}
725 
726 	/* non-verbose faddrs, suitable for pipelines to sctp_faddr */
727 	if (paddr != 0) {
728 		sctp_faddr_t faddr, *fp;
729 		for (fp = sctp.sctp_faddrs; fp != NULL; fp = faddr.next) {
730 			if (mdb_vread(&faddr, sizeof (faddr), (uintptr_t)fp)
731 			    == -1) {
732 				mdb_warn("failed to read faddr at %p",
733 				    fp);
734 				return (DCMD_ERR);
735 			}
736 			mdb_printf("%p\n", fp);
737 		}
738 		return (DCMD_OK);
739 	}
740 
741 	mdb_nhconvert(&lport, &sctp.sctp_lport, sizeof (lport));
742 	mdb_nhconvert(&fport, &sctp.sctp_fport, sizeof (fport));
743 	mdb_printf("%<u>%p% %22s S=%-6hu D=%-6hu% STACK=%d ZONE=%d%</u>", addr,
744 	    state2str(&sctp), lport, fport,
745 	    ns_to_stackid((uintptr_t)connp.conn_netstack), connp.conn_zoneid);
746 
747 	if (sctp.sctp_faddrs) {
748 		sctp_faddr_t faddr;
749 		if (mdb_vread(&faddr, sizeof (faddr),
750 		    (uintptr_t)sctp.sctp_faddrs) != -1)
751 			mdb_printf("%<u> %N%</u>", &faddr.faddr);
752 	}
753 	mdb_printf("\n");
754 
755 	if (opts & MDB_SCTP_DUMP_ADDRS) {
756 		mdb_printf("%<b>Local and Peer Addresses%</b>\n");
757 
758 		/* Display source addresses */
759 		mdb_printf("nsaddrs\t\t%?d\n", sctp.sctp_nsaddrs);
760 		(void) mdb_pwalk("sctp_walk_saddr", print_saddr, NULL, addr);
761 
762 		/* Display peer addresses */
763 		mdb_printf("nfaddrs\t\t%?d\n", sctp.sctp_nfaddrs);
764 		i = 1;
765 		(void) mdb_pwalk("sctp_walk_faddr", print_faddr, &i, addr);
766 
767 		mdb_printf("lastfaddr\t%?p\tprimary\t\t%?p\n",
768 		    sctp.sctp_lastfaddr, sctp.sctp_primary);
769 		mdb_printf("current\t\t%?p\tlastdata\t%?p\n",
770 		    sctp.sctp_current, sctp.sctp_lastdata);
771 	}
772 
773 	if (opts & MDB_SCTP_SHOW_OUT) {
774 		mdb_printf("%<b>Outbound Data%</b>\n");
775 		mdb_printf("xmit_head\t%?p\txmit_tail\t%?p\n",
776 		    sctp.sctp_xmit_head, sctp.sctp_xmit_tail);
777 		mdb_printf("xmit_unsent\t%?p\txmit_unsent_tail%?p\n",
778 		    sctp.sctp_xmit_unsent, sctp.sctp_xmit_unsent_tail);
779 		mdb_printf("xmit_unacked\t%?p\n", sctp.sctp_xmit_unacked);
780 		mdb_printf("unacked\t\t%?u\tunsent\t\t%?ld\n",
781 		    sctp.sctp_unacked, sctp.sctp_unsent);
782 		mdb_printf("ltsn\t\t%?x\tlastack_rxd\t%?x\n",
783 		    sctp.sctp_ltsn, sctp.sctp_lastack_rxd);
784 		mdb_printf("recovery_tsn\t%?x\tadv_pap\t\t%?x\n",
785 		    sctp.sctp_recovery_tsn, sctp.sctp_adv_pap);
786 		mdb_printf("num_ostr\t%?hu\tostrcntrs\t%?p\n",
787 		    sctp.sctp_num_ostr, sctp.sctp_ostrcntrs);
788 		mdb_printf("pad_mp\t\t%?p\n", sctp.sctp_pad_mp);
789 
790 		mdb_printf("%<b>Default Send Parameters%</b>\n");
791 		mdb_printf("def_stream\t%?u\tdef_flags\t%?x\n",
792 		    sctp.sctp_def_stream, sctp.sctp_def_flags);
793 		mdb_printf("def_ppid\t%?x\tdef_context\t%?x\n",
794 		    sctp.sctp_def_ppid, sctp.sctp_def_context);
795 		mdb_printf("def_timetolive\t%?u\n",
796 		    sctp.sctp_def_timetolive);
797 	}
798 
799 	if (opts & MDB_SCTP_SHOW_IN) {
800 		mdb_printf("%<b>Inbound Data%</b>\n");
801 		mdb_printf("sack_info\t%?p\tsack_gaps\t%?d\n",
802 		    sctp.sctp_sack_info, sctp.sctp_sack_gaps);
803 		dump_sack_info((uintptr_t)sctp.sctp_sack_info);
804 		mdb_printf("ftsn\t\t%?x\tlastacked\t%?x\n",
805 		    sctp.sctp_ftsn, sctp.sctp_lastacked);
806 		mdb_printf("istr_nmsgs\t%?d\tsack_toggle\t%?d\n",
807 		    sctp.sctp_istr_nmsgs, sctp.sctp_sack_toggle);
808 		mdb_printf("ack_mp\t\t%?p\n", sctp.sctp_ack_mp);
809 		mdb_printf("num_istr\t%?hu\tinstr\t\t%?p\n",
810 		    sctp.sctp_num_istr, sctp.sctp_instr);
811 		mdb_printf("unord_reass\t%?p\n", sctp.sctp_uo_frags);
812 	}
813 
814 	if (opts & MDB_SCTP_SHOW_RTT) {
815 		mdb_printf("%<b>RTT Tracking%</b>\n");
816 		mdb_printf("rtt_tsn\t\t%?x\tout_time\t%?ld\n",
817 		    sctp.sctp_rtt_tsn, sctp.sctp_out_time);
818 	}
819 
820 	if (opts & MDB_SCTP_SHOW_FLOW) {
821 		mdb_printf("%<b>Flow Control%</b>\n");
822 		mdb_printf("txmit_hiwater\t%?d\n"
823 		    "xmit_lowater\t%?d\tfrwnd\t\t%?u\n"
824 		    "rwnd\t\t%?u\tinitial rwnd\t%?u\n"
825 		    "rxqueued\t%?u\tcwnd_max\t%?u\n", sctp.sctp_xmit_hiwater,
826 		    sctp.sctp_xmit_lowater, sctp.sctp_frwnd,
827 		    sctp.sctp_rwnd, sctp.sctp_irwnd, sctp.sctp_rxqueued,
828 		    sctp.sctp_cwnd_max);
829 	}
830 
831 	if (opts & MDB_SCTP_SHOW_HDR) {
832 		mdb_printf("%<b>Composite Headers%</b>\n");
833 		mdb_printf("iphc\t\t%?p\tiphc6\t\t%?p\n"
834 		    "iphc_len\t%?d\tiphc6_len\t%?d\n"
835 		    "hdr_len\t\t%?d\thdr6_len\t%?d\n"
836 		    "ipha\t\t%?p\tip6h\t\t%?p\n"
837 		    "ip_hdr_len\t%?d\tip_hdr6_len\t%?d\n"
838 		    "sctph\t\t%?p\tsctph6\t\t%?p\n"
839 		    "lvtag\t\t%?x\tfvtag\t\t%?x\n", sctp.sctp_iphc,
840 		    sctp.sctp_iphc6, sctp.sctp_iphc_len,
841 		    sctp.sctp_iphc6_len, sctp.sctp_hdr_len,
842 		    sctp.sctp_hdr6_len, sctp.sctp_ipha, sctp.sctp_ip6h,
843 		    sctp.sctp_ip_hdr_len, sctp.sctp_ip_hdr6_len,
844 		    sctp.sctp_sctph, sctp.sctp_sctph6, sctp.sctp_lvtag,
845 		    sctp.sctp_fvtag);
846 	}
847 
848 	if (opts & MDB_SCTP_SHOW_PMTUD) {
849 		mdb_printf("%<b>PMTUd%</b>\n");
850 		mdb_printf("last_mtu_probe\t%?ld\tmtu_probe_intvl\t%?ld\n"
851 		    "mss\t\t%?u\n",
852 		    sctp.sctp_last_mtu_probe, sctp.sctp_mtu_probe_intvl,
853 		    sctp.sctp_mss);
854 	}
855 
856 	if (opts & MDB_SCTP_SHOW_RXT) {
857 		mdb_printf("%<b>Retransmit Info%</b>\n");
858 		mdb_printf("cookie_mp\t%?p\tstrikes\t\t%?d\n"
859 		    "max_init_rxt\t%?d\tpa_max_rxt\t%?d\n"
860 		    "pp_max_rxt\t%?d\trto_max\t\t%?u\n"
861 		    "rto_min\t\t%?u\trto_initial\t%?u\n"
862 		    "init_rto_max\t%?u\n"
863 		    "rxt_nxttsn\t%?u\trxt_maxtsn\t%?u\n", sctp.sctp_cookie_mp,
864 		    sctp.sctp_strikes, sctp.sctp_max_init_rxt,
865 		    sctp.sctp_pa_max_rxt, sctp.sctp_pp_max_rxt,
866 		    sctp.sctp_rto_max, sctp.sctp_rto_min,
867 		    sctp.sctp_rto_initial, sctp.sctp_init_rto_max,
868 		    sctp.sctp_rxt_nxttsn, sctp.sctp_rxt_maxtsn);
869 	}
870 
871 	if (opts & MDB_SCTP_SHOW_CONN) {
872 		mdb_printf("%<b>Connection State%</b>\n");
873 		mdb_printf("last_secret_update%?ld\n",
874 		    sctp.sctp_last_secret_update);
875 
876 		mdb_printf("secret\t\t");
877 		for (i = 0; i < SCTP_SECRET_LEN; i++) {
878 			if (i % 2 == 0)
879 				mdb_printf("0x%02x", sctp.sctp_secret[i]);
880 			else
881 				mdb_printf("%02x ", sctp.sctp_secret[i]);
882 		}
883 		mdb_printf("\n");
884 		mdb_printf("old_secret\t");
885 		for (i = 0; i < SCTP_SECRET_LEN; i++) {
886 			if (i % 2 == 0)
887 				mdb_printf("0x%02x", sctp.sctp_old_secret[i]);
888 			else
889 				mdb_printf("%02x ", sctp.sctp_old_secret[i]);
890 		}
891 		mdb_printf("\n");
892 	}
893 
894 	if (opts & MDB_SCTP_SHOW_STATS) {
895 		mdb_printf("%<b>Stats Counters%</b>\n");
896 		mdb_printf("opkts\t\t%?llu\tobchunks\t%?llu\n"
897 		    "odchunks\t%?llu\toudchunks\t%?llu\n"
898 		    "rxtchunks\t%?llu\tT1expire\t%?lu\n"
899 		    "T2expire\t%?lu\tT3expire\t%?lu\n"
900 		    "msgcount\t%?llu\tprsctpdrop\t%?llu\n"
901 		    "AssocStartTime\t%?lu\n",
902 		    sctp.sctp_opkts, sctp.sctp_obchunks,
903 		    sctp.sctp_odchunks, sctp.sctp_oudchunks,
904 		    sctp.sctp_rxtchunks, sctp.sctp_T1expire,
905 		    sctp.sctp_T2expire, sctp.sctp_T3expire,
906 		    sctp.sctp_msgcount, sctp.sctp_prsctpdrop,
907 		    sctp.sctp_assoc_start_time);
908 		mdb_printf("ipkts\t\t%?llu\tibchunks\t%?llu\n"
909 		    "idchunks\t%?llu\tiudchunks\t%?llu\n"
910 		    "fragdmsgs\t%?llu\treassmsgs\t%?llu\n",
911 		    sctp.sctp_ipkts, sctp.sctp_ibchunks,
912 		    sctp.sctp_idchunks, sctp.sctp_iudchunks,
913 		    sctp.sctp_fragdmsgs, sctp.sctp_reassmsgs);
914 	}
915 
916 	if (opts & MDB_SCTP_SHOW_HASH) {
917 		mdb_printf("%<b>Hash Tables%</b>\n");
918 		mdb_printf("conn_hash_next\t%?p\t", sctp.sctp_conn_hash_next);
919 		mdb_printf("conn_hash_prev\t%?p\n", sctp.sctp_conn_hash_prev);
920 
921 		mdb_printf("listen_hash_next%?p\t",
922 		    sctp.sctp_listen_hash_next);
923 		mdb_printf("listen_hash_prev%?p\n",
924 		    sctp.sctp_listen_hash_prev);
925 		mdb_nhconvert(&lport, &sctp.sctp_lport, sizeof (lport));
926 		mdb_printf("[ listen_hash bucket\t%?d ]\n",
927 		    SCTP_LISTEN_HASH(lport));
928 
929 		mdb_printf("conn_tfp\t%?p\t", sctp.sctp_conn_tfp);
930 		mdb_printf("listen_tfp\t%?p\n", sctp.sctp_listen_tfp);
931 
932 		mdb_printf("bind_hash\t%?p\tptpbhn\t\t%?p\n",
933 		    sctp.sctp_bind_hash, sctp.sctp_ptpbhn);
934 		mdb_printf("bind_lockp\t%?p\n",
935 		    sctp.sctp_bind_lockp);
936 		mdb_printf("[ bind_hash bucket\t%?d ]\n",
937 		    SCTP_BIND_HASH(lport));
938 	}
939 
940 	if (opts & MDB_SCTP_SHOW_CLOSE) {
941 		mdb_printf("%<b>Cleanup / Close%</b>\n");
942 		mdb_printf("shutdown_faddr\t%?p\tclient_errno\t%?d\n"
943 		    "lingertime\t%?d\trefcnt\t\t%?hu\n",
944 		    sctp.sctp_shutdown_faddr, sctp.sctp_client_errno,
945 		    sctp.sctp_lingertime, sctp.sctp_refcnt);
946 	}
947 
948 	if (opts & MDB_SCTP_SHOW_MISC) {
949 		mdb_printf("%<b>Miscellaneous%</b>\n");
950 		mdb_printf("bound_if\t%?u\theartbeat_mp\t%?p\n"
951 		    "family\t\t%?u\tipversion\t%?hu\n"
952 		    "hb_interval\t%?u\tautoclose\t%?d\n"
953 		    "active\t\t%?ld\ttx_adaption_code%?x\n"
954 		    "rx_adaption_code%?x\ttimer_mp\t%?p\n"
955 		    "partial_delivery_point\t%?d\n",
956 		    sctp.sctp_bound_if, sctp.sctp_heartbeat_mp,
957 		    sctp.sctp_family, sctp.sctp_ipversion,
958 		    sctp.sctp_hb_interval, sctp.sctp_autoclose,
959 		    sctp.sctp_active, sctp.sctp_tx_adaption_code,
960 		    sctp.sctp_rx_adaption_code, sctp.sctp_timer_mp,
961 		    sctp.sctp_pd_point);
962 	}
963 
964 	if (opts & MDB_SCTP_SHOW_EXT) {
965 		mdb_printf("%<b>Extensions and Reliable Ctl Chunks%</b>\n");
966 		mdb_printf("cxmit_list\t%?p\tlcsn\t\t%?x\n"
967 		    "fcsn\t\t%?x\n", sctp.sctp_cxmit_list, sctp.sctp_lcsn,
968 		    sctp.sctp_fcsn);
969 	}
970 
971 	if (opts & MDB_SCTP_SHOW_FLAGS) {
972 		mdb_printf("%<b>Flags%</b>\n");
973 		show_sctp_flags(&sctp);
974 	}
975 
976 	return (DCMD_OK);
977 }
978 
979 typedef struct fanout_walk_data {
980 	int index;
981 	int size;
982 	uintptr_t sctp;
983 	sctp_tf_t *fanout;
984 	uintptr_t (*getnext)(sctp_t *);
985 } fanout_walk_data_t;
986 
987 typedef struct fanout_init {
988 	const char *nested_walker_name;
989 	size_t offset;	/* for what used to be a symbol */
990 	int (*getsize)(sctp_stack_t *);
991 	uintptr_t (*getnext)(sctp_t *);
992 } fanout_init_t;
993 
994 static uintptr_t
995 listen_next(sctp_t *sctp)
996 {
997 	return ((uintptr_t)sctp->sctp_listen_hash_next);
998 }
999 
1000 /* ARGSUSED */
1001 static int
1002 listen_size(sctp_stack_t *sctps)
1003 {
1004 	return (SCTP_LISTEN_FANOUT_SIZE);
1005 }
1006 
1007 static uintptr_t
1008 conn_next(sctp_t *sctp)
1009 {
1010 	return ((uintptr_t)sctp->sctp_conn_hash_next);
1011 }
1012 
1013 static int
1014 conn_size(sctp_stack_t *sctps)
1015 {
1016 	int size;
1017 	uintptr_t kaddr;
1018 
1019 	kaddr = (uintptr_t)&sctps->sctps_conn_hash_size;
1020 
1021 	if (mdb_vread(&size, sizeof (size), kaddr) == -1) {
1022 		mdb_warn("can't read 'sctps_conn_hash_size' at %p", kaddr);
1023 		return (1);
1024 	}
1025 	return (size);
1026 }
1027 
1028 static uintptr_t
1029 bind_next(sctp_t *sctp)
1030 {
1031 	return ((uintptr_t)sctp->sctp_bind_hash);
1032 }
1033 
1034 /* ARGSUSED */
1035 static int
1036 bind_size(sctp_stack_t *sctps)
1037 {
1038 	return (SCTP_BIND_FANOUT_SIZE);
1039 }
1040 
1041 static intptr_t
1042 find_next_hash_item(fanout_walk_data_t *fw)
1043 {
1044 	sctp_tf_t tf;
1045 	sctp_t sctp;
1046 
1047 	/* first try to continue down the hash chain */
1048 	if (fw->sctp != NULL) {
1049 		/* try to get next in hash chain */
1050 		if (mdb_vread(&sctp, sizeof (sctp), fw->sctp) == -1) {
1051 			mdb_warn("failed to read sctp at %p", fw->sctp);
1052 			return (NULL);
1053 		}
1054 		fw->sctp = fw->getnext(&sctp);
1055 		if (fw->sctp != NULL)
1056 			return (fw->sctp);
1057 		else
1058 			/* end of chain; go to next bucket */
1059 			fw->index++;
1060 	}
1061 
1062 	/* find a new hash chain, traversing the buckets */
1063 	for (; fw->index < fw->size; fw->index++) {
1064 		/* read the current hash line for an sctp */
1065 		if (mdb_vread(&tf, sizeof (tf),
1066 		    (uintptr_t)(fw->fanout + fw->index)) == -1) {
1067 			mdb_warn("failed to read tf at %p",
1068 			    fw->fanout + fw->index);
1069 			return (NULL);
1070 		}
1071 		if (tf.tf_sctp != NULL) {
1072 			/* start of a new chain */
1073 			fw->sctp = (uintptr_t)tf.tf_sctp;
1074 			return (fw->sctp);
1075 		}
1076 	}
1077 	return (NULL);
1078 }
1079 
1080 static int
1081 fanout_stack_walk_init(mdb_walk_state_t *wsp)
1082 {
1083 	fanout_walk_data_t *lw;
1084 	fanout_init_t *fi = wsp->walk_arg;
1085 	sctp_stack_t *sctps = (sctp_stack_t *)wsp->walk_addr;
1086 	uintptr_t kaddr;
1087 
1088 	if (mdb_vread(&kaddr, sizeof (kaddr),
1089 	    wsp->walk_addr + fi->offset) == -1) {
1090 		mdb_warn("can't read sctp fanout at %p",
1091 		    wsp->walk_addr + fi->offset);
1092 		return (WALK_ERR);
1093 	}
1094 
1095 	lw = mdb_alloc(sizeof (*lw), UM_SLEEP);
1096 	lw->index = 0;
1097 	lw->size = fi->getsize(sctps);
1098 	lw->sctp = NULL;
1099 	lw->fanout = (sctp_tf_t *)kaddr;
1100 	lw->getnext = fi->getnext;
1101 
1102 	if ((wsp->walk_addr = find_next_hash_item(lw)) == NULL) {
1103 		return (WALK_DONE);
1104 	}
1105 	wsp->walk_data = lw;
1106 	return (WALK_NEXT);
1107 }
1108 
1109 static int
1110 fanout_stack_walk_step(mdb_walk_state_t *wsp)
1111 {
1112 	fanout_walk_data_t *fw = wsp->walk_data;
1113 	uintptr_t addr = wsp->walk_addr;
1114 	sctp_t sctp;
1115 	int status;
1116 
1117 	if (mdb_vread(&sctp, sizeof (sctp), addr) == -1) {
1118 		mdb_warn("failed to read sctp at %p", addr);
1119 		return (WALK_DONE);
1120 	}
1121 
1122 	status = wsp->walk_callback(addr, &sctp, wsp->walk_cbdata);
1123 	if (status != WALK_NEXT)
1124 		return (status);
1125 
1126 	if ((wsp->walk_addr = find_next_hash_item(fw)) == NULL)
1127 		return (WALK_DONE);
1128 
1129 	return (WALK_NEXT);
1130 }
1131 
1132 static void
1133 fanout_stack_walk_fini(mdb_walk_state_t *wsp)
1134 {
1135 	fanout_walk_data_t *fw = wsp->walk_data;
1136 
1137 	mdb_free(fw, sizeof (*fw));
1138 }
1139 
1140 int
1141 fanout_walk_init(mdb_walk_state_t *wsp)
1142 {
1143 	if (mdb_layered_walk("sctp_stacks", wsp) == -1) {
1144 		mdb_warn("can't walk 'sctp_stacks'");
1145 		return (WALK_ERR);
1146 	}
1147 
1148 	return (WALK_NEXT);
1149 }
1150 
1151 int
1152 fanout_walk_step(mdb_walk_state_t *wsp)
1153 {
1154 	fanout_init_t *fi = wsp->walk_arg;
1155 
1156 	if (mdb_pwalk(fi->nested_walker_name, wsp->walk_callback,
1157 	    wsp->walk_cbdata, wsp->walk_addr) == -1) {
1158 		mdb_warn("couldn't walk '%s'for address %p",
1159 		    fi->nested_walker_name, wsp->walk_addr);
1160 		return (WALK_ERR);
1161 	}
1162 	return (WALK_NEXT);
1163 }
1164 
1165 int
1166 sctps_walk_init(mdb_walk_state_t *wsp)
1167 {
1168 
1169 	if (mdb_layered_walk("sctp_stacks", wsp) == -1) {
1170 		mdb_warn("can't walk 'sctp_stacks'");
1171 		return (WALK_ERR);
1172 	}
1173 
1174 	return (WALK_NEXT);
1175 }
1176 
1177 int
1178 sctps_walk_step(mdb_walk_state_t *wsp)
1179 {
1180 	uintptr_t kaddr;
1181 
1182 	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_g_list);
1183 	if (mdb_pwalk("list", wsp->walk_callback,
1184 	    wsp->walk_cbdata, kaddr) == -1) {
1185 		mdb_warn("couldn't walk 'list' for address %p", kaddr);
1186 		return (WALK_ERR);
1187 	}
1188 	return (WALK_NEXT);
1189 }
1190 
1191 static int
1192 sctp_walk_faddr_init(mdb_walk_state_t *wsp)
1193 {
1194 	sctp_t sctp;
1195 
1196 	if (wsp->walk_addr == NULL)
1197 		return (WALK_ERR);
1198 
1199 	if (mdb_vread(&sctp, sizeof (sctp), wsp->walk_addr) == -1) {
1200 		mdb_warn("failed to read sctp at %p", wsp->walk_addr);
1201 		return (WALK_ERR);
1202 	}
1203 	if ((wsp->walk_addr = (uintptr_t)sctp.sctp_faddrs) != NULL)
1204 		return (WALK_NEXT);
1205 	else
1206 		return (WALK_DONE);
1207 }
1208 
1209 static int
1210 sctp_walk_faddr_step(mdb_walk_state_t *wsp)
1211 {
1212 	uintptr_t faddr_ptr = wsp->walk_addr;
1213 	sctp_faddr_t sctp_faddr;
1214 	int status;
1215 
1216 	if (mdb_vread(&sctp_faddr, sizeof (sctp_faddr_t), faddr_ptr) == -1) {
1217 		mdb_warn("failed to read sctp_faddr_t at %p", faddr_ptr);
1218 		return (WALK_ERR);
1219 	}
1220 	status = wsp->walk_callback(faddr_ptr, &sctp_faddr, wsp->walk_cbdata);
1221 	if (status != WALK_NEXT)
1222 		return (status);
1223 	if ((faddr_ptr = (uintptr_t)sctp_faddr.next) == NULL) {
1224 		return (WALK_DONE);
1225 	} else {
1226 		wsp->walk_addr = faddr_ptr;
1227 		return (WALK_NEXT);
1228 	}
1229 }
1230 
1231 /*
1232  * Helper structure for sctp_walk_saddr.  It stores the sctp_t being walked,
1233  * the current index to the sctp_saddrs[], and the current count of the
1234  * sctp_saddr_ipif_t list.
1235  */
1236 typedef struct {
1237 	sctp_t	sctp;
1238 	int	hash_index;
1239 	int	cur_cnt;
1240 } saddr_walk_t;
1241 
1242 static int
1243 sctp_walk_saddr_init(mdb_walk_state_t *wsp)
1244 {
1245 	sctp_t *sctp;
1246 	int i;
1247 	saddr_walk_t *swalker;
1248 
1249 	if (wsp->walk_addr == NULL)
1250 		return (WALK_ERR);
1251 
1252 	swalker = mdb_alloc(sizeof (saddr_walk_t), UM_SLEEP);
1253 	sctp = &swalker->sctp;
1254 	if (mdb_vread(sctp, sizeof (sctp_t), wsp->walk_addr) == -1) {
1255 		mdb_warn("failed to read sctp at %p", wsp->walk_addr);
1256 		mdb_free(swalker, sizeof (saddr_walk_t));
1257 		return (WALK_ERR);
1258 	}
1259 
1260 	/* Find the first source address. */
1261 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1262 		if (sctp->sctp_saddrs[i].ipif_count > 0) {
1263 			list_t *addr_list;
1264 
1265 			addr_list = &sctp->sctp_saddrs[i].sctp_ipif_list;
1266 			wsp->walk_addr = (uintptr_t)list_object(addr_list,
1267 			    addr_list->list_head.list_next);
1268 
1269 			/* Recode the current info */
1270 			swalker->hash_index = i;
1271 			swalker->cur_cnt = 1;
1272 			wsp->walk_data = swalker;
1273 
1274 			return (WALK_NEXT);
1275 		}
1276 	}
1277 	return (WALK_DONE);
1278 }
1279 
1280 static int
1281 sctp_walk_saddr_step(mdb_walk_state_t *wsp)
1282 {
1283 	uintptr_t saddr_ptr = wsp->walk_addr;
1284 	sctp_saddr_ipif_t saddr;
1285 	saddr_walk_t *swalker;
1286 	sctp_t *sctp;
1287 	int status;
1288 	int i, j;
1289 
1290 	if (mdb_vread(&saddr, sizeof (sctp_saddr_ipif_t), saddr_ptr) == -1) {
1291 		mdb_warn("failed to read sctp_saddr_ipif_t at %p", saddr_ptr);
1292 		return (WALK_ERR);
1293 	}
1294 	status = wsp->walk_callback(saddr_ptr, &saddr, wsp->walk_cbdata);
1295 	if (status != WALK_NEXT)
1296 		return (status);
1297 
1298 	swalker = (saddr_walk_t *)wsp->walk_data;
1299 	sctp = &swalker->sctp;
1300 	i = swalker->hash_index;
1301 	j = swalker->cur_cnt;
1302 
1303 	/*
1304 	 * If there is still a source address in the current list, return it.
1305 	 * Otherwise, go to the next list in the sctp_saddrs[].
1306 	 */
1307 	if (j++ < sctp->sctp_saddrs[i].ipif_count) {
1308 		wsp->walk_addr = (uintptr_t)saddr.saddr_ipif.list_next;
1309 		swalker->cur_cnt = j;
1310 		return (WALK_NEXT);
1311 	} else {
1312 		list_t *lst;
1313 
1314 		for (i = i + 1; i < SCTP_IPIF_HASH; i++) {
1315 			if (sctp->sctp_saddrs[i].ipif_count > 0) {
1316 				lst = &sctp->sctp_saddrs[i].sctp_ipif_list;
1317 				wsp->walk_addr = (uintptr_t)list_object(
1318 				    lst, lst->list_head.list_next);
1319 				swalker->hash_index = i;
1320 				swalker->cur_cnt = 1;
1321 				return (WALK_NEXT);
1322 			}
1323 		}
1324 	}
1325 	return (WALK_DONE);
1326 }
1327 
1328 static void
1329 sctp_walk_saddr_fini(mdb_walk_state_t *wsp)
1330 {
1331 	saddr_walk_t *swalker = (saddr_walk_t *)wsp->walk_data;
1332 
1333 	mdb_free(swalker, sizeof (saddr_walk_t));
1334 }
1335 
1336 
1337 typedef struct ill_walk_data {
1338 	sctp_ill_hash_t ills[SCTP_ILL_HASH];
1339 	uint32_t	count;
1340 } ill_walk_data_t;
1341 
1342 typedef struct ipuf_walk_data {
1343 	sctp_ipif_hash_t ipifs[SCTP_IPIF_HASH];
1344 	uint32_t	count;
1345 } ipif_walk_data_t;
1346 
1347 
1348 int
1349 sctp_ill_walk_init(mdb_walk_state_t *wsp)
1350 {
1351 	if (mdb_layered_walk("sctp_stacks", wsp) == -1) {
1352 		mdb_warn("can't walk 'sctp_stacks'");
1353 		return (WALK_ERR);
1354 	}
1355 
1356 	return (WALK_NEXT);
1357 }
1358 
1359 int
1360 sctp_ill_walk_step(mdb_walk_state_t *wsp)
1361 {
1362 	if (mdb_pwalk("sctp_stack_walk_ill", wsp->walk_callback,
1363 	    wsp->walk_cbdata, wsp->walk_addr) == -1) {
1364 		mdb_warn("couldn't walk 'sctp_stack_walk_ill' for addr %p",
1365 		    wsp->walk_addr);
1366 		return (WALK_ERR);
1367 	}
1368 	return (WALK_NEXT);
1369 }
1370 
1371 /*
1372  * wsp->walk_addr is the address of sctps_ill_list
1373  */
1374 static int
1375 sctp_stack_ill_walk_init(mdb_walk_state_t *wsp)
1376 {
1377 	ill_walk_data_t iw;
1378 	intptr_t i;
1379 	uintptr_t kaddr, uaddr;
1380 	size_t offset;
1381 
1382 	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_ills_count);
1383 	if (mdb_vread(&iw.count, sizeof (iw.count), kaddr) == -1) {
1384 		mdb_warn("can't read sctps_ills_count at %p", kaddr);
1385 		return (WALK_ERR);
1386 	}
1387 	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_g_ills);
1388 
1389 	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
1390 		mdb_warn("can't read scpts_g_ills %p", kaddr);
1391 		return (WALK_ERR);
1392 	}
1393 	if (mdb_vread(&iw.ills, sizeof (iw.ills), kaddr) == -1) {
1394 		mdb_warn("failed to read 'sctps_g_ills'");
1395 		return (NULL);
1396 	}
1397 
1398 	/* Find the first ill. */
1399 	for (i = 0; i < SCTP_ILL_HASH; i++) {
1400 		if (iw.ills[i].ill_count > 0) {
1401 			uaddr = (uintptr_t)&iw.ills[i].sctp_ill_list;
1402 			offset = uaddr - (uintptr_t)&iw.ills;
1403 			if (mdb_pwalk("list", wsp->walk_callback,
1404 			    wsp->walk_cbdata, kaddr+offset) == -1) {
1405 				mdb_warn("couldn't walk 'list' for address %p",
1406 				    kaddr);
1407 				return (WALK_ERR);
1408 			}
1409 		}
1410 	}
1411 	return (WALK_DONE);
1412 }
1413 
1414 static int
1415 sctp_stack_ill_walk_step(mdb_walk_state_t *wsp)
1416 {
1417 	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
1418 	    wsp->walk_cbdata));
1419 }
1420 
1421 int
1422 sctp_ipif_walk_init(mdb_walk_state_t *wsp)
1423 {
1424 	if (mdb_layered_walk("sctp_stacks", wsp) == -1) {
1425 		mdb_warn("can't walk 'sctp_stacks'");
1426 		return (WALK_ERR);
1427 	}
1428 	return (WALK_NEXT);
1429 }
1430 
1431 int
1432 sctp_ipif_walk_step(mdb_walk_state_t *wsp)
1433 {
1434 	if (mdb_pwalk("sctp_stack_walk_ipif", wsp->walk_callback,
1435 	    wsp->walk_cbdata, wsp->walk_addr) == -1) {
1436 		mdb_warn("couldn't walk 'sctp_stack_walk_ipif' for addr %p",
1437 		    wsp->walk_addr);
1438 		return (WALK_ERR);
1439 	}
1440 	return (WALK_NEXT);
1441 }
1442 
1443 /*
1444  * wsp->walk_addr is the address of sctps_ipif_list
1445  */
1446 static int
1447 sctp_stack_ipif_walk_init(mdb_walk_state_t *wsp)
1448 {
1449 	ipif_walk_data_t iw;
1450 	intptr_t i;
1451 	uintptr_t kaddr, uaddr;
1452 	size_t offset;
1453 
1454 	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_g_ipifs_count);
1455 	if (mdb_vread(&iw.count, sizeof (iw.count), kaddr) == -1) {
1456 		mdb_warn("can't read sctps_g_ipifs_count at %p", kaddr);
1457 		return (WALK_ERR);
1458 	}
1459 	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_g_ipifs);
1460 
1461 	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
1462 		mdb_warn("can't read scpts_g_ipifs %p", kaddr);
1463 		return (WALK_ERR);
1464 	}
1465 	if (mdb_vread(&iw.ipifs, sizeof (iw.ipifs), kaddr) == -1) {
1466 		mdb_warn("failed to read 'sctps_g_ipifs'");
1467 		return (NULL);
1468 	}
1469 
1470 	/* Find the first ipif. */
1471 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1472 		if (iw.ipifs[i].ipif_count > 0) {
1473 			uaddr = (uintptr_t)&iw.ipifs[i].sctp_ipif_list;
1474 			offset = uaddr - (uintptr_t)&iw.ipifs;
1475 			if (mdb_pwalk("list", wsp->walk_callback,
1476 			    wsp->walk_cbdata, kaddr+offset) == -1) {
1477 				mdb_warn("couldn't walk 'list' for address %p",
1478 				    kaddr);
1479 				return (WALK_ERR);
1480 			}
1481 		}
1482 	}
1483 	return (WALK_DONE);
1484 }
1485 
1486 static int
1487 sctp_stack_ipif_walk_step(mdb_walk_state_t *wsp)
1488 {
1489 	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
1490 	    wsp->walk_cbdata));
1491 }
1492 
1493 static void
1494 sctp_help(void)
1495 {
1496 	mdb_printf("Print information for a given SCTP sctp_t\n\n");
1497 	mdb_printf("Options:\n");
1498 	mdb_printf("\t-a\t All the information\n");
1499 	mdb_printf("\t-f\t Flags\n");
1500 	mdb_printf("\t-h\t Hash Tables\n");
1501 	mdb_printf("\t-o\t Outbound Data\n");
1502 	mdb_printf("\t-i\t Inbound Data\n");
1503 	mdb_printf("\t-m\t Miscellaneous Information\n");
1504 	mdb_printf("\t-r\t RTT Tracking\n");
1505 	mdb_printf("\t-S\t Stats Counters\n");
1506 	mdb_printf("\t-F\t Flow Control\n");
1507 	mdb_printf("\t-H\t Composite Headers\n");
1508 	mdb_printf("\t-p\t PMTUD\n");
1509 	mdb_printf("\t-R\t Retransmit Information\n");
1510 	mdb_printf("\t-C\t Connection State\n");
1511 	mdb_printf("\t-c\t Cleanup / Close\n");
1512 	mdb_printf("\t-e\t Extensions and Reliable Control Chunks\n");
1513 	mdb_printf("\t-d\t Local and Peer addresses\n");
1514 	mdb_printf("\t-P\t Peer addresses\n");
1515 }
1516 static const mdb_dcmd_t dcmds[] = {
1517 	{ "sctp", ":[-afhoimrSFHpRCcedP]",
1518 	    "display sctp control structure", sctp, sctp_help },
1519 	{ "sctp_set", ":", "display a SCTP set", sctp_set },
1520 	{ "sctp_faddr", ":", "display a faddr", sctp_faddr },
1521 	{ "sctp_istr_msgs", ":", "display msg list on an instream",
1522 	    sctp_istr_msgs },
1523 	{ "sctp_mdata_chunk", ":", "display a data chunk in an mblk",
1524 	    sctp_mdata_chunk },
1525 	{ "sctp_xmit_list", ":", "display sctp xmit lists", sctp_xmit_list },
1526 	{ "sctp_instr", ":", "display instr", sctp_instr },
1527 	{ "sctp_reass_list", ":", "display reass list", sctp_reass_list },
1528 	{ "sctp_uo_reass_list", ":", "display un-ordered reass list",
1529 	    sctp_uo_reass_list },
1530 	{ NULL }
1531 };
1532 
1533 static const fanout_init_t listen_fanout_init = {
1534 	"sctp_stack_listen_fanout", OFFSETOF(sctp_stack_t, sctps_listen_fanout),
1535 	listen_size, listen_next
1536 };
1537 
1538 static const fanout_init_t conn_fanout_init = {
1539 	"sctp_stack_conn_fanout",  OFFSETOF(sctp_stack_t, sctps_conn_fanout),
1540 	conn_size, conn_next
1541 };
1542 
1543 static const fanout_init_t bind_fanout_init = {
1544 	"sctp_stack_bind_fanout", OFFSETOF(sctp_stack_t, sctps_bind_fanout),
1545 	bind_size, bind_next
1546 };
1547 
1548 static const mdb_walker_t walkers[] = {
1549 	{ "sctps", "walk the full chain of sctps for all stacks",
1550 	    sctps_walk_init, sctps_walk_step, NULL },
1551 	{ "sctp_listen_fanout", "walk the sctp listen fanout for all stacks",
1552 	    fanout_walk_init, fanout_walk_step, NULL,
1553 	    (void *)&listen_fanout_init },
1554 	{ "sctp_conn_fanout", "walk the sctp conn fanout for all stacks",
1555 	    fanout_walk_init, fanout_walk_step, NULL,
1556 	    (void *)&conn_fanout_init },
1557 	{ "sctp_bind_fanout", "walk the sctp bind fanout for all stacks",
1558 	    fanout_walk_init, fanout_walk_step, NULL,
1559 	    (void *)&bind_fanout_init },
1560 	{ "sctp_stack_listen_fanout",
1561 	    "walk the sctp listen fanout for one stack",
1562 	    fanout_stack_walk_init, fanout_stack_walk_step,
1563 	    fanout_stack_walk_fini,
1564 	    (void *)&listen_fanout_init },
1565 	{ "sctp_stack_conn_fanout", "walk the sctp conn fanout for one stack",
1566 	    fanout_stack_walk_init, fanout_stack_walk_step,
1567 	    fanout_stack_walk_fini,
1568 	    (void *)&conn_fanout_init },
1569 	{ "sctp_stack_bind_fanout", "walk the sctp bind fanoutfor one stack",
1570 	    fanout_stack_walk_init, fanout_stack_walk_step,
1571 	    fanout_stack_walk_fini,
1572 	    (void *)&bind_fanout_init },
1573 	{ "sctp_walk_faddr", "walk the peer address list of a given sctp_t",
1574 	    sctp_walk_faddr_init, sctp_walk_faddr_step, NULL },
1575 	{ "sctp_walk_saddr", "walk the local address list of a given sctp_t",
1576 	    sctp_walk_saddr_init, sctp_walk_saddr_step, sctp_walk_saddr_fini },
1577 	{ "sctp_walk_ill", "walk the sctp_g_ills list for all stacks",
1578 	    sctp_ill_walk_init, sctp_ill_walk_step, NULL },
1579 	{ "sctp_walk_ipif", "walk the sctp_g_ipif list for all stacks",
1580 		sctp_ipif_walk_init, sctp_ipif_walk_step, NULL },
1581 	{ "sctp_stack_walk_ill", "walk the sctp_g_ills list for one stack",
1582 		sctp_stack_ill_walk_init, sctp_stack_ill_walk_step, NULL },
1583 	{ "sctp_stack_walk_ipif", "walk the sctp_g_ipif list for one stack",
1584 		sctp_stack_ipif_walk_init, sctp_stack_ipif_walk_step, NULL },
1585 	{ "sctp_stacks", "walk all the sctp_stack_t",
1586 		sctp_stacks_walk_init, sctp_stacks_walk_step, NULL },
1587 	{ NULL }
1588 };
1589 
1590 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
1591 
1592 const mdb_modinfo_t *
1593 _mdb_init(void)
1594 {
1595 	return (&modinfo);
1596 }
1597