xref: /illumos-gate/usr/src/cmd/mdb/common/modules/sctp/sctp.c (revision 7f093707988cae175f34a000f899756d645fe088)
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\terr_chunks\t%?p\n",
789 		    sctp.sctp_pad_mp, sctp.sctp_err_chunks);
790 		mdb_printf("err_len\t\t%?u\n", sctp.sctp_err_len);
791 
792 		mdb_printf("%<b>Default Send Parameters%</b>\n");
793 		mdb_printf("def_stream\t%?u\tdef_flags\t%?x\n",
794 		    sctp.sctp_def_stream, sctp.sctp_def_flags);
795 		mdb_printf("def_ppid\t%?x\tdef_context\t%?x\n",
796 		    sctp.sctp_def_ppid, sctp.sctp_def_context);
797 		mdb_printf("def_timetolive\t%?u\n",
798 		    sctp.sctp_def_timetolive);
799 	}
800 
801 	if (opts & MDB_SCTP_SHOW_IN) {
802 		mdb_printf("%<b>Inbound Data%</b>\n");
803 		mdb_printf("sack_info\t%?p\tsack_gaps\t%?d\n",
804 		    sctp.sctp_sack_info, sctp.sctp_sack_gaps);
805 		dump_sack_info((uintptr_t)sctp.sctp_sack_info);
806 		mdb_printf("ftsn\t\t%?x\tlastacked\t%?x\n",
807 		    sctp.sctp_ftsn, sctp.sctp_lastacked);
808 		mdb_printf("istr_nmsgs\t%?d\tsack_toggle\t%?d\n",
809 		    sctp.sctp_istr_nmsgs, sctp.sctp_sack_toggle);
810 		mdb_printf("ack_mp\t\t%?p\n", sctp.sctp_ack_mp);
811 		mdb_printf("num_istr\t%?hu\tinstr\t\t%?p\n",
812 		    sctp.sctp_num_istr, sctp.sctp_instr);
813 		mdb_printf("unord_reass\t%?p\n", sctp.sctp_uo_frags);
814 	}
815 
816 	if (opts & MDB_SCTP_SHOW_RTT) {
817 		mdb_printf("%<b>RTT Tracking%</b>\n");
818 		mdb_printf("rtt_tsn\t\t%?x\tout_time\t%?ld\n",
819 		    sctp.sctp_rtt_tsn, sctp.sctp_out_time);
820 	}
821 
822 	if (opts & MDB_SCTP_SHOW_FLOW) {
823 		mdb_printf("%<b>Flow Control%</b>\n");
824 		mdb_printf("txmit_hiwater\t%?d\n"
825 		    "xmit_lowater\t%?d\tfrwnd\t\t%?u\n"
826 		    "rwnd\t\t%?u\tinitial rwnd\t%?u\n"
827 		    "rxqueued\t%?u\tcwnd_max\t%?u\n", sctp.sctp_xmit_hiwater,
828 		    sctp.sctp_xmit_lowater, sctp.sctp_frwnd,
829 		    sctp.sctp_rwnd, sctp.sctp_irwnd, sctp.sctp_rxqueued,
830 		    sctp.sctp_cwnd_max);
831 	}
832 
833 	if (opts & MDB_SCTP_SHOW_HDR) {
834 		mdb_printf("%<b>Composite Headers%</b>\n");
835 		mdb_printf("iphc\t\t%?p\tiphc6\t\t%?p\n"
836 		    "iphc_len\t%?d\tiphc6_len\t%?d\n"
837 		    "hdr_len\t\t%?d\thdr6_len\t%?d\n"
838 		    "ipha\t\t%?p\tip6h\t\t%?p\n"
839 		    "ip_hdr_len\t%?d\tip_hdr6_len\t%?d\n"
840 		    "sctph\t\t%?p\tsctph6\t\t%?p\n"
841 		    "lvtag\t\t%?x\tfvtag\t\t%?x\n", sctp.sctp_iphc,
842 		    sctp.sctp_iphc6, sctp.sctp_iphc_len,
843 		    sctp.sctp_iphc6_len, sctp.sctp_hdr_len,
844 		    sctp.sctp_hdr6_len, sctp.sctp_ipha, sctp.sctp_ip6h,
845 		    sctp.sctp_ip_hdr_len, sctp.sctp_ip_hdr6_len,
846 		    sctp.sctp_sctph, sctp.sctp_sctph6, sctp.sctp_lvtag,
847 		    sctp.sctp_fvtag);
848 	}
849 
850 	if (opts & MDB_SCTP_SHOW_PMTUD) {
851 		mdb_printf("%<b>PMTUd%</b>\n");
852 		mdb_printf("last_mtu_probe\t%?ld\tmtu_probe_intvl\t%?ld\n"
853 		    "mss\t\t%?u\n",
854 		    sctp.sctp_last_mtu_probe, sctp.sctp_mtu_probe_intvl,
855 		    sctp.sctp_mss);
856 	}
857 
858 	if (opts & MDB_SCTP_SHOW_RXT) {
859 		mdb_printf("%<b>Retransmit Info%</b>\n");
860 		mdb_printf("cookie_mp\t%?p\tstrikes\t\t%?d\n"
861 		    "max_init_rxt\t%?d\tpa_max_rxt\t%?d\n"
862 		    "pp_max_rxt\t%?d\trto_max\t\t%?u\n"
863 		    "rto_min\t\t%?u\trto_initial\t%?u\n"
864 		    "init_rto_max\t%?u\n"
865 		    "rxt_nxttsn\t%?u\trxt_maxtsn\t%?u\n", sctp.sctp_cookie_mp,
866 		    sctp.sctp_strikes, sctp.sctp_max_init_rxt,
867 		    sctp.sctp_pa_max_rxt, sctp.sctp_pp_max_rxt,
868 		    sctp.sctp_rto_max, sctp.sctp_rto_min,
869 		    sctp.sctp_rto_initial, sctp.sctp_init_rto_max,
870 		    sctp.sctp_rxt_nxttsn, sctp.sctp_rxt_maxtsn);
871 	}
872 
873 	if (opts & MDB_SCTP_SHOW_CONN) {
874 		mdb_printf("%<b>Connection State%</b>\n");
875 		mdb_printf("last_secret_update%?ld\n",
876 		    sctp.sctp_last_secret_update);
877 
878 		mdb_printf("secret\t\t");
879 		for (i = 0; i < SCTP_SECRET_LEN; i++) {
880 			if (i % 2 == 0)
881 				mdb_printf("0x%02x", sctp.sctp_secret[i]);
882 			else
883 				mdb_printf("%02x ", sctp.sctp_secret[i]);
884 		}
885 		mdb_printf("\n");
886 		mdb_printf("old_secret\t");
887 		for (i = 0; i < SCTP_SECRET_LEN; i++) {
888 			if (i % 2 == 0)
889 				mdb_printf("0x%02x", sctp.sctp_old_secret[i]);
890 			else
891 				mdb_printf("%02x ", sctp.sctp_old_secret[i]);
892 		}
893 		mdb_printf("\n");
894 	}
895 
896 	if (opts & MDB_SCTP_SHOW_STATS) {
897 		mdb_printf("%<b>Stats Counters%</b>\n");
898 		mdb_printf("opkts\t\t%?llu\tobchunks\t%?llu\n"
899 		    "odchunks\t%?llu\toudchunks\t%?llu\n"
900 		    "rxtchunks\t%?llu\tT1expire\t%?lu\n"
901 		    "T2expire\t%?lu\tT3expire\t%?lu\n"
902 		    "msgcount\t%?llu\tprsctpdrop\t%?llu\n"
903 		    "AssocStartTime\t%?lu\n",
904 		    sctp.sctp_opkts, sctp.sctp_obchunks,
905 		    sctp.sctp_odchunks, sctp.sctp_oudchunks,
906 		    sctp.sctp_rxtchunks, sctp.sctp_T1expire,
907 		    sctp.sctp_T2expire, sctp.sctp_T3expire,
908 		    sctp.sctp_msgcount, sctp.sctp_prsctpdrop,
909 		    sctp.sctp_assoc_start_time);
910 		mdb_printf("ipkts\t\t%?llu\tibchunks\t%?llu\n"
911 		    "idchunks\t%?llu\tiudchunks\t%?llu\n"
912 		    "fragdmsgs\t%?llu\treassmsgs\t%?llu\n",
913 		    sctp.sctp_ipkts, sctp.sctp_ibchunks,
914 		    sctp.sctp_idchunks, sctp.sctp_iudchunks,
915 		    sctp.sctp_fragdmsgs, sctp.sctp_reassmsgs);
916 	}
917 
918 	if (opts & MDB_SCTP_SHOW_HASH) {
919 		mdb_printf("%<b>Hash Tables%</b>\n");
920 		mdb_printf("conn_hash_next\t%?p\t", sctp.sctp_conn_hash_next);
921 		mdb_printf("conn_hash_prev\t%?p\n", sctp.sctp_conn_hash_prev);
922 
923 		mdb_printf("listen_hash_next%?p\t",
924 		    sctp.sctp_listen_hash_next);
925 		mdb_printf("listen_hash_prev%?p\n",
926 		    sctp.sctp_listen_hash_prev);
927 		mdb_nhconvert(&lport, &sctp.sctp_lport, sizeof (lport));
928 		mdb_printf("[ listen_hash bucket\t%?d ]\n",
929 		    SCTP_LISTEN_HASH(lport));
930 
931 		mdb_printf("conn_tfp\t%?p\t", sctp.sctp_conn_tfp);
932 		mdb_printf("listen_tfp\t%?p\n", sctp.sctp_listen_tfp);
933 
934 		mdb_printf("bind_hash\t%?p\tptpbhn\t\t%?p\n",
935 		    sctp.sctp_bind_hash, sctp.sctp_ptpbhn);
936 		mdb_printf("bind_lockp\t%?p\n",
937 		    sctp.sctp_bind_lockp);
938 		mdb_printf("[ bind_hash bucket\t%?d ]\n",
939 		    SCTP_BIND_HASH(lport));
940 	}
941 
942 	if (opts & MDB_SCTP_SHOW_CLOSE) {
943 		mdb_printf("%<b>Cleanup / Close%</b>\n");
944 		mdb_printf("shutdown_faddr\t%?p\tclient_errno\t%?d\n"
945 		    "lingertime\t%?d\trefcnt\t\t%?hu\n",
946 		    sctp.sctp_shutdown_faddr, sctp.sctp_client_errno,
947 		    sctp.sctp_lingertime, sctp.sctp_refcnt);
948 	}
949 
950 	if (opts & MDB_SCTP_SHOW_MISC) {
951 		mdb_printf("%<b>Miscellaneous%</b>\n");
952 		mdb_printf("bound_if\t%?u\theartbeat_mp\t%?p\n"
953 		    "family\t\t%?u\tipversion\t%?hu\n"
954 		    "hb_interval\t%?u\tautoclose\t%?d\n"
955 		    "active\t\t%?ld\ttx_adaption_code%?x\n"
956 		    "rx_adaption_code%?x\ttimer_mp\t%?p\n"
957 		    "partial_delivery_point\t%?d\n",
958 		    sctp.sctp_bound_if, sctp.sctp_heartbeat_mp,
959 		    sctp.sctp_family, sctp.sctp_ipversion,
960 		    sctp.sctp_hb_interval, sctp.sctp_autoclose,
961 		    sctp.sctp_active, sctp.sctp_tx_adaption_code,
962 		    sctp.sctp_rx_adaption_code, sctp.sctp_timer_mp,
963 		    sctp.sctp_pd_point);
964 	}
965 
966 	if (opts & MDB_SCTP_SHOW_EXT) {
967 		mdb_printf("%<b>Extensions and Reliable Ctl Chunks%</b>\n");
968 		mdb_printf("cxmit_list\t%?p\tlcsn\t\t%?x\n"
969 		    "fcsn\t\t%?x\n", sctp.sctp_cxmit_list, sctp.sctp_lcsn,
970 		    sctp.sctp_fcsn);
971 	}
972 
973 	if (opts & MDB_SCTP_SHOW_FLAGS) {
974 		mdb_printf("%<b>Flags%</b>\n");
975 		show_sctp_flags(&sctp);
976 	}
977 
978 	return (DCMD_OK);
979 }
980 
981 typedef struct fanout_walk_data {
982 	int index;
983 	int size;
984 	uintptr_t sctp;
985 	sctp_tf_t *fanout;
986 	uintptr_t (*getnext)(sctp_t *);
987 } fanout_walk_data_t;
988 
989 typedef struct fanout_init {
990 	const char *nested_walker_name;
991 	size_t offset;	/* for what used to be a symbol */
992 	int (*getsize)(sctp_stack_t *);
993 	uintptr_t (*getnext)(sctp_t *);
994 } fanout_init_t;
995 
996 static uintptr_t
997 listen_next(sctp_t *sctp)
998 {
999 	return ((uintptr_t)sctp->sctp_listen_hash_next);
1000 }
1001 
1002 /* ARGSUSED */
1003 static int
1004 listen_size(sctp_stack_t *sctps)
1005 {
1006 	return (SCTP_LISTEN_FANOUT_SIZE);
1007 }
1008 
1009 static uintptr_t
1010 conn_next(sctp_t *sctp)
1011 {
1012 	return ((uintptr_t)sctp->sctp_conn_hash_next);
1013 }
1014 
1015 static int
1016 conn_size(sctp_stack_t *sctps)
1017 {
1018 	int size;
1019 	uintptr_t kaddr;
1020 
1021 	kaddr = (uintptr_t)&sctps->sctps_conn_hash_size;
1022 
1023 	if (mdb_vread(&size, sizeof (size), kaddr) == -1) {
1024 		mdb_warn("can't read 'sctps_conn_hash_size' at %p", kaddr);
1025 		return (1);
1026 	}
1027 	return (size);
1028 }
1029 
1030 static uintptr_t
1031 bind_next(sctp_t *sctp)
1032 {
1033 	return ((uintptr_t)sctp->sctp_bind_hash);
1034 }
1035 
1036 /* ARGSUSED */
1037 static int
1038 bind_size(sctp_stack_t *sctps)
1039 {
1040 	return (SCTP_BIND_FANOUT_SIZE);
1041 }
1042 
1043 static intptr_t
1044 find_next_hash_item(fanout_walk_data_t *fw)
1045 {
1046 	sctp_tf_t tf;
1047 	sctp_t sctp;
1048 
1049 	/* first try to continue down the hash chain */
1050 	if (fw->sctp != NULL) {
1051 		/* try to get next in hash chain */
1052 		if (mdb_vread(&sctp, sizeof (sctp), fw->sctp) == -1) {
1053 			mdb_warn("failed to read sctp at %p", fw->sctp);
1054 			return (NULL);
1055 		}
1056 		fw->sctp = fw->getnext(&sctp);
1057 		if (fw->sctp != NULL)
1058 			return (fw->sctp);
1059 		else
1060 			/* end of chain; go to next bucket */
1061 			fw->index++;
1062 	}
1063 
1064 	/* find a new hash chain, traversing the buckets */
1065 	for (; fw->index < fw->size; fw->index++) {
1066 		/* read the current hash line for an sctp */
1067 		if (mdb_vread(&tf, sizeof (tf),
1068 		    (uintptr_t)(fw->fanout + fw->index)) == -1) {
1069 			mdb_warn("failed to read tf at %p",
1070 			    fw->fanout + fw->index);
1071 			return (NULL);
1072 		}
1073 		if (tf.tf_sctp != NULL) {
1074 			/* start of a new chain */
1075 			fw->sctp = (uintptr_t)tf.tf_sctp;
1076 			return (fw->sctp);
1077 		}
1078 	}
1079 	return (NULL);
1080 }
1081 
1082 static int
1083 fanout_stack_walk_init(mdb_walk_state_t *wsp)
1084 {
1085 	fanout_walk_data_t *lw;
1086 	fanout_init_t *fi = wsp->walk_arg;
1087 	sctp_stack_t *sctps = (sctp_stack_t *)wsp->walk_addr;
1088 	uintptr_t kaddr;
1089 
1090 	if (mdb_vread(&kaddr, sizeof (kaddr),
1091 	    wsp->walk_addr + fi->offset) == -1) {
1092 		mdb_warn("can't read sctp fanout at %p",
1093 		    wsp->walk_addr + fi->offset);
1094 		return (WALK_ERR);
1095 	}
1096 
1097 	lw = mdb_alloc(sizeof (*lw), UM_SLEEP);
1098 	lw->index = 0;
1099 	lw->size = fi->getsize(sctps);
1100 	lw->sctp = NULL;
1101 	lw->fanout = (sctp_tf_t *)kaddr;
1102 	lw->getnext = fi->getnext;
1103 
1104 	if ((wsp->walk_addr = find_next_hash_item(lw)) == NULL) {
1105 		return (WALK_DONE);
1106 	}
1107 	wsp->walk_data = lw;
1108 	return (WALK_NEXT);
1109 }
1110 
1111 static int
1112 fanout_stack_walk_step(mdb_walk_state_t *wsp)
1113 {
1114 	fanout_walk_data_t *fw = wsp->walk_data;
1115 	uintptr_t addr = wsp->walk_addr;
1116 	sctp_t sctp;
1117 	int status;
1118 
1119 	if (mdb_vread(&sctp, sizeof (sctp), addr) == -1) {
1120 		mdb_warn("failed to read sctp at %p", addr);
1121 		return (WALK_DONE);
1122 	}
1123 
1124 	status = wsp->walk_callback(addr, &sctp, wsp->walk_cbdata);
1125 	if (status != WALK_NEXT)
1126 		return (status);
1127 
1128 	if ((wsp->walk_addr = find_next_hash_item(fw)) == NULL)
1129 		return (WALK_DONE);
1130 
1131 	return (WALK_NEXT);
1132 }
1133 
1134 static void
1135 fanout_stack_walk_fini(mdb_walk_state_t *wsp)
1136 {
1137 	fanout_walk_data_t *fw = wsp->walk_data;
1138 
1139 	mdb_free(fw, sizeof (*fw));
1140 }
1141 
1142 int
1143 fanout_walk_init(mdb_walk_state_t *wsp)
1144 {
1145 	if (mdb_layered_walk("sctp_stacks", wsp) == -1) {
1146 		mdb_warn("can't walk 'sctp_stacks'");
1147 		return (WALK_ERR);
1148 	}
1149 
1150 	return (WALK_NEXT);
1151 }
1152 
1153 int
1154 fanout_walk_step(mdb_walk_state_t *wsp)
1155 {
1156 	fanout_init_t *fi = wsp->walk_arg;
1157 
1158 	if (mdb_pwalk(fi->nested_walker_name, wsp->walk_callback,
1159 	    wsp->walk_cbdata, wsp->walk_addr) == -1) {
1160 		mdb_warn("couldn't walk '%s'for address %p",
1161 		    fi->nested_walker_name, wsp->walk_addr);
1162 		return (WALK_ERR);
1163 	}
1164 	return (WALK_NEXT);
1165 }
1166 
1167 int
1168 sctps_walk_init(mdb_walk_state_t *wsp)
1169 {
1170 
1171 	if (mdb_layered_walk("sctp_stacks", wsp) == -1) {
1172 		mdb_warn("can't walk 'sctp_stacks'");
1173 		return (WALK_ERR);
1174 	}
1175 
1176 	return (WALK_NEXT);
1177 }
1178 
1179 int
1180 sctps_walk_step(mdb_walk_state_t *wsp)
1181 {
1182 	uintptr_t kaddr;
1183 
1184 	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_g_list);
1185 	if (mdb_pwalk("list", wsp->walk_callback,
1186 	    wsp->walk_cbdata, kaddr) == -1) {
1187 		mdb_warn("couldn't walk 'list' for address %p", kaddr);
1188 		return (WALK_ERR);
1189 	}
1190 	return (WALK_NEXT);
1191 }
1192 
1193 static int
1194 sctp_walk_faddr_init(mdb_walk_state_t *wsp)
1195 {
1196 	sctp_t sctp;
1197 
1198 	if (wsp->walk_addr == NULL)
1199 		return (WALK_ERR);
1200 
1201 	if (mdb_vread(&sctp, sizeof (sctp), wsp->walk_addr) == -1) {
1202 		mdb_warn("failed to read sctp at %p", wsp->walk_addr);
1203 		return (WALK_ERR);
1204 	}
1205 	if ((wsp->walk_addr = (uintptr_t)sctp.sctp_faddrs) != NULL)
1206 		return (WALK_NEXT);
1207 	else
1208 		return (WALK_DONE);
1209 }
1210 
1211 static int
1212 sctp_walk_faddr_step(mdb_walk_state_t *wsp)
1213 {
1214 	uintptr_t faddr_ptr = wsp->walk_addr;
1215 	sctp_faddr_t sctp_faddr;
1216 	int status;
1217 
1218 	if (mdb_vread(&sctp_faddr, sizeof (sctp_faddr_t), faddr_ptr) == -1) {
1219 		mdb_warn("failed to read sctp_faddr_t at %p", faddr_ptr);
1220 		return (WALK_ERR);
1221 	}
1222 	status = wsp->walk_callback(faddr_ptr, &sctp_faddr, wsp->walk_cbdata);
1223 	if (status != WALK_NEXT)
1224 		return (status);
1225 	if ((faddr_ptr = (uintptr_t)sctp_faddr.next) == NULL) {
1226 		return (WALK_DONE);
1227 	} else {
1228 		wsp->walk_addr = faddr_ptr;
1229 		return (WALK_NEXT);
1230 	}
1231 }
1232 
1233 /*
1234  * Helper structure for sctp_walk_saddr.  It stores the sctp_t being walked,
1235  * the current index to the sctp_saddrs[], and the current count of the
1236  * sctp_saddr_ipif_t list.
1237  */
1238 typedef struct {
1239 	sctp_t	sctp;
1240 	int	hash_index;
1241 	int	cur_cnt;
1242 } saddr_walk_t;
1243 
1244 static int
1245 sctp_walk_saddr_init(mdb_walk_state_t *wsp)
1246 {
1247 	sctp_t *sctp;
1248 	int i;
1249 	saddr_walk_t *swalker;
1250 
1251 	if (wsp->walk_addr == NULL)
1252 		return (WALK_ERR);
1253 
1254 	swalker = mdb_alloc(sizeof (saddr_walk_t), UM_SLEEP);
1255 	sctp = &swalker->sctp;
1256 	if (mdb_vread(sctp, sizeof (sctp_t), wsp->walk_addr) == -1) {
1257 		mdb_warn("failed to read sctp at %p", wsp->walk_addr);
1258 		mdb_free(swalker, sizeof (saddr_walk_t));
1259 		return (WALK_ERR);
1260 	}
1261 
1262 	/* Find the first source address. */
1263 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1264 		if (sctp->sctp_saddrs[i].ipif_count > 0) {
1265 			list_t *addr_list;
1266 
1267 			addr_list = &sctp->sctp_saddrs[i].sctp_ipif_list;
1268 			wsp->walk_addr = (uintptr_t)list_object(addr_list,
1269 			    addr_list->list_head.list_next);
1270 
1271 			/* Recode the current info */
1272 			swalker->hash_index = i;
1273 			swalker->cur_cnt = 1;
1274 			wsp->walk_data = swalker;
1275 
1276 			return (WALK_NEXT);
1277 		}
1278 	}
1279 	return (WALK_DONE);
1280 }
1281 
1282 static int
1283 sctp_walk_saddr_step(mdb_walk_state_t *wsp)
1284 {
1285 	uintptr_t saddr_ptr = wsp->walk_addr;
1286 	sctp_saddr_ipif_t saddr;
1287 	saddr_walk_t *swalker;
1288 	sctp_t *sctp;
1289 	int status;
1290 	int i, j;
1291 
1292 	if (mdb_vread(&saddr, sizeof (sctp_saddr_ipif_t), saddr_ptr) == -1) {
1293 		mdb_warn("failed to read sctp_saddr_ipif_t at %p", saddr_ptr);
1294 		return (WALK_ERR);
1295 	}
1296 	status = wsp->walk_callback(saddr_ptr, &saddr, wsp->walk_cbdata);
1297 	if (status != WALK_NEXT)
1298 		return (status);
1299 
1300 	swalker = (saddr_walk_t *)wsp->walk_data;
1301 	sctp = &swalker->sctp;
1302 	i = swalker->hash_index;
1303 	j = swalker->cur_cnt;
1304 
1305 	/*
1306 	 * If there is still a source address in the current list, return it.
1307 	 * Otherwise, go to the next list in the sctp_saddrs[].
1308 	 */
1309 	if (j++ < sctp->sctp_saddrs[i].ipif_count) {
1310 		wsp->walk_addr = (uintptr_t)saddr.saddr_ipif.list_next;
1311 		swalker->cur_cnt = j;
1312 		return (WALK_NEXT);
1313 	} else {
1314 		list_t *lst;
1315 
1316 		for (i = i + 1; i < SCTP_IPIF_HASH; i++) {
1317 			if (sctp->sctp_saddrs[i].ipif_count > 0) {
1318 				lst = &sctp->sctp_saddrs[i].sctp_ipif_list;
1319 				wsp->walk_addr = (uintptr_t)list_object(
1320 				    lst, lst->list_head.list_next);
1321 				swalker->hash_index = i;
1322 				swalker->cur_cnt = 1;
1323 				return (WALK_NEXT);
1324 			}
1325 		}
1326 	}
1327 	return (WALK_DONE);
1328 }
1329 
1330 static void
1331 sctp_walk_saddr_fini(mdb_walk_state_t *wsp)
1332 {
1333 	saddr_walk_t *swalker = (saddr_walk_t *)wsp->walk_data;
1334 
1335 	mdb_free(swalker, sizeof (saddr_walk_t));
1336 }
1337 
1338 
1339 typedef struct ill_walk_data {
1340 	sctp_ill_hash_t ills[SCTP_ILL_HASH];
1341 	uint32_t	count;
1342 } ill_walk_data_t;
1343 
1344 typedef struct ipuf_walk_data {
1345 	sctp_ipif_hash_t ipifs[SCTP_IPIF_HASH];
1346 	uint32_t	count;
1347 } ipif_walk_data_t;
1348 
1349 
1350 int
1351 sctp_ill_walk_init(mdb_walk_state_t *wsp)
1352 {
1353 	if (mdb_layered_walk("sctp_stacks", wsp) == -1) {
1354 		mdb_warn("can't walk 'sctp_stacks'");
1355 		return (WALK_ERR);
1356 	}
1357 
1358 	return (WALK_NEXT);
1359 }
1360 
1361 int
1362 sctp_ill_walk_step(mdb_walk_state_t *wsp)
1363 {
1364 	if (mdb_pwalk("sctp_stack_walk_ill", wsp->walk_callback,
1365 	    wsp->walk_cbdata, wsp->walk_addr) == -1) {
1366 		mdb_warn("couldn't walk 'sctp_stack_walk_ill' for addr %p",
1367 		    wsp->walk_addr);
1368 		return (WALK_ERR);
1369 	}
1370 	return (WALK_NEXT);
1371 }
1372 
1373 /*
1374  * wsp->walk_addr is the address of sctps_ill_list
1375  */
1376 static int
1377 sctp_stack_ill_walk_init(mdb_walk_state_t *wsp)
1378 {
1379 	ill_walk_data_t iw;
1380 	intptr_t i;
1381 	uintptr_t kaddr, uaddr;
1382 	size_t offset;
1383 
1384 	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_ills_count);
1385 	if (mdb_vread(&iw.count, sizeof (iw.count), kaddr) == -1) {
1386 		mdb_warn("can't read sctps_ills_count at %p", kaddr);
1387 		return (WALK_ERR);
1388 	}
1389 	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_g_ills);
1390 
1391 	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
1392 		mdb_warn("can't read scpts_g_ills %p", kaddr);
1393 		return (WALK_ERR);
1394 	}
1395 	if (mdb_vread(&iw.ills, sizeof (iw.ills), kaddr) == -1) {
1396 		mdb_warn("failed to read 'sctps_g_ills'");
1397 		return (NULL);
1398 	}
1399 
1400 	/* Find the first ill. */
1401 	for (i = 0; i < SCTP_ILL_HASH; i++) {
1402 		if (iw.ills[i].ill_count > 0) {
1403 			uaddr = (uintptr_t)&iw.ills[i].sctp_ill_list;
1404 			offset = uaddr - (uintptr_t)&iw.ills;
1405 			if (mdb_pwalk("list", wsp->walk_callback,
1406 			    wsp->walk_cbdata, kaddr+offset) == -1) {
1407 				mdb_warn("couldn't walk 'list' for address %p",
1408 				    kaddr);
1409 				return (WALK_ERR);
1410 			}
1411 		}
1412 	}
1413 	return (WALK_DONE);
1414 }
1415 
1416 static int
1417 sctp_stack_ill_walk_step(mdb_walk_state_t *wsp)
1418 {
1419 	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
1420 	    wsp->walk_cbdata));
1421 }
1422 
1423 int
1424 sctp_ipif_walk_init(mdb_walk_state_t *wsp)
1425 {
1426 	if (mdb_layered_walk("sctp_stacks", wsp) == -1) {
1427 		mdb_warn("can't walk 'sctp_stacks'");
1428 		return (WALK_ERR);
1429 	}
1430 	return (WALK_NEXT);
1431 }
1432 
1433 int
1434 sctp_ipif_walk_step(mdb_walk_state_t *wsp)
1435 {
1436 	if (mdb_pwalk("sctp_stack_walk_ipif", wsp->walk_callback,
1437 	    wsp->walk_cbdata, wsp->walk_addr) == -1) {
1438 		mdb_warn("couldn't walk 'sctp_stack_walk_ipif' for addr %p",
1439 		    wsp->walk_addr);
1440 		return (WALK_ERR);
1441 	}
1442 	return (WALK_NEXT);
1443 }
1444 
1445 /*
1446  * wsp->walk_addr is the address of sctps_ipif_list
1447  */
1448 static int
1449 sctp_stack_ipif_walk_init(mdb_walk_state_t *wsp)
1450 {
1451 	ipif_walk_data_t iw;
1452 	intptr_t i;
1453 	uintptr_t kaddr, uaddr;
1454 	size_t offset;
1455 
1456 	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_g_ipifs_count);
1457 	if (mdb_vread(&iw.count, sizeof (iw.count), kaddr) == -1) {
1458 		mdb_warn("can't read sctps_g_ipifs_count at %p", kaddr);
1459 		return (WALK_ERR);
1460 	}
1461 	kaddr = wsp->walk_addr + OFFSETOF(sctp_stack_t, sctps_g_ipifs);
1462 
1463 	if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
1464 		mdb_warn("can't read scpts_g_ipifs %p", kaddr);
1465 		return (WALK_ERR);
1466 	}
1467 	if (mdb_vread(&iw.ipifs, sizeof (iw.ipifs), kaddr) == -1) {
1468 		mdb_warn("failed to read 'sctps_g_ipifs'");
1469 		return (NULL);
1470 	}
1471 
1472 	/* Find the first ipif. */
1473 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1474 		if (iw.ipifs[i].ipif_count > 0) {
1475 			uaddr = (uintptr_t)&iw.ipifs[i].sctp_ipif_list;
1476 			offset = uaddr - (uintptr_t)&iw.ipifs;
1477 			if (mdb_pwalk("list", wsp->walk_callback,
1478 			    wsp->walk_cbdata, kaddr+offset) == -1) {
1479 				mdb_warn("couldn't walk 'list' for address %p",
1480 				    kaddr);
1481 				return (WALK_ERR);
1482 			}
1483 		}
1484 	}
1485 	return (WALK_DONE);
1486 }
1487 
1488 static int
1489 sctp_stack_ipif_walk_step(mdb_walk_state_t *wsp)
1490 {
1491 	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
1492 	    wsp->walk_cbdata));
1493 }
1494 
1495 static void
1496 sctp_help(void)
1497 {
1498 	mdb_printf("Print information for a given SCTP sctp_t\n\n");
1499 	mdb_printf("Options:\n");
1500 	mdb_printf("\t-a\t All the information\n");
1501 	mdb_printf("\t-f\t Flags\n");
1502 	mdb_printf("\t-h\t Hash Tables\n");
1503 	mdb_printf("\t-o\t Outbound Data\n");
1504 	mdb_printf("\t-i\t Inbound Data\n");
1505 	mdb_printf("\t-m\t Miscellaneous Information\n");
1506 	mdb_printf("\t-r\t RTT Tracking\n");
1507 	mdb_printf("\t-S\t Stats Counters\n");
1508 	mdb_printf("\t-F\t Flow Control\n");
1509 	mdb_printf("\t-H\t Composite Headers\n");
1510 	mdb_printf("\t-p\t PMTUD\n");
1511 	mdb_printf("\t-R\t Retransmit Information\n");
1512 	mdb_printf("\t-C\t Connection State\n");
1513 	mdb_printf("\t-c\t Cleanup / Close\n");
1514 	mdb_printf("\t-e\t Extensions and Reliable Control Chunks\n");
1515 	mdb_printf("\t-d\t Local and Peer addresses\n");
1516 	mdb_printf("\t-P\t Peer addresses\n");
1517 }
1518 static const mdb_dcmd_t dcmds[] = {
1519 	{ "sctp", ":[-afhoimrSFHpRCcedP]",
1520 	    "display sctp control structure", sctp, sctp_help },
1521 	{ "sctp_set", ":", "display a SCTP set", sctp_set },
1522 	{ "sctp_faddr", ":", "display a faddr", sctp_faddr },
1523 	{ "sctp_istr_msgs", ":", "display msg list on an instream",
1524 	    sctp_istr_msgs },
1525 	{ "sctp_mdata_chunk", ":", "display a data chunk in an mblk",
1526 	    sctp_mdata_chunk },
1527 	{ "sctp_xmit_list", ":", "display sctp xmit lists", sctp_xmit_list },
1528 	{ "sctp_instr", ":", "display instr", sctp_instr },
1529 	{ "sctp_reass_list", ":", "display reass list", sctp_reass_list },
1530 	{ "sctp_uo_reass_list", ":", "display un-ordered reass list",
1531 	    sctp_uo_reass_list },
1532 	{ NULL }
1533 };
1534 
1535 static const fanout_init_t listen_fanout_init = {
1536 	"sctp_stack_listen_fanout", OFFSETOF(sctp_stack_t, sctps_listen_fanout),
1537 	listen_size, listen_next
1538 };
1539 
1540 static const fanout_init_t conn_fanout_init = {
1541 	"sctp_stack_conn_fanout",  OFFSETOF(sctp_stack_t, sctps_conn_fanout),
1542 	conn_size, conn_next
1543 };
1544 
1545 static const fanout_init_t bind_fanout_init = {
1546 	"sctp_stack_bind_fanout", OFFSETOF(sctp_stack_t, sctps_bind_fanout),
1547 	bind_size, bind_next
1548 };
1549 
1550 static const mdb_walker_t walkers[] = {
1551 	{ "sctps", "walk the full chain of sctps for all stacks",
1552 	    sctps_walk_init, sctps_walk_step, NULL },
1553 	{ "sctp_listen_fanout", "walk the sctp listen fanout for all stacks",
1554 	    fanout_walk_init, fanout_walk_step, NULL,
1555 	    (void *)&listen_fanout_init },
1556 	{ "sctp_conn_fanout", "walk the sctp conn fanout for all stacks",
1557 	    fanout_walk_init, fanout_walk_step, NULL,
1558 	    (void *)&conn_fanout_init },
1559 	{ "sctp_bind_fanout", "walk the sctp bind fanout for all stacks",
1560 	    fanout_walk_init, fanout_walk_step, NULL,
1561 	    (void *)&bind_fanout_init },
1562 	{ "sctp_stack_listen_fanout",
1563 	    "walk the sctp listen fanout for one stack",
1564 	    fanout_stack_walk_init, fanout_stack_walk_step,
1565 	    fanout_stack_walk_fini,
1566 	    (void *)&listen_fanout_init },
1567 	{ "sctp_stack_conn_fanout", "walk the sctp conn fanout for one stack",
1568 	    fanout_stack_walk_init, fanout_stack_walk_step,
1569 	    fanout_stack_walk_fini,
1570 	    (void *)&conn_fanout_init },
1571 	{ "sctp_stack_bind_fanout", "walk the sctp bind fanoutfor one stack",
1572 	    fanout_stack_walk_init, fanout_stack_walk_step,
1573 	    fanout_stack_walk_fini,
1574 	    (void *)&bind_fanout_init },
1575 	{ "sctp_walk_faddr", "walk the peer address list of a given sctp_t",
1576 	    sctp_walk_faddr_init, sctp_walk_faddr_step, NULL },
1577 	{ "sctp_walk_saddr", "walk the local address list of a given sctp_t",
1578 	    sctp_walk_saddr_init, sctp_walk_saddr_step, sctp_walk_saddr_fini },
1579 	{ "sctp_walk_ill", "walk the sctp_g_ills list for all stacks",
1580 	    sctp_ill_walk_init, sctp_ill_walk_step, NULL },
1581 	{ "sctp_walk_ipif", "walk the sctp_g_ipif list for all stacks",
1582 		sctp_ipif_walk_init, sctp_ipif_walk_step, NULL },
1583 	{ "sctp_stack_walk_ill", "walk the sctp_g_ills list for one stack",
1584 		sctp_stack_ill_walk_init, sctp_stack_ill_walk_step, NULL },
1585 	{ "sctp_stack_walk_ipif", "walk the sctp_g_ipif list for one stack",
1586 		sctp_stack_ipif_walk_init, sctp_stack_ipif_walk_step, NULL },
1587 	{ "sctp_stacks", "walk all the sctp_stack_t",
1588 		sctp_stacks_walk_init, sctp_stacks_walk_step, NULL },
1589 	{ NULL }
1590 };
1591 
1592 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
1593 
1594 const mdb_modinfo_t *
1595 _mdb_init(void)
1596 {
1597 	return (&modinfo);
1598 }
1599