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