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