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