Home | History | Annotate | Download | only in sctp
      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_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\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_adaptation_code%?x\n"
    956 		    "rx_adaptation_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_adaptation_code,
    962 		    sctp.sctp_rx_adaptation_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