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 <mdb/mdb_modapi.h> 30 #include <mdb/mdb_ks.h> 31 #include <mdb/mdb_ctf.h> 32 #include <sys/types.h> 33 #include <sys/tihdr.h> 34 #include <inet/led.h> 35 #include <inet/common.h> 36 #include <netinet/in.h> 37 #include <netinet/ip6.h> 38 #include <netinet/icmp6.h> 39 #include <inet/ip.h> 40 #include <inet/ip6.h> 41 #include <inet/ipclassifier.h> 42 #include <inet/tcp.h> 43 #include <sys/stream.h> 44 #include <sys/vfs.h> 45 #include <sys/stropts.h> 46 #include <sys/tpicommon.h> 47 #include <sys/socket.h> 48 #include <sys/socketvar.h> 49 #include <sys/cred_impl.h> 50 #include <inet/udp_impl.h> 51 #include <inet/arp_impl.h> 52 #include <inet/rawip_impl.h> 53 #include <inet/mi.h> 54 55 #define MIH2MIO(mihp) (&(mihp)->mh_o) 56 57 #define ADDR_V6_WIDTH 23 58 #define ADDR_V4_WIDTH 15 59 60 #define NETSTAT_ALL 0x1 61 #define NETSTAT_VERBOSE 0x2 62 63 /* 64 * Print an IPv4 address and port number in a compact and easy to read format 65 * The arguments are in network byte order 66 */ 67 static void 68 net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport) 69 { 70 uint32_t naddr = V4_PART_OF_V6((*nipv6addr)); 71 72 mdb_nhconvert(&nport, &nport, sizeof (nport)); 73 mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport); 74 } 75 76 /* 77 * Print an IPv6 address and port number in a compact and easy to read format 78 * The arguments are in network byte order 79 */ 80 static void 81 net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport) 82 { 83 mdb_nhconvert(&nport, &nport, sizeof (nport)); 84 mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport); 85 } 86 87 static int 88 net_tcp_active(const tcp_t *tcp) 89 { 90 return (tcp->tcp_state >= TCPS_ESTABLISHED); 91 } 92 93 static int 94 net_tcp_ipv4(const tcp_t *tcp) 95 { 96 return ((tcp->tcp_ipversion == IPV4_VERSION) || 97 (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_ip_src_v6) && 98 (tcp->tcp_state <= TCPS_LISTEN))); 99 } 100 101 static int 102 net_tcp_ipv6(const tcp_t *tcp) 103 { 104 return (tcp->tcp_ipversion == IPV6_VERSION); 105 } 106 107 static int 108 net_udp_active(const udp_t *udp) 109 { 110 return ((udp->udp_state != TS_UNBND) && (udp->udp_state != TS_IDLE)); 111 } 112 113 static int 114 net_udp_ipv4(const udp_t *udp) 115 { 116 return ((udp->udp_ipversion == IPV4_VERSION) || 117 (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src) && 118 (udp->udp_state <= TS_IDLE))); 119 } 120 121 static int 122 net_udp_ipv6(const udp_t *udp) 123 { 124 return (udp->udp_ipversion == IPV6_VERSION); 125 } 126 127 int 128 sonode_walk_init(mdb_walk_state_t *wsp) 129 { 130 if (wsp->walk_addr == NULL) { 131 GElf_Sym sym; 132 struct socklist *slp; 133 134 if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) { 135 mdb_warn("failed to lookup sockfs`socklist"); 136 return (WALK_ERR); 137 } 138 139 slp = (struct socklist *)(uintptr_t)sym.st_value; 140 141 if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr), 142 (uintptr_t)&slp->sl_list) == -1) { 143 mdb_warn("failed to read address of initial sonode " 144 "at %p", &slp->sl_list); 145 return (WALK_ERR); 146 } 147 } 148 149 wsp->walk_data = mdb_alloc(sizeof (struct sonode), UM_SLEEP); 150 return (WALK_NEXT); 151 } 152 153 int 154 sonode_walk_step(mdb_walk_state_t *wsp) 155 { 156 int status; 157 struct sonode *sonodep; 158 159 if (wsp->walk_addr == NULL) 160 return (WALK_DONE); 161 162 if (mdb_vread(wsp->walk_data, sizeof (struct sonode), 163 wsp->walk_addr) == -1) { 164 mdb_warn("failed to read sonode at %p", wsp->walk_addr); 165 return (WALK_ERR); 166 } 167 168 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 169 wsp->walk_cbdata); 170 171 sonodep = wsp->walk_data; 172 173 wsp->walk_addr = (uintptr_t)sonodep->so_next; 174 return (status); 175 } 176 177 void 178 sonode_walk_fini(mdb_walk_state_t *wsp) 179 { 180 mdb_free(wsp->walk_data, sizeof (struct sonode)); 181 } 182 183 struct mi_walk_data { 184 uintptr_t mi_wd_miofirst; 185 MI_O mi_wd_miodata; 186 }; 187 188 int 189 mi_walk_init(mdb_walk_state_t *wsp) 190 { 191 struct mi_walk_data *wdp; 192 193 if (wsp->walk_addr == NULL) { 194 mdb_warn("mi doesn't support global walks\n"); 195 return (WALK_ERR); 196 } 197 198 wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP); 199 200 /* So that we do not immediately return WALK_DONE below */ 201 wdp->mi_wd_miofirst = NULL; 202 203 wsp->walk_data = wdp; 204 return (WALK_NEXT); 205 } 206 207 int 208 mi_walk_step(mdb_walk_state_t *wsp) 209 { 210 struct mi_walk_data *wdp = wsp->walk_data; 211 MI_OP miop = &wdp->mi_wd_miodata; 212 int status; 213 214 /* Always false in the first iteration */ 215 if ((wsp->walk_addr == (uintptr_t)NULL) || 216 (wsp->walk_addr == wdp->mi_wd_miofirst)) { 217 return (WALK_DONE); 218 } 219 220 if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) { 221 mdb_warn("failed to read MI object at %p", wsp->walk_addr); 222 return (WALK_ERR); 223 } 224 225 status = wsp->walk_callback(wsp->walk_addr, miop, wsp->walk_cbdata); 226 227 /* Only true in the first iteration */ 228 if (wdp->mi_wd_miofirst == NULL) 229 wdp->mi_wd_miofirst = wsp->walk_addr; 230 231 wsp->walk_addr = (uintptr_t)miop->mi_o_next; 232 return (status); 233 } 234 235 void 236 mi_walk_fini(mdb_walk_state_t *wsp) 237 { 238 mdb_free(wsp->walk_data, sizeof (struct mi_walk_data)); 239 } 240 241 typedef struct mi_payload_walk_data_s { 242 uintptr_t mi_pwd_first; 243 void *mi_pwd_data; 244 } mi_payload_walk_data_t; 245 246 static void 247 delete_mi_payload_walk_data(mi_payload_walk_data_t *pwdp, size_t payload_size) 248 { 249 mdb_free(pwdp->mi_pwd_data, payload_size); 250 mdb_free(pwdp, sizeof (mi_payload_walk_data_t)); 251 } 252 253 typedef struct mi_payload_walk_arg_s { 254 const char *mi_pwa_obj; /* load object of mi_o_head_t * */ 255 const char *mi_pwa_sym; /* symbol name of mi_o_head_t * */ 256 const size_t mi_pwa_size; /* size of mi payload */ 257 const uint_t mi_pwa_flags; /* device and/or module */ 258 } mi_payload_walk_arg_t; 259 260 #define MI_PAYLOAD_DEVICE 0x1 261 #define MI_PAYLOAD_MODULE 0x2 262 263 int 264 mi_payload_walk_init(mdb_walk_state_t *wsp) 265 { 266 const mi_payload_walk_arg_t *arg = wsp->walk_arg; 267 mi_payload_walk_data_t *pwdp; 268 GElf_Sym sym; 269 mi_head_t *mihp; 270 271 /* Determine the address to start or end the walk with */ 272 if (mdb_lookup_by_obj(arg->mi_pwa_obj, arg->mi_pwa_sym, &sym) == -1) { 273 mdb_warn("failed to lookup %s`%s", 274 arg->mi_pwa_obj, arg->mi_pwa_sym); 275 return (WALK_ERR); 276 } 277 278 if (mdb_vread(&mihp, sizeof (mihp), (uintptr_t)sym.st_value) == -1) { 279 mdb_warn("failed to read address of global MI Head " 280 "mi_o_head_t at %p", (uintptr_t)sym.st_value); 281 return (WALK_ERR); 282 } 283 284 pwdp = mdb_alloc(sizeof (mi_payload_walk_data_t), UM_SLEEP); 285 pwdp->mi_pwd_data = mdb_alloc(arg->mi_pwa_size, UM_SLEEP); 286 wsp->walk_data = pwdp; 287 288 if (wsp->walk_addr == NULL) { 289 /* Do not immediately return WALK_DONE below */ 290 pwdp->mi_pwd_first = NULL; 291 /* We determined where to begin */ 292 wsp->walk_addr = (uintptr_t)MIH2MIO(mihp); 293 } else { 294 /* Do not cycle through all of the MI_O objects */ 295 pwdp->mi_pwd_first = (uintptr_t)MIH2MIO(mihp); 296 /* We were given where to begin */ 297 wsp->walk_addr = (uintptr_t)((MI_OP)wsp->walk_addr - 1); 298 } 299 300 if (mdb_layered_walk("genunix`mi", wsp) == -1) { 301 mdb_warn("failed to walk genunix`mi"); 302 delete_mi_payload_walk_data(pwdp, arg->mi_pwa_size); 303 return (WALK_ERR); 304 } 305 306 return (WALK_NEXT); 307 } 308 309 int 310 mi_payload_walk_step(mdb_walk_state_t *wsp) 311 { 312 const mi_payload_walk_arg_t *arg = wsp->walk_arg; 313 mi_payload_walk_data_t *pwdp = wsp->walk_data; 314 void *payload = pwdp->mi_pwd_data; 315 uintptr_t payload_kaddr = (uintptr_t)((MI_OP)wsp->walk_addr + 1); 316 const MI_O *mio = wsp->walk_layer; 317 318 /* If this is a local walk, prevent cycling */ 319 if (wsp->walk_addr == pwdp->mi_pwd_first) 320 return (WALK_DONE); 321 322 /* 323 * This was a global walk, prevent reading this payload as the 324 * initial MI_O is the head of the list and is not the header 325 * to a valid payload 326 */ 327 if (pwdp->mi_pwd_first == NULL) { 328 pwdp->mi_pwd_first = wsp->walk_addr; 329 return (WALK_NEXT); 330 } 331 332 if (mio->mi_o_isdev == B_FALSE) { 333 /* mio is a module */ 334 if (!(arg->mi_pwa_flags & MI_PAYLOAD_MODULE)) 335 return (WALK_NEXT); 336 } else { 337 /* mio is a device */ 338 if (!(arg->mi_pwa_flags & MI_PAYLOAD_DEVICE)) 339 return (WALK_NEXT); 340 } 341 342 if (mdb_vread(payload, arg->mi_pwa_size, payload_kaddr) == -1) { 343 mdb_warn("failed to read payload at %p", payload_kaddr); 344 return (WALK_ERR); 345 } 346 347 return (wsp->walk_callback(payload_kaddr, payload, wsp->walk_cbdata)); 348 } 349 350 void 351 mi_payload_walk_fini(mdb_walk_state_t *wsp) 352 { 353 const mi_payload_walk_arg_t *arg = wsp->walk_arg; 354 355 delete_mi_payload_walk_data(wsp->walk_data, arg->mi_pwa_size); 356 } 357 358 const mi_payload_walk_arg_t mi_udp_arg = { 359 "udp", "udp_g_head", sizeof (udp_t), 360 MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE 361 }; 362 363 const mi_payload_walk_arg_t mi_ar_arg = { 364 "arp", "ar_g_head", sizeof (ar_t), 365 MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE 366 }; 367 368 const mi_payload_walk_arg_t mi_icmp_arg = { 369 "icmp", "icmp_g_head", sizeof (icmp_t), 370 MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE 371 }; 372 373 const mi_payload_walk_arg_t mi_ill_arg = 374 { "ip", "ip_g_head", sizeof (ill_t), MI_PAYLOAD_MODULE }; 375 376 int 377 sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 378 { 379 const char *optf = NULL; 380 const char *optt = NULL; 381 const char *optp = NULL; 382 int family, type, proto; 383 int filter = 0; 384 struct sonode so; 385 386 if (!(flags & DCMD_ADDRSPEC)) { 387 if (mdb_walk_dcmd("genunix`sonode", "genunix`sonode", argc, 388 argv) == -1) { 389 mdb_warn("failed to walk sonode"); 390 return (DCMD_ERR); 391 } 392 393 return (DCMD_OK); 394 } 395 396 if (mdb_getopts(argc, argv, 397 'f', MDB_OPT_STR, &optf, 398 't', MDB_OPT_STR, &optt, 399 'p', MDB_OPT_STR, &optp, 400 NULL) != argc) 401 return (DCMD_USAGE); 402 403 if (optf != NULL) { 404 if (strcmp("inet", optf) == 0) 405 family = AF_INET; 406 else if (strcmp("inet6", optf) == 0) 407 family = AF_INET6; 408 else if (strcmp("unix", optf) == 0) 409 family = AF_UNIX; 410 else 411 family = mdb_strtoull(optf); 412 filter = 1; 413 } 414 415 if (optt != NULL) { 416 if (strcmp("stream", optt) == 0) 417 type = SOCK_STREAM; 418 else if (strcmp("dgram", optt) == 0) 419 type = SOCK_DGRAM; 420 else if (strcmp("raw", optt) == 0) 421 type = SOCK_RAW; 422 else 423 type = mdb_strtoull(optt); 424 filter = 1; 425 } 426 427 if (optp != NULL) { 428 proto = mdb_strtoull(optp); 429 filter = 1; 430 } 431 432 if (DCMD_HDRSPEC(flags) && !filter) { 433 mdb_printf("%<u>%-?s Family Type Proto State Mode Flag " 434 "AccessVP%</u>\n", "Sonode:"); 435 } 436 437 if (mdb_vread(&so, sizeof (so), addr) == -1) { 438 mdb_warn("failed to read sonode at %p", addr); 439 return (DCMD_ERR); 440 } 441 442 if ((optf != NULL) && (so.so_family != family)) 443 return (DCMD_OK); 444 445 if ((optt != NULL) && (so.so_type != type)) 446 return (DCMD_OK); 447 448 if ((optp != NULL) && (so.so_protocol != proto)) 449 return (DCMD_OK); 450 451 if (filter) { 452 mdb_printf("%0?p\n", addr); 453 return (DCMD_OK); 454 } 455 456 mdb_printf("%0?p ", addr); 457 458 switch (so.so_family) { 459 case AF_UNIX: 460 mdb_printf("unix "); 461 break; 462 case AF_INET: 463 mdb_printf("inet "); 464 break; 465 case AF_INET6: 466 mdb_printf("inet6 "); 467 break; 468 default: 469 mdb_printf("%6hi", so.so_family); 470 } 471 472 switch (so.so_type) { 473 case SOCK_STREAM: 474 mdb_printf(" strm"); 475 break; 476 case SOCK_DGRAM: 477 mdb_printf(" dgrm"); 478 break; 479 case SOCK_RAW: 480 mdb_printf(" raw "); 481 break; 482 default: 483 mdb_printf(" %4hi", so.so_type); 484 } 485 486 mdb_printf(" %5hi %05x %04x %04hx %0?p\n", 487 so.so_protocol, so.so_state, so.so_mode, 488 so.so_flag, so.so_accessvp); 489 490 return (DCMD_OK); 491 } 492 493 #define MI_PAYLOAD 0x1 494 #define MI_DEVICE 0x2 495 #define MI_MODULE 0x4 496 497 int 498 mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 499 { 500 uint_t opts = 0; 501 MI_O mio; 502 503 if (!(flags & DCMD_ADDRSPEC)) 504 return (DCMD_USAGE); 505 506 if (mdb_getopts(argc, argv, 507 'p', MDB_OPT_SETBITS, MI_PAYLOAD, &opts, 508 'd', MDB_OPT_SETBITS, MI_DEVICE, &opts, 509 'm', MDB_OPT_SETBITS, MI_MODULE, &opts, 510 NULL) != argc) 511 return (DCMD_USAGE); 512 513 if ((opts & (MI_DEVICE | MI_MODULE)) == (MI_DEVICE | MI_MODULE)) { 514 mdb_warn("at most one filter, d for devices or m " 515 "for modules, may be specified\n"); 516 return (DCMD_USAGE); 517 } 518 519 if ((opts == 0) && (DCMD_HDRSPEC(flags))) { 520 mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n", 521 "MI_O", "Next", "Prev"); 522 } 523 524 if (mdb_vread(&mio, sizeof (mio), addr) == -1) { 525 mdb_warn("failed to read mi object MI_O at %p", addr); 526 return (DCMD_ERR); 527 } 528 529 if (opts != 0) { 530 if (mio.mi_o_isdev == B_FALSE) { 531 /* mio is a module */ 532 if (!(opts & MI_MODULE) && (opts & MI_DEVICE)) 533 return (DCMD_OK); 534 } else { 535 /* mio is a device */ 536 if (!(opts & MI_DEVICE) && (opts & MI_MODULE)) 537 return (DCMD_OK); 538 } 539 540 if (opts & MI_PAYLOAD) 541 mdb_printf("%p\n", addr + sizeof (MI_O)); 542 else 543 mdb_printf("%p\n", addr); 544 return (DCMD_OK); 545 } 546 547 mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev); 548 549 if (mio.mi_o_isdev == B_FALSE) 550 mdb_printf("FALSE"); 551 else 552 mdb_printf("TRUE "); 553 554 mdb_printf(" %0?p\n", mio.mi_o_dev); 555 556 return (DCMD_OK); 557 } 558 559 static void 560 netstat_tcp_verbose_pr(const tcp_t *tcp) 561 { 562 mdb_printf(" %5i %08x %08x %5i %08x %08x %5li %5i\n", 563 tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd, 564 tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss); 565 } 566 567 /*ARGSUSED*/ 568 static int 569 netstat_tcp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data, int af) 570 { 571 const uintptr_t opts = (uintptr_t)cb_data; 572 static size_t itc_size = 0; 573 uintptr_t tcp_kaddr; 574 conn_t *connp; 575 tcp_t *tcp; 576 577 if (itc_size == 0) { 578 mdb_ctf_id_t id; 579 580 if (mdb_ctf_lookup_by_name("itc_t", &id) != 0) { 581 mdb_warn("failed to lookup type 'itc_t'"); 582 return (WALK_ERR); 583 } 584 itc_size = mdb_ctf_type_size(id); 585 } 586 587 connp = (conn_t *)mdb_alloc(itc_size, UM_SLEEP | UM_GC); 588 589 if (mdb_vread(connp, itc_size, kaddr) == -1) { 590 mdb_warn("failed to read connection info at %p", kaddr); 591 return (WALK_ERR); 592 } 593 594 tcp_kaddr = (uintptr_t)connp->conn_tcp; 595 tcp = (tcp_t *)((uintptr_t)connp + (tcp_kaddr - kaddr)); 596 597 if ((uintptr_t)tcp < (uintptr_t)connp || 598 (uintptr_t)&tcp->tcp_connp > (uintptr_t)connp + itc_size || 599 (uintptr_t)tcp->tcp_connp != kaddr) { 600 mdb_warn("conn_tcp %p is invalid", tcp_kaddr); 601 return (WALK_NEXT); 602 } 603 connp->conn_tcp = tcp; 604 tcp->tcp_connp = connp; 605 606 if (!(opts & NETSTAT_ALL || net_tcp_active(tcp)) || 607 (af == AF_INET && !net_tcp_ipv4(tcp)) || 608 (af == AF_INET6 && !net_tcp_ipv6(tcp))) { 609 return (WALK_NEXT); 610 } 611 612 mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state); 613 if (af == AF_INET) { 614 net_ipv4addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport); 615 mdb_printf(" "); 616 net_ipv4addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport); 617 } else if (af == AF_INET6) { 618 net_ipv6addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport); 619 mdb_printf(" "); 620 net_ipv6addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport); 621 } 622 mdb_printf(" %4i\n", connp->conn_zoneid); 623 624 if (opts & NETSTAT_VERBOSE) 625 netstat_tcp_verbose_pr(tcp); 626 627 return (WALK_NEXT); 628 } 629 630 static int 631 netstat_tcpv4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 632 { 633 return (netstat_tcp_cb(kaddr, walk_data, cb_data, AF_INET)); 634 } 635 636 static int 637 netstat_tcpv6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 638 { 639 return (netstat_tcp_cb(kaddr, walk_data, cb_data, AF_INET6)); 640 } 641 642 static int 643 netstat_udpv4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 644 { 645 const udp_t *udp = walk_data; 646 const uintptr_t opts = (uintptr_t)cb_data; 647 648 if (!((opts & NETSTAT_ALL || net_udp_active(udp)) && net_udp_ipv4(udp))) 649 return (WALK_NEXT); 650 651 mdb_printf("%0?p %2i ", kaddr, udp->udp_state); 652 net_ipv4addrport_pr(&udp->udp_v6src, udp->udp_port); 653 mdb_printf(" "); 654 net_ipv4addrport_pr(&udp->udp_v6dst, udp->udp_dstport); 655 mdb_printf(" %4i\n", udp->udp_zoneid); 656 657 return (WALK_NEXT); 658 } 659 660 static int 661 netstat_udpv6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 662 { 663 const udp_t *udp = walk_data; 664 const uintptr_t opts = (uintptr_t)cb_data; 665 666 if (!((opts & NETSTAT_ALL || net_udp_active(udp)) && net_udp_ipv6(udp))) 667 return (WALK_NEXT); 668 669 mdb_printf("%0?p %2i ", kaddr, udp->udp_state); 670 net_ipv6addrport_pr(&udp->udp_v6src, udp->udp_port); 671 mdb_printf(" "); 672 673 /* Remote */ 674 if (udp->udp_state == TS_DATA_XFER) 675 net_ipv6addrport_pr(&udp->udp_v6dst, udp->udp_dstport); 676 else 677 mdb_printf("%*s.0 ", ADDR_V6_WIDTH, "0:0:0:0:0:0:0:0"); 678 mdb_printf(" %4i\n", udp->udp_zoneid); 679 680 return (WALK_NEXT); 681 } 682 683 /* 684 * print the address of a unix domain socket 685 * 686 * so is the address of a AF_UNIX struct sonode in mdb's address space 687 * soa is the address of the struct soaddr to print 688 * 689 * returns 0 on success, -1 otherwise 690 */ 691 static int 692 netstat_unix_name_pr(const struct sonode *so, const struct soaddr *soa) 693 { 694 const char none[] = " (none)"; 695 696 if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) { 697 if (so->so_state & SS_FADDR_NOXLATE) { 698 mdb_printf("%-14s ", " (socketpair)"); 699 } else { 700 if (soa->soa_len > sizeof (sa_family_t)) { 701 char addr[MAXPATHLEN + 1]; 702 703 if (mdb_readstr(addr, sizeof (addr), 704 (uintptr_t)&soa->soa_sa->sa_data) == -1) { 705 mdb_warn("failed to read unix address " 706 "at %p", &soa->soa_sa->sa_data); 707 return (-1); 708 } 709 710 mdb_printf("%-14s ", addr); 711 } else { 712 mdb_printf("%-14s ", none); 713 } 714 } 715 } else { 716 mdb_printf("%-14s ", none); 717 } 718 719 return (0); 720 } 721 722 /* based on sockfs_snapshot */ 723 /*ARGSUSED*/ 724 static int 725 netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 726 { 727 const struct sonode *so = walk_data; 728 729 if (so->so_accessvp == NULL) 730 return (WALK_NEXT); 731 732 if (so->so_family != AF_UNIX) { 733 mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr); 734 return (WALK_ERR); 735 } 736 737 mdb_printf("%-?p ", kaddr); 738 739 switch (so->so_serv_type) { 740 case T_CLTS: 741 mdb_printf("%-10s ", "dgram"); 742 break; 743 case T_COTS: 744 mdb_printf("%-10s ", "stream"); 745 break; 746 case T_COTS_ORD: 747 mdb_printf("%-10s ", "stream-ord"); 748 break; 749 default: 750 mdb_printf("%-10i ", so->so_serv_type); 751 } 752 753 if ((so->so_state & SS_ISBOUND) && 754 (so->so_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) { 755 mdb_printf("%0?p ", so->so_ux_laddr.soua_vp); 756 } else { 757 mdb_printf("%0?p ", NULL); 758 } 759 760 if ((so->so_state & SS_ISCONNECTED) && 761 (so->so_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) { 762 mdb_printf("%0?p ", so->so_ux_faddr.soua_vp); 763 } else { 764 mdb_printf("%0?p ", NULL); 765 } 766 767 if (netstat_unix_name_pr(so, &so->so_laddr) == -1) 768 return (WALK_ERR); 769 770 if (netstat_unix_name_pr(so, &so->so_faddr) == -1) 771 return (WALK_ERR); 772 773 mdb_printf("%4i\n", so->so_zoneid); 774 775 return (WALK_NEXT); 776 } 777 778 static void 779 netstat_tcp_verbose_header_pr(void) 780 { 781 mdb_printf(" %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n", 782 "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss"); 783 } 784 785 /*ARGSUSED*/ 786 int 787 netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 788 { 789 uint_t opts = 0; 790 const char *optf = NULL; 791 const char *optP = NULL; 792 793 if (mdb_getopts(argc, argv, 794 'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts, 795 'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts, 796 'f', MDB_OPT_STR, &optf, 797 'P', MDB_OPT_STR, &optP, 798 NULL) != argc) 799 return (DCMD_USAGE); 800 801 if (optP != NULL) { 802 if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0)) 803 return (DCMD_USAGE); 804 805 } 806 807 if (optf != NULL) { 808 if ((strcmp("inet", optf) != 0) && 809 (strcmp("inet6", optf) != 0) && 810 (strcmp("unix", optf) != 0)) 811 return (DCMD_USAGE); 812 } 813 814 if ((optP == NULL) || (strcmp("tcp", optP) == 0)) { 815 if ((optf == NULL) || (strcmp("inet", optf) == 0)) { 816 /* Print TCPv4 connection */ 817 mdb_printf( 818 "%<u>%-?s St %*s %*s %s%</u>\n", 819 "TCPv4", ADDR_V4_WIDTH, "Local Address", 820 ADDR_V4_WIDTH, "Remote Address", "Zone"); 821 822 if (opts & NETSTAT_VERBOSE) 823 netstat_tcp_verbose_header_pr(); 824 825 if (mdb_walk("ipcl_tcpconn_cache", netstat_tcpv4_cb, 826 (void *)(uintptr_t)opts) == -1) { 827 mdb_warn("failed to walk ipcl_tcpconn_cache"); 828 return (DCMD_ERR); 829 } 830 } 831 832 if ((optf == NULL) || (strcmp("inet6", optf) == 0)) { 833 /* Print TCPv6 connection */ 834 mdb_printf( 835 "%<u>%-?s St %*s %*s %s\n%</u>", 836 "TCPv6", ADDR_V6_WIDTH, "Local Address", 837 ADDR_V6_WIDTH, "Remote Address", "Zone"); 838 839 if (opts & NETSTAT_VERBOSE) 840 netstat_tcp_verbose_header_pr(); 841 842 if (mdb_walk("ipcl_tcpconn_cache", netstat_tcpv6_cb, 843 (void *)(uintptr_t)opts) == -1) { 844 mdb_warn("failed to walk ipcl_tcpconn_cache"); 845 return (DCMD_ERR); 846 } 847 } 848 } 849 850 if ((optP == NULL) || (strcmp("udp", optP) == 0)) { 851 if ((optf == NULL) || (strcmp("inet", optf) == 0)) { 852 /* Print UDPv4 connection */ 853 mdb_printf( 854 "%<u>%-?s St %*s %*s %s\n%</u>", 855 "UDPv4", ADDR_V4_WIDTH, "Local Address", 856 ADDR_V4_WIDTH, "Remote Address", "Zone"); 857 858 if (mdb_walk("genunix`udp", netstat_udpv4_cb, 859 (void *)(uintptr_t)opts) == -1) { 860 mdb_warn("failed to walk genunix`udp"); 861 return (DCMD_ERR); 862 } 863 864 } 865 866 if ((optf == NULL) || (strcmp("inet6", optf) == 0)) { 867 /* Print UDPv6 connection */ 868 mdb_printf( 869 "%<u>%-?s St %*s %*s %s\n%</u>", 870 "UDPv6", ADDR_V6_WIDTH, "Local Address", 871 ADDR_V6_WIDTH, "Remote Address", "Zone"); 872 873 if (mdb_walk("genunix`udp", netstat_udpv6_cb, 874 (void *)(uintptr_t)opts) == -1) { 875 mdb_warn("failed to walk genunix`udp"); 876 return (DCMD_ERR); 877 } 878 879 } 880 } 881 882 if (((optf == NULL) || (strcmp("unix", optf) == 0)) && (optP == NULL)) { 883 /* Print Unix Domain Sockets */ 884 mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n", 885 "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr", 886 "Remote Addr", "Zone"); 887 888 if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) { 889 mdb_warn("failed to walk genunix`sonode"); 890 return (DCMD_ERR); 891 } 892 } 893 894 return (DCMD_OK); 895 } 896