/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <sys/mdb_modapi.h>
#include <mdb/mdb_stdlib.h>
#include <inet/ipclassifier.h>
#include <sctp/sctp_impl.h>
#include <sctp/sctp_addr.h>
/*
* mdb list walker?
*/
static int
{
return (0);
}
return (nss.netstack_stackid);
}
int
{
mdb_warn("can't walk 'netstack'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
return (WALK_ERR);
}
}
static char *
{
char *statestr;
switch (state) {
case SCTP_FADDRS_UNREACH:
statestr = "Unreachable";
break;
case SCTP_FADDRS_DOWN:
statestr = "Down";
break;
case SCTP_FADDRS_ALIVE:
statestr = "Alive";
break;
case SCTP_FADDRS_UNCONFIRMED:
statestr = "Unconfirmed";
break;
default:
statestr = "Unknown";
break;
}
return (statestr);
}
/* ARGSUSED */
static int
{
char *statestr;
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_ERR);
}
statestr);
fa->sf_rtt_updates);
fa->sf_max_retr);
fa->sf_hb_interval);
fa->sf_hb_secret);
mdb_printf("hb_enabled\t%?d\thb_pending\t%?d\n"
"timer_running\t%?d\tdf\t\t%?d\n"
"pmtu_discovered\t%?d\tisv4\t\t%?d\n"
"retransmissions\t%?u\n",
return (DCMD_OK);
}
static void
{
mdb_printf("\tbegin\t%<b>%?x%</b>\t\tend\t%<b>%?x%</b>\n",
}
/* ARGSUSED */
static int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_ERR);
return (DCMD_OK);
}
static void
{
while (addr != 0) {
return;
}
}
}
static int
{
return (-1);
mdb_printf("%<u>msg_hdr_t at \t%?p\tsentto\t%?p%</u>\n",
return (0);
}
static int
{
return (-1);
mdb_printf("%<u>data_chunk_t \t%?p\tsentto\t%?p%</u>\n",
sizeof (sdc.sdh_payload_id));
return (0);
}
static int
{
if (!addr)
return (0);
return (-1);
for (;;) {
dump_msghdr(&meta);
mdb_printf("No data chunks with message header!\n");
return (-1);
}
return (-1);
}
for (;;) {
dump_datahdr(&mp);
break;
return (-1);
}
break;
return (-1);
}
return (0);
}
static int
{
if (!addr)
return (0);
return (-1);
for (;;) {
dump_msghdr(&meta);
break;
return (-1);
}
return (0);
}
/* ARGSUSED */
static int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_ERR);
mdb_printf("%<b>Chunkified TX list%</b>\n");
return (DCMD_ERR);
mdb_printf("%<b>Unchunkified TX list%</b>\n");
return (DCMD_ERR);
return (DCMD_OK);
}
/* ARGSUSED */
static int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_ERR);
return (DCMD_ERR);
return (DCMD_OK);
}
/* ARGSUSED */
static int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
do {
return (DCMD_ERR);
mdb_printf("\tistr mblk at %p: next: %?p\n"
do {
break;
break;
mdb_printf("\t\t\ttsn: %x bbit: %d ebit: %d\n",
return (DCMD_OK);
}
/* ARGSUSED */
static int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
do {
return (DCMD_ERR);
return (DCMD_ERR);
mdb_printf("\treassembly mblk at %p: next: %?p\n"
mdb_printf("\t\tssn: %hu\tneeded: %hu\tgot: %hu\ttail: %?p\n"
"FALSE");
/* display the contents of this ssn's reassemby list */
do {
break;
break;
mdb_printf("\t\t\ttsn: %x bbit: %d ebit: %d\n",
return (DCMD_OK);
}
/* ARGSUSED */
static int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
do {
return (DCMD_ERR);
mdb_printf("\treassembly mblk at %p: next: %?p\n"
break;
mdb_printf("\t\t\tsid: %hu ssn: %hu tsn: %x "
return (DCMD_OK);
}
static int
{
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_ERR);
mdb_printf("%<b>%-?p%</b>\n\tmsglist\t%?p\tnmsgs\t%?d\n"
}
static const char *
{
switch (sctp->sctp_state) {
case SCTPS_IDLE: return ("SCTPS_IDLE");
case SCTPS_BOUND: return ("SCTPS_BOUND");
case SCTPS_LISTEN: return ("SCTPS_LISTEN");
case SCTPS_COOKIE_WAIT: return ("SCTPS_COOKIE_WAIT");
case SCTPS_COOKIE_ECHOED: return ("SCTPS_COOKIE_ECHOED");
case SCTPS_ESTABLISHED: return ("SCTPS_ESTABLISHED");
case SCTPS_SHUTDOWN_PENDING: return ("SCTPS_SHUTDOWN_PENDING");
case SCTPS_SHUTDOWN_SENT: return ("SCTPS_SHUTDOWN_SENT");
case SCTPS_SHUTDOWN_RECEIVED: return ("SCTPS_SHUTDOWN_RECEIVED");
case SCTPS_SHUTDOWN_ACK_SENT: return ("SCTPS_SHUTDOWN_ACK_SENT");
default: return ("UNKNOWN STATE");
}
}
static void
{
mdb_printf("\tunderstands_asconf\t%d\n",
mdb_printf("\tdgram_errind\t\t%d\n",
if (sctp->sctp_lingering)
return;
mdb_printf("\trecvdstaddr\t\t%d\n",
}
/*
* Given a sctp_saddr_ipif_t, print out its address. This assumes
* that addr contains the sctp_addr_ipif_t structure already and this
* function does not need to read it in.
*/
/* ARGSUSED */
static int
{
char *statestr;
/* Read in the sctp_ipif object */
-1) {
return (WALK_ERR);
}
switch (ipif.sctp_ipif_state) {
case SCTP_IPIFS_CONDEMNED:
statestr = "Condemned";
break;
case SCTP_IPIFS_INVALID:
statestr = "Invalid";
break;
case SCTP_IPIFS_DOWN:
statestr = "Down";
break;
case SCTP_IPIFS_UP:
statestr = "Up";
break;
default:
statestr = "Unknown";
break;
}
statestr);
mdb_printf("/Dontsrc");
mdb_printf("/Unconfirmed");
mdb_printf("/DeletePending");
mdb_printf(")\n");
mdb_printf("\t\t\tid %d zoneid %d IPIF flags %x\n",
return (WALK_NEXT);
}
/*
* Given a sctp_faddr_t, print out its address. This assumes that
* addr contains the sctp_faddr_t structure already and this function
* does not need to read it in.
*/
static int
{
char *statestr;
int *i = cbdata;
statestr);
return (WALK_NEXT);
}
int
{
int i;
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
return (DCMD_ERR);
}
return (DCMD_ERR);
}
return (DCMD_USAGE);
}
/* non-verbose faddrs, suitable for pipelines to sctp_faddr */
if (paddr != 0) {
== -1) {
mdb_warn("failed to read faddr at %p",
fp);
return (DCMD_ERR);
}
}
return (DCMD_OK);
}
if (sctp->sctp_faddrs) {
}
mdb_printf("\n");
if (opts & MDB_SCTP_DUMP_ADDRS) {
mdb_printf("%<b>Local and Peer Addresses%</b>\n");
/* Display source addresses */
/* Display peer addresses */
i = 1;
mdb_printf("lastfaddr\t%?p\tprimary\t\t%?p\n",
mdb_printf("current\t\t%?p\tlastdata\t%?p\n",
}
if (opts & MDB_SCTP_SHOW_OUT) {
mdb_printf("%<b>Outbound Data%</b>\n");
mdb_printf("xmit_head\t%?p\txmit_tail\t%?p\n",
mdb_printf("xmit_unsent\t%?p\txmit_unsent_tail%?p\n",
mdb_printf("unacked\t\t%?u\tunsent\t\t%?ld\n",
mdb_printf("ltsn\t\t%?x\tlastack_rxd\t%?x\n",
mdb_printf("recovery_tsn\t%?x\tadv_pap\t\t%?x\n",
mdb_printf("num_ostr\t%?hu\tostrcntrs\t%?p\n",
mdb_printf("pad_mp\t\t%?p\terr_chunks\t%?p\n",
mdb_printf("%<b>Default Send Parameters%</b>\n");
mdb_printf("def_stream\t%?u\tdef_flags\t%?x\n",
mdb_printf("def_ppid\t%?x\tdef_context\t%?x\n",
mdb_printf("def_timetolive\t%?u\n",
}
if (opts & MDB_SCTP_SHOW_IN) {
mdb_printf("%<b>Inbound Data%</b>\n");
mdb_printf("sack_info\t%?p\tsack_gaps\t%?d\n",
mdb_printf("ftsn\t\t%?x\tlastacked\t%?x\n",
mdb_printf("istr_nmsgs\t%?d\tsack_toggle\t%?d\n",
mdb_printf("num_istr\t%?hu\tinstr\t\t%?p\n",
}
if (opts & MDB_SCTP_SHOW_RTT) {
mdb_printf("%<b>RTT Tracking%</b>\n");
mdb_printf("rtt_tsn\t\t%?x\tout_time\t%?ld\n",
}
if (opts & MDB_SCTP_SHOW_FLOW) {
mdb_printf("%<b>Flow Control%</b>\n");
mdb_printf("tconn_sndbuf\t%?d\n"
"conn_sndlowat\t%?d\tfrwnd\t\t%?u\n"
"rwnd\t\t%?u\tlast advertised rwnd\t%?u\n"
}
if (opts & MDB_SCTP_SHOW_HDR) {
mdb_printf("%<b>Composite Headers%</b>\n");
mdb_printf("iphc\t\t%?p\tiphc6\t\t%?p\n"
"iphc_len\t%?d\tiphc6_len\t%?d\n"
"hdr_len\t\t%?d\thdr6_len\t%?d\n"
"ipha\t\t%?p\tip6h\t\t%?p\n"
"ip_hdr_len\t%?d\tip_hdr6_len\t%?d\n"
"sctph\t\t%?p\tsctph6\t\t%?p\n"
sctp->sctp_fvtag);
}
if (opts & MDB_SCTP_SHOW_PMTUD) {
mdb_printf("%<b>PMTUd%</b>\n");
mdb_printf("last_mtu_probe\t%?ld\tmtu_probe_intvl\t%?ld\n"
"mss\t\t%?u\n",
}
if (opts & MDB_SCTP_SHOW_RXT) {
mdb_printf("%<b>Retransmit Info%</b>\n");
mdb_printf("cookie_mp\t%?p\tstrikes\t\t%?d\n"
"max_init_rxt\t%?d\tpa_max_rxt\t%?d\n"
"pp_max_rxt\t%?d\trto_max\t\t%?u\n"
"rto_min\t\t%?u\trto_initial\t%?u\n"
"init_rto_max\t%?u\n"
}
if (opts & MDB_SCTP_SHOW_CONN) {
mdb_printf("%<b>Connection State%</b>\n");
mdb_printf("last_secret_update%?ld\n",
mdb_printf("secret\t\t");
for (i = 0; i < SCTP_SECRET_LEN; i++) {
if (i % 2 == 0)
else
}
mdb_printf("\n");
mdb_printf("old_secret\t");
for (i = 0; i < SCTP_SECRET_LEN; i++) {
if (i % 2 == 0)
else
}
mdb_printf("\n");
}
if (opts & MDB_SCTP_SHOW_STATS) {
mdb_printf("%<b>Stats Counters%</b>\n");
mdb_printf("opkts\t\t%?llu\tobchunks\t%?llu\n"
"odchunks\t%?llu\toudchunks\t%?llu\n"
"rxtchunks\t%?llu\tT1expire\t%?lu\n"
"T2expire\t%?lu\tT3expire\t%?lu\n"
"msgcount\t%?llu\tprsctpdrop\t%?llu\n"
"AssocStartTime\t%?lu\n",
mdb_printf("ipkts\t\t%?llu\tibchunks\t%?llu\n"
"idchunks\t%?llu\tiudchunks\t%?llu\n"
"fragdmsgs\t%?llu\treassmsgs\t%?llu\n",
}
if (opts & MDB_SCTP_SHOW_HASH) {
mdb_printf("%<b>Hash Tables%</b>\n");
mdb_printf("listen_hash_next%?p\t",
mdb_printf("listen_hash_prev%?p\n",
mdb_printf("[ listen_hash bucket\t%?d ]\n",
mdb_printf("bind_hash\t%?p\tptpbhn\t\t%?p\n",
mdb_printf("bind_lockp\t%?p\n",
mdb_printf("[ bind_hash bucket\t%?d ]\n",
}
if (opts & MDB_SCTP_SHOW_CLOSE) {
mdb_printf("%<b>Cleanup / Close%</b>\n");
mdb_printf("shutdown_faddr\t%?p\tclient_errno\t%?d\n"
"lingertime\t%?d\trefcnt\t\t%?hu\n",
}
if (opts & MDB_SCTP_SHOW_MISC) {
mdb_printf("%<b>Miscellaneous%</b>\n");
mdb_printf("bound_if\t%?u\theartbeat_mp\t%?p\n"
"family\t\t%?u\tipversion\t%?hu\n"
"hb_interval\t%?u\tautoclose\t%?d\n"
"active\t\t%?ld\ttx_adaptation_code%?x\n"
"rx_adaptation_code%?x\ttimer_mp\t%?p\n"
"partial_delivery_point\t%?d\n",
}
if (opts & MDB_SCTP_SHOW_EXT) {
mdb_printf("%<b>Extensions and Reliable Ctl Chunks%</b>\n");
mdb_printf("cxmit_list\t%?p\tlcsn\t\t%?x\n"
}
if (opts & MDB_SCTP_SHOW_FLAGS) {
mdb_printf("%<b>Flags%</b>\n");
}
return (DCMD_OK);
}
typedef struct fanout_walk_data {
int index;
int size;
typedef struct fanout_init {
const char *nested_walker_name;
static uintptr_t
{
}
/* ARGSUSED */
static int
{
return (SCTP_LISTEN_FANOUT_SIZE);
}
static uintptr_t
{
}
static int
{
int size;
return (1);
}
return (size);
}
static uintptr_t
{
}
/* ARGSUSED */
static int
{
return (SCTP_BIND_FANOUT_SIZE);
}
static intptr_t
{
/* first try to continue down the hash chain */
/* try to get next in hash chain */
return (NULL);
}
else
/* end of chain; go to next bucket */
}
/* find a new hash chain, traversing the buckets */
/* read the current hash line for an sctp */
mdb_warn("failed to read tf at %p",
return (NULL);
}
/* start of a new chain */
}
}
return (NULL);
}
static int
{
mdb_warn("can't read sctp fanout at %p",
return (WALK_ERR);
}
return (WALK_DONE);
}
return (WALK_NEXT);
}
static int
{
int status;
return (WALK_DONE);
}
return (status);
return (WALK_DONE);
return (WALK_NEXT);
}
static void
{
}
int
{
mdb_warn("can't walk 'sctp_stacks'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
mdb_warn("couldn't walk '%s'for address %p",
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
mdb_warn("can't walk 'sctp_stacks'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
return (WALK_ERR);
}
return (WALK_NEXT);
}
static int
{
return (WALK_ERR);
return (WALK_ERR);
}
return (WALK_NEXT);
else
return (WALK_DONE);
}
static int
{
int status;
return (WALK_ERR);
}
return (status);
return (WALK_DONE);
} else {
return (WALK_NEXT);
}
}
/*
* Helper structure for sctp_walk_saddr. It stores the sctp_t being walked,
* the current index to the sctp_saddrs[], and the current count of the
* sctp_saddr_ipif_t list.
*/
typedef struct {
int hash_index;
int cur_cnt;
} saddr_walk_t;
static int
{
int i;
return (WALK_ERR);
return (WALK_ERR);
}
/* Find the first source address. */
for (i = 0; i < SCTP_IPIF_HASH; i++) {
/* Recode the current info */
swalker->hash_index = i;
return (WALK_NEXT);
}
}
return (WALK_DONE);
}
static int
{
int status;
int i, j;
return (WALK_ERR);
}
return (status);
i = swalker->hash_index;
/*
* If there is still a source address in the current list, return it.
* Otherwise, go to the next list in the sctp_saddrs[].
*/
return (WALK_NEXT);
} else {
for (i = i + 1; i < SCTP_IPIF_HASH; i++) {
swalker->hash_index = i;
return (WALK_NEXT);
}
}
}
return (WALK_DONE);
}
static void
{
}
typedef struct ill_walk_data {
typedef struct ipuf_walk_data {
int
{
mdb_warn("can't walk 'sctp_stacks'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
mdb_warn("couldn't walk 'sctp_stack_walk_ill' for addr %p",
return (WALK_ERR);
}
return (WALK_NEXT);
}
/*
* wsp->walk_addr is the address of sctps_ill_list
*/
static int
{
intptr_t i;
return (WALK_ERR);
}
return (WALK_ERR);
}
mdb_warn("failed to read 'sctps_g_ills'");
return (NULL);
}
/* Find the first ill. */
for (i = 0; i < SCTP_ILL_HASH; i++) {
mdb_warn("couldn't walk 'list' for address %p",
kaddr);
return (WALK_ERR);
}
}
}
return (WALK_DONE);
}
static int
{
wsp->walk_cbdata));
}
int
{
mdb_warn("can't walk 'sctp_stacks'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
int
{
mdb_warn("couldn't walk 'sctp_stack_walk_ipif' for addr %p",
return (WALK_ERR);
}
return (WALK_NEXT);
}
/*
* wsp->walk_addr is the address of sctps_ipif_list
*/
static int
{
intptr_t i;
return (WALK_ERR);
}
return (WALK_ERR);
}
mdb_warn("failed to read 'sctps_g_ipifs'");
return (NULL);
}
/* Find the first ipif. */
for (i = 0; i < SCTP_IPIF_HASH; i++) {
mdb_warn("couldn't walk 'list' for address %p",
kaddr);
return (WALK_ERR);
}
}
}
return (WALK_DONE);
}
static int
{
wsp->walk_cbdata));
}
/*
* Initialization function for the per CPU SCTP stats counter walker of a given
* SCTP stack.
*/
int
{
return (WALK_ERR);
return (WALK_ERR);
}
if (sctps.sctps_sc_cnt == 0)
return (WALK_DONE);
/*
* Store the sctp_stack_t pointer in walk_data. The stepping function
* used it to calculate if the end of the counter has reached.
*/
return (WALK_NEXT);
}
/*
* Stepping function for the per CPU SCTP stats counterwalker.
*/
int
{
int status;
-1) {
return (WALK_ERR);
}
mdb_warn("failed ot read sctp_stats_cpu_t at %p",
return (WALK_ERR);
}
return (status);
sizeof (sctp_stats_cpu_t *);
return (WALK_DONE);
return (WALK_NEXT);
}
static void
sctp_help(void)
{
mdb_printf("Print information for a given SCTP sctp_t\n\n");
mdb_printf("Options:\n");
mdb_printf("\t-a\t All the information\n");
mdb_printf("\t-f\t Flags\n");
mdb_printf("\t-h\t Hash Tables\n");
mdb_printf("\t-o\t Outbound Data\n");
mdb_printf("\t-i\t Inbound Data\n");
mdb_printf("\t-m\t Miscellaneous Information\n");
mdb_printf("\t-r\t RTT Tracking\n");
mdb_printf("\t-S\t Stats Counters\n");
mdb_printf("\t-F\t Flow Control\n");
mdb_printf("\t-H\t Composite Headers\n");
mdb_printf("\t-p\t PMTUD\n");
mdb_printf("\t-R\t Retransmit Information\n");
mdb_printf("\t-C\t Connection State\n");
mdb_printf("\t-c\t Cleanup / Close\n");
mdb_printf("\t-e\t Extensions and Reliable Control Chunks\n");
mdb_printf("\t-d\t Local and Peer addresses\n");
mdb_printf("\t-P\t Peer addresses\n");
}
{ "sctp", ":[-afhoimrSFHpRCcedP]",
{ "sctp_istr_msgs", ":", "display msg list on an instream",
{ "sctp_mdata_chunk", ":", "display a data chunk in an mblk",
{ "sctp_uo_reass_list", ":", "display un-ordered reass list",
{ NULL }
};
};
};
};
{ "sctps", "walk the full chain of sctps for all stacks",
{ "sctp_listen_fanout", "walk the sctp listen fanout for all stacks",
(void *)&listen_fanout_init },
{ "sctp_conn_fanout", "walk the sctp conn fanout for all stacks",
(void *)&conn_fanout_init },
{ "sctp_bind_fanout", "walk the sctp bind fanout for all stacks",
(void *)&bind_fanout_init },
{ "sctp_stack_listen_fanout",
"walk the sctp listen fanout for one stack",
(void *)&listen_fanout_init },
{ "sctp_stack_conn_fanout", "walk the sctp conn fanout for one stack",
(void *)&conn_fanout_init },
{ "sctp_stack_bind_fanout", "walk the sctp bind fanoutfor one stack",
(void *)&bind_fanout_init },
{ "sctp_walk_faddr", "walk the peer address list of a given sctp_t",
{ "sctp_walk_saddr", "walk the local address list of a given sctp_t",
{ "sctp_walk_ill", "walk the sctp_g_ills list for all stacks",
{ "sctp_walk_ipif", "walk the sctp_g_ipif list for all stacks",
{ "sctp_stack_walk_ill", "walk the sctp_g_ills list for one stack",
{ "sctp_stack_walk_ipif", "walk the sctp_g_ipif list for one stack",
{ "sctps_sc", "walk all the per CPU stats counters of a sctp_stack_t",
{ NULL }
};
const mdb_modinfo_t *
_mdb_init(void)
{
return (&modinfo);
}