1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <mdb/mdb_modapi.h>
  27 #include <mdb/mdb_ks.h>
  28 #include <mdb/mdb_ctf.h>
  29 #include <sys/types.h>
  30 #include <sys/tihdr.h>
  31 #include <inet/led.h>
  32 #include <inet/common.h>
  33 #include <netinet/in.h>
  34 #include <netinet/ip6.h>
  35 #include <netinet/icmp6.h>
  36 #include <inet/ip.h>
  37 #include <inet/ip6.h>
  38 #include <inet/ipclassifier.h>
  39 #include <inet/tcp.h>
  40 #include <sys/stream.h>
  41 #include <sys/vfs.h>
  42 #include <sys/stropts.h>
  43 #include <sys/tpicommon.h>
  44 #include <sys/socket.h>
  45 #include <sys/socketvar.h>
  46 #include <sys/cred_impl.h>
  47 #include <inet/udp_impl.h>
  48 #include <inet/rawip_impl.h>
  49 #include <inet/mi.h>
  50 #include <inet/dccp_impl.h>
  51 #include <fs/sockfs/socktpi_impl.h>
  52 #include <net/bridge_impl.h>
  53 #include <io/trill_impl.h>
  54 #include <sys/mac_impl.h>
  55 
  56 #define ADDR_V6_WIDTH   23
  57 #define ADDR_V4_WIDTH   15
  58 
  59 #define NETSTAT_ALL     0x01
  60 #define NETSTAT_VERBOSE 0x02
  61 #define NETSTAT_ROUTE   0x04
  62 #define NETSTAT_V4      0x08
  63 #define NETSTAT_V6      0x10
  64 #define NETSTAT_UNIX    0x20
  65 
  66 #define NETSTAT_FIRST   0x80000000u
  67 
  68 typedef struct netstat_cb_data_s {
  69         uint_t  opts;
  70         conn_t  conn;
  71         int     af;
  72 } netstat_cb_data_t;
  73 
  74 int
  75 icmp_stacks_walk_init(mdb_walk_state_t *wsp)
  76 {
  77         if (mdb_layered_walk("netstack", wsp) == -1) {
  78                 mdb_warn("can't walk 'netstack'");
  79                 return (WALK_ERR);
  80         }
  81         return (WALK_NEXT);
  82 }
  83 
  84 int
  85 icmp_stacks_walk_step(mdb_walk_state_t *wsp)
  86 {
  87         uintptr_t kaddr;
  88         netstack_t nss;
  89 
  90         if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
  91                 mdb_warn("can't read netstack at %p", wsp->walk_addr);
  92                 return (WALK_ERR);
  93         }
  94         kaddr = (uintptr_t)nss.netstack_modules[NS_ICMP];
  95         return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
  96 }
  97 
  98 int
  99 tcp_stacks_walk_init(mdb_walk_state_t *wsp)
 100 {
 101         if (mdb_layered_walk("netstack", wsp) == -1) {
 102                 mdb_warn("can't walk 'netstack'");
 103                 return (WALK_ERR);
 104         }
 105         return (WALK_NEXT);
 106 }
 107 
 108 int
 109 tcp_stacks_walk_step(mdb_walk_state_t *wsp)
 110 {
 111         uintptr_t kaddr;
 112         netstack_t nss;
 113 
 114         if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
 115                 mdb_warn("can't read netstack at %p", wsp->walk_addr);
 116                 return (WALK_ERR);
 117         }
 118         kaddr = (uintptr_t)nss.netstack_modules[NS_TCP];
 119         return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
 120 }
 121 
 122 int
 123 udp_stacks_walk_init(mdb_walk_state_t *wsp)
 124 {
 125         if (mdb_layered_walk("netstack", wsp) == -1) {
 126                 mdb_warn("can't walk 'netstack'");
 127                 return (WALK_ERR);
 128         }
 129         return (WALK_NEXT);
 130 }
 131 
 132 int
 133 udp_stacks_walk_step(mdb_walk_state_t *wsp)
 134 {
 135         uintptr_t kaddr;
 136         netstack_t nss;
 137 
 138         if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
 139                 mdb_warn("can't read netstack at %p", wsp->walk_addr);
 140                 return (WALK_ERR);
 141         }
 142         kaddr = (uintptr_t)nss.netstack_modules[NS_UDP];
 143         return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
 144 }
 145 
 146 int
 147 dccp_stacks_walk_init(mdb_walk_state_t *wsp)
 148 {
 149         if (mdb_layered_walk("netstack", wsp) == -1) {
 150                 mdb_warn("can't walk 'netstack'");
 151                 return (WALK_ERR);
 152         }
 153         return (WALK_NEXT);
 154 }
 155 
 156 int
 157 dccp_stacks_walk_step(mdb_walk_state_t *wsp)
 158 {
 159         uintptr_t kaddr;
 160         netstack_t nss;
 161 
 162         if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
 163                 mdb_warn("can't read netstack at %p", wsp->walk_addr);
 164                 return (WALK_ERR);
 165         }
 166         kaddr = (uintptr_t)nss.netstack_modules[NS_DCCP];
 167         return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
 168 }
 169 
 170 /*
 171  * Print an IPv4 address and port number in a compact and easy to read format
 172  * The arguments are in network byte order
 173  */
 174 static void
 175 net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport)
 176 {
 177         uint32_t naddr = V4_PART_OF_V6((*nipv6addr));
 178 
 179         mdb_nhconvert(&nport, &nport, sizeof (nport));
 180         mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport);
 181 }
 182 
 183 /*
 184  * Print an IPv6 address and port number in a compact and easy to read format
 185  * The arguments are in network byte order
 186  */
 187 static void
 188 net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport)
 189 {
 190         mdb_nhconvert(&nport, &nport, sizeof (nport));
 191         mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport);
 192 }
 193 
 194 static int
 195 net_tcp_active(const tcp_t *tcp)
 196 {
 197         return (tcp->tcp_state >= TCPS_ESTABLISHED);
 198 }
 199 
 200 static int
 201 net_tcp_ipv4(const tcp_t *tcp)
 202 {
 203         return ((tcp->tcp_connp->conn_ipversion == IPV4_VERSION) ||
 204             (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_connp->conn_laddr_v6) &&
 205             (tcp->tcp_state <= TCPS_LISTEN)));
 206 }
 207 
 208 static int
 209 net_tcp_ipv6(const tcp_t *tcp)
 210 {
 211         return (tcp->tcp_connp->conn_ipversion == IPV6_VERSION);
 212 }
 213 
 214 static int
 215 net_udp_active(const udp_t *udp)
 216 {
 217         return ((udp->udp_state == TS_IDLE) ||
 218             (udp->udp_state == TS_DATA_XFER));
 219 }
 220 
 221 static int
 222 net_udp_ipv4(const udp_t *udp)
 223 {
 224         return ((udp->udp_connp->conn_ipversion == IPV4_VERSION) ||
 225             (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_connp->conn_laddr_v6) &&
 226             (udp->udp_state <= TS_IDLE)));
 227 }
 228 
 229 static int
 230 net_udp_ipv6(const udp_t *udp)
 231 {
 232         return (udp->udp_connp->conn_ipversion == IPV6_VERSION);
 233 }
 234 
 235 static int
 236 net_dccp_active(const dccp_t *dccp)
 237 {
 238         return ((dccp->dccp_state == TS_IDLE) ||
 239             (dccp->dccp_state == TS_DATA_XFER));
 240 }
 241 
 242 static int
 243 net_dccp_ipv4(const dccp_t *dccp)
 244 {
 245         return ((dccp->dccp_connp->conn_ipversion == IPV4_VERSION) ||
 246             (IN6_IS_ADDR_UNSPECIFIED(&dccp->dccp_connp->conn_laddr_v6) &&
 247             (dccp->dccp_state <= DCCPS_LISTEN)));
 248 }
 249 
 250 static int
 251 net_dccp_ipv6(const dccp_t *dccp)
 252 {
 253         return (dccp->dccp_connp->conn_ipversion == IPV6_VERSION);
 254 }
 255 
 256 int
 257 sonode_walk_init(mdb_walk_state_t *wsp)
 258 {
 259         if (wsp->walk_addr == NULL) {
 260                 GElf_Sym sym;
 261                 struct socklist *slp;
 262 
 263                 if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) {
 264                         mdb_warn("failed to lookup sockfs`socklist");
 265                         return (WALK_ERR);
 266                 }
 267 
 268                 slp = (struct socklist *)(uintptr_t)sym.st_value;
 269 
 270                 if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),
 271                     (uintptr_t)&slp->sl_list) == -1) {
 272                         mdb_warn("failed to read address of initial sonode "
 273                             "at %p", &slp->sl_list);
 274                         return (WALK_ERR);
 275                 }
 276         }
 277 
 278         wsp->walk_data = mdb_alloc(sizeof (struct sotpi_sonode), UM_SLEEP);
 279         return (WALK_NEXT);
 280 }
 281 
 282 int
 283 sonode_walk_step(mdb_walk_state_t *wsp)
 284 {
 285         int status;
 286         struct sotpi_sonode *stp;
 287 
 288         if (wsp->walk_addr == NULL)
 289                 return (WALK_DONE);
 290 
 291         if (mdb_vread(wsp->walk_data, sizeof (struct sotpi_sonode),
 292             wsp->walk_addr) == -1) {
 293                 mdb_warn("failed to read sonode at %p", wsp->walk_addr);
 294                 return (WALK_ERR);
 295         }
 296 
 297         status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
 298             wsp->walk_cbdata);
 299 
 300         stp = wsp->walk_data;
 301 
 302         wsp->walk_addr = (uintptr_t)stp->st_info.sti_next_so;
 303         return (status);
 304 }
 305 
 306 void
 307 sonode_walk_fini(mdb_walk_state_t *wsp)
 308 {
 309         mdb_free(wsp->walk_data, sizeof (struct sotpi_sonode));
 310 }
 311 
 312 struct mi_walk_data {
 313         uintptr_t mi_wd_miofirst;
 314         MI_O mi_wd_miodata;
 315 };
 316 
 317 int
 318 mi_walk_init(mdb_walk_state_t *wsp)
 319 {
 320         struct mi_walk_data *wdp;
 321 
 322         if (wsp->walk_addr == NULL) {
 323                 mdb_warn("mi doesn't support global walks\n");
 324                 return (WALK_ERR);
 325         }
 326 
 327         wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP);
 328 
 329         /* So that we do not immediately return WALK_DONE below */
 330         wdp->mi_wd_miofirst = NULL;
 331 
 332         wsp->walk_data = wdp;
 333         return (WALK_NEXT);
 334 }
 335 
 336 int
 337 mi_walk_step(mdb_walk_state_t *wsp)
 338 {
 339         struct mi_walk_data *wdp = wsp->walk_data;
 340         MI_OP miop = &wdp->mi_wd_miodata;
 341         int status;
 342 
 343         /* Always false in the first iteration */
 344         if ((wsp->walk_addr == (uintptr_t)NULL) ||
 345             (wsp->walk_addr == wdp->mi_wd_miofirst)) {
 346                 return (WALK_DONE);
 347         }
 348 
 349         if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) {
 350                 mdb_warn("failed to read MI object at %p", wsp->walk_addr);
 351                 return (WALK_ERR);
 352         }
 353 
 354         /* Only true in the first iteration */
 355         if (wdp->mi_wd_miofirst == NULL) {
 356                 wdp->mi_wd_miofirst = wsp->walk_addr;
 357                 status = WALK_NEXT;
 358         } else {
 359                 status = wsp->walk_callback(wsp->walk_addr + sizeof (MI_O),
 360                     &miop[1], wsp->walk_cbdata);
 361         }
 362 
 363         wsp->walk_addr = (uintptr_t)miop->mi_o_next;
 364         return (status);
 365 }
 366 
 367 void
 368 mi_walk_fini(mdb_walk_state_t *wsp)
 369 {
 370         mdb_free(wsp->walk_data, sizeof (struct mi_walk_data));
 371 }
 372 
 373 typedef struct mi_payload_walk_arg_s {
 374         const char *mi_pwa_walker;      /* Underlying walker */
 375         const off_t mi_pwa_head_off;    /* Offset for mi_o_head_t * in stack */
 376         const size_t mi_pwa_size;       /* size of mi payload */
 377         const uint_t mi_pwa_flags;      /* device and/or module */
 378 } mi_payload_walk_arg_t;
 379 
 380 #define MI_PAYLOAD_DEVICE       0x1
 381 #define MI_PAYLOAD_MODULE       0x2
 382 
 383 int
 384 mi_payload_walk_init(mdb_walk_state_t *wsp)
 385 {
 386         const mi_payload_walk_arg_t *arg = wsp->walk_arg;
 387 
 388         if (mdb_layered_walk(arg->mi_pwa_walker, wsp) == -1) {
 389                 mdb_warn("can't walk '%s'", arg->mi_pwa_walker);
 390                 return (WALK_ERR);
 391         }
 392         return (WALK_NEXT);
 393 }
 394 
 395 int
 396 mi_payload_walk_step(mdb_walk_state_t *wsp)
 397 {
 398         const mi_payload_walk_arg_t *arg = wsp->walk_arg;
 399         uintptr_t kaddr;
 400 
 401         kaddr = wsp->walk_addr + arg->mi_pwa_head_off;
 402 
 403         if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
 404                 mdb_warn("can't read address of mi head at %p for %s",
 405                     kaddr, arg->mi_pwa_walker);
 406                 return (WALK_ERR);
 407         }
 408 
 409         if (kaddr == 0) {
 410                 /* Empty list */
 411                 return (WALK_DONE);
 412         }
 413 
 414         if (mdb_pwalk("genunix`mi", wsp->walk_callback,
 415             wsp->walk_cbdata, kaddr) == -1) {
 416                 mdb_warn("failed to walk genunix`mi");
 417                 return (WALK_ERR);
 418         }
 419         return (WALK_NEXT);
 420 }
 421 
 422 const mi_payload_walk_arg_t mi_icmp_arg = {
 423         "icmp_stacks", OFFSETOF(icmp_stack_t, is_head), sizeof (icmp_t),
 424         MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
 425 };
 426 
 427 int
 428 sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 429 {
 430         const char *optf = NULL;
 431         const char *optt = NULL;
 432         const char *optp = NULL;
 433         int family, type, proto;
 434         int filter = 0;
 435         struct sonode so;
 436 
 437         if (!(flags & DCMD_ADDRSPEC)) {
 438                 if (mdb_walk_dcmd("genunix`sonode", "genunix`sonode", argc,
 439                     argv) == -1) {
 440                         mdb_warn("failed to walk sonode");
 441                         return (DCMD_ERR);
 442                 }
 443 
 444                 return (DCMD_OK);
 445         }
 446 
 447         if (mdb_getopts(argc, argv,
 448             'f', MDB_OPT_STR, &optf,
 449             't', MDB_OPT_STR, &optt,
 450             'p', MDB_OPT_STR, &optp,
 451             NULL) != argc)
 452                 return (DCMD_USAGE);
 453 
 454         if (optf != NULL) {
 455                 if (strcmp("inet", optf) == 0)
 456                         family = AF_INET;
 457                 else if (strcmp("inet6", optf) == 0)
 458                         family = AF_INET6;
 459                 else if (strcmp("unix", optf) == 0)
 460                         family = AF_UNIX;
 461                 else
 462                         family = mdb_strtoull(optf);
 463                 filter = 1;
 464         }
 465 
 466         if (optt != NULL) {
 467                 if (strcmp("stream", optt) == 0)
 468                         type = SOCK_STREAM;
 469                 else if (strcmp("dgram", optt) == 0)
 470                         type = SOCK_DGRAM;
 471                 else if (strcmp("raw", optt) == 0)
 472                         type = SOCK_RAW;
 473                 else
 474                         type = mdb_strtoull(optt);
 475                 filter = 1;
 476         }
 477 
 478         if (optp != NULL) {
 479                 proto = mdb_strtoull(optp);
 480                 filter = 1;
 481         }
 482 
 483         if (DCMD_HDRSPEC(flags) && !filter) {
 484                 mdb_printf("%<u>%-?s Family Type Proto State Mode Flag "
 485                     "AccessVP%</u>\n", "Sonode:");
 486         }
 487 
 488         if (mdb_vread(&so, sizeof (so), addr) == -1) {
 489                 mdb_warn("failed to read sonode at %p", addr);
 490                 return (DCMD_ERR);
 491         }
 492 
 493         if ((optf != NULL) && (so.so_family != family))
 494                 return (DCMD_OK);
 495 
 496         if ((optt != NULL) && (so.so_type != type))
 497                 return (DCMD_OK);
 498 
 499         if ((optp != NULL) && (so.so_protocol != proto))
 500                 return (DCMD_OK);
 501 
 502         if (filter) {
 503                 mdb_printf("%0?p\n", addr);
 504                 return (DCMD_OK);
 505         }
 506 
 507         mdb_printf("%0?p ", addr);
 508 
 509         switch (so.so_family) {
 510         case AF_UNIX:
 511                 mdb_printf("unix  ");
 512                 break;
 513         case AF_INET:
 514                 mdb_printf("inet  ");
 515                 break;
 516         case AF_INET6:
 517                 mdb_printf("inet6 ");
 518                 break;
 519         default:
 520                 mdb_printf("%6hi", so.so_family);
 521         }
 522 
 523         switch (so.so_type) {
 524         case SOCK_STREAM:
 525                 mdb_printf(" strm");
 526                 break;
 527         case SOCK_DGRAM:
 528                 mdb_printf(" dgrm");
 529                 break;
 530         case SOCK_RAW:
 531                 mdb_printf(" raw ");
 532                 break;
 533         default:
 534                 mdb_printf(" %4hi", so.so_type);
 535         }
 536 
 537         mdb_printf(" %5hi %05x %04x %04hx\n",
 538             so.so_protocol, so.so_state, so.so_mode,
 539             so.so_flag);
 540 
 541         return (DCMD_OK);
 542 }
 543 
 544 #define MI_PAYLOAD      0x1
 545 #define MI_DEVICE       0x2
 546 #define MI_MODULE       0x4
 547 
 548 int
 549 mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 550 {
 551         uint_t opts = 0;
 552         MI_O    mio;
 553 
 554         if (!(flags & DCMD_ADDRSPEC))
 555                 return (DCMD_USAGE);
 556 
 557         if (mdb_getopts(argc, argv,
 558             'p', MDB_OPT_SETBITS, MI_PAYLOAD, &opts,
 559             'd', MDB_OPT_SETBITS, MI_DEVICE, &opts,
 560             'm', MDB_OPT_SETBITS, MI_MODULE, &opts,
 561             NULL) != argc)
 562                 return (DCMD_USAGE);
 563 
 564         if ((opts & (MI_DEVICE | MI_MODULE)) == (MI_DEVICE | MI_MODULE)) {
 565                 mdb_warn("at most one filter, d for devices or m "
 566                     "for modules, may be specified\n");
 567                 return (DCMD_USAGE);
 568         }
 569 
 570         if ((opts == 0) && (DCMD_HDRSPEC(flags))) {
 571                 mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n",
 572                     "MI_O", "Next", "Prev");
 573         }
 574 
 575         if (mdb_vread(&mio, sizeof (mio), addr) == -1) {
 576                 mdb_warn("failed to read mi object MI_O at %p", addr);
 577                 return (DCMD_ERR);
 578         }
 579 
 580         if (opts != 0) {
 581                 if (mio.mi_o_isdev == B_FALSE) {
 582                         /* mio is a module */
 583                         if (!(opts & MI_MODULE) && (opts & MI_DEVICE))
 584                                 return (DCMD_OK);
 585                 } else {
 586                         /* mio is a device */
 587                         if (!(opts & MI_DEVICE) && (opts & MI_MODULE))
 588                                 return (DCMD_OK);
 589                 }
 590 
 591                 if (opts & MI_PAYLOAD)
 592                         mdb_printf("%p\n", addr + sizeof (MI_O));
 593                 else
 594                         mdb_printf("%p\n", addr);
 595                 return (DCMD_OK);
 596         }
 597 
 598         mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev);
 599 
 600         if (mio.mi_o_isdev == B_FALSE)
 601                 mdb_printf("FALSE");
 602         else
 603                 mdb_printf("TRUE ");
 604 
 605         mdb_printf(" %0?p\n", mio.mi_o_dev);
 606 
 607         return (DCMD_OK);
 608 }
 609 
 610 static int
 611 ns_to_stackid(uintptr_t kaddr)
 612 {
 613         netstack_t nss;
 614 
 615         if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
 616                 mdb_warn("failed to read netstack_t %p", kaddr);
 617                 return (0);
 618         }
 619         return (nss.netstack_stackid);
 620 }
 621 
 622 
 623 
 624 static void
 625 netstat_tcp_verbose_pr(const tcp_t *tcp)
 626 {
 627         mdb_printf("       %5i %08x %08x %5i %08x %08x %5li %5i\n",
 628             tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
 629             tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
 630 }
 631 
 632 /*ARGSUSED*/
 633 static int
 634 netstat_tcp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
 635 {
 636         netstat_cb_data_t *ncb = cb_data;
 637         uint_t opts = ncb->opts;
 638         int af = ncb->af;
 639         uintptr_t tcp_kaddr;
 640         conn_t *connp = &ncb->conn;
 641         tcp_t tcps, *tcp;
 642 
 643         if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
 644                 mdb_warn("failed to read conn_t at %p", kaddr);
 645                 return (WALK_ERR);
 646         }
 647 
 648         tcp_kaddr = (uintptr_t)connp->conn_tcp;
 649         if (mdb_vread(&tcps, sizeof (tcp_t), tcp_kaddr) == -1) {
 650                 mdb_warn("failed to read tcp_t at %p", tcp_kaddr);
 651                 return (WALK_ERR);
 652         }
 653 
 654         tcp = &tcps;
 655         connp->conn_tcp = tcp;
 656         tcp->tcp_connp = connp;
 657 
 658         if (!((opts & NETSTAT_ALL) || net_tcp_active(tcp)) ||
 659             (af == AF_INET && !net_tcp_ipv4(tcp)) ||
 660             (af == AF_INET6 && !net_tcp_ipv6(tcp))) {
 661                 return (WALK_NEXT);
 662         }
 663 
 664         mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state);
 665         if (af == AF_INET) {
 666                 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
 667                 mdb_printf(" ");
 668                 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
 669         } else if (af == AF_INET6) {
 670                 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
 671                 mdb_printf(" ");
 672                 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
 673         }
 674         mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
 675         mdb_printf(" %4i\n", connp->conn_zoneid);
 676         if (opts & NETSTAT_VERBOSE)
 677                 netstat_tcp_verbose_pr(tcp);
 678 
 679         return (WALK_NEXT);
 680 }
 681 
 682 /*ARGSUSED*/
 683 static int
 684 netstat_udp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
 685 {
 686         netstat_cb_data_t *ncb = cb_data;
 687         uint_t opts = ncb->opts;
 688         int af = ncb->af;
 689         udp_t udp;
 690         conn_t *connp = &ncb->conn;
 691         char *state;
 692 
 693         if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
 694                 mdb_warn("failed to read conn_t at %p", kaddr);
 695                 return (WALK_ERR);
 696         }
 697 
 698         if (mdb_vread(&udp, sizeof (udp_t),
 699             (uintptr_t)connp->conn_udp) == -1) {
 700                 mdb_warn("failed to read conn_udp at %p",
 701                     (uintptr_t)connp->conn_udp);
 702                 return (WALK_ERR);
 703         }
 704 
 705         connp->conn_udp = &udp;
 706         udp.udp_connp = connp;
 707 
 708         if (!((opts & NETSTAT_ALL) || net_udp_active(&udp)) ||
 709             (af == AF_INET && !net_udp_ipv4(&udp)) ||
 710             (af == AF_INET6 && !net_udp_ipv6(&udp))) {
 711                 return (WALK_NEXT);
 712         }
 713 
 714         if (udp.udp_state == TS_UNBND)
 715                 state = "UNBOUND";
 716         else if (udp.udp_state == TS_IDLE)
 717                 state = "IDLE";
 718         else if (udp.udp_state == TS_DATA_XFER)
 719                 state = "CONNECTED";
 720         else
 721                 state = "UNKNOWN";
 722 
 723         mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_udp, state);
 724         if (af == AF_INET) {
 725                 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
 726                 mdb_printf(" ");
 727                 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
 728         } else if (af == AF_INET6) {
 729                 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
 730                 mdb_printf(" ");
 731                 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
 732         }
 733         mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
 734         mdb_printf(" %4i\n", connp->conn_zoneid);
 735 
 736         return (WALK_NEXT);
 737 }
 738 
 739 /*ARGSUSED*/
 740 static int
 741 netstat_icmp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
 742 {
 743         netstat_cb_data_t *ncb = cb_data;
 744         int af = ncb->af;
 745         icmp_t icmp;
 746         conn_t *connp = &ncb->conn;
 747         char *state;
 748 
 749         if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
 750                 mdb_warn("failed to read conn_t at %p", kaddr);
 751                 return (WALK_ERR);
 752         }
 753 
 754         if (mdb_vread(&icmp, sizeof (icmp_t),
 755             (uintptr_t)connp->conn_icmp) == -1) {
 756                 mdb_warn("failed to read conn_icmp at %p",
 757                     (uintptr_t)connp->conn_icmp);
 758                 return (WALK_ERR);
 759         }
 760 
 761         connp->conn_icmp = &icmp;
 762         icmp.icmp_connp = connp;
 763 
 764         if ((af == AF_INET && connp->conn_ipversion != IPV4_VERSION) ||
 765             (af == AF_INET6 && connp->conn_ipversion != IPV6_VERSION)) {
 766                 return (WALK_NEXT);
 767         }
 768 
 769         if (icmp.icmp_state == TS_UNBND)
 770                 state = "UNBOUND";
 771         else if (icmp.icmp_state == TS_IDLE)
 772                 state = "IDLE";
 773         else if (icmp.icmp_state == TS_DATA_XFER)
 774                 state = "CONNECTED";
 775         else
 776                 state = "UNKNOWN";
 777 
 778         mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_icmp, state);
 779         if (af == AF_INET) {
 780                 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
 781                 mdb_printf(" ");
 782                 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
 783         } else if (af == AF_INET6) {
 784                 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
 785                 mdb_printf(" ");
 786                 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
 787         }
 788         mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
 789         mdb_printf(" %4i\n", connp->conn_zoneid);
 790 
 791         return (WALK_NEXT);
 792 }
 793 
 794 static void
 795 netstat_dccp_verbose_pr(const dccp_t *dccp)
 796 {
 797 /* XXX:DCCP
 798         mdb_printf("       %5i %08x %08x %5i %08x %08x %5li %5i\n",
 799             tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
 800             tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
 801 */
 802 }
 803 
 804 /*ARGSUSED*/
 805 static int
 806 netstat_dccp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
 807 {
 808         netstat_cb_data_t *ncb = cb_data;
 809         uint_t opts = ncb->opts;
 810         int af = ncb->af;
 811         uintptr_t dccp_kaddr;
 812         conn_t *connp = &ncb->conn;
 813         dccp_t dccps, *dccp;
 814 
 815         if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
 816                 mdb_warn("failed to read conn_t at %p", kaddr);
 817                 return (WALK_ERR);
 818         }
 819 
 820         dccp_kaddr = (uintptr_t)connp->conn_dccp;
 821         if (mdb_vread(&dccps, sizeof (dccp_t), dccp_kaddr) == -1) {
 822                 mdb_warn("failed to read tcp_t at %p", dccp_kaddr);
 823                 return (WALK_ERR);
 824         }
 825 
 826         dccp = &dccps;
 827         connp->conn_dccp = dccp;
 828         dccp->dccp_connp = connp;
 829 
 830         if (!((opts & NETSTAT_ALL) || net_dccp_active(dccp)) ||
 831             (af == AF_INET && !net_dccp_ipv4(dccp)) ||
 832             (af == AF_INET6 && !net_dccp_ipv6(dccp))) {
 833                 return (WALK_NEXT);
 834         }
 835 
 836         mdb_printf("%0?p %2i ", dccp_kaddr, dccp->dccp_state);
 837         if (af == AF_INET) {
 838                 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
 839                 mdb_printf(" ");
 840                 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
 841         } else if (af == AF_INET6) {
 842                 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
 843                 mdb_printf(" ");
 844                 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
 845         }
 846         mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
 847         mdb_printf(" %4i\n", connp->conn_zoneid);
 848         if (opts & NETSTAT_VERBOSE)
 849                 netstat_dccp_verbose_pr(dccp);
 850 
 851         return (WALK_NEXT);
 852 }
 853 
 854 /*
 855  * print the address of a unix domain socket
 856  *
 857  * so is the address of a AF_UNIX struct sonode in mdb's address space
 858  * soa is the address of the struct soaddr to print
 859  *
 860  * returns 0 on success, -1 otherwise
 861  */
 862 static int
 863 netstat_unix_name_pr(const struct sotpi_sonode *st, const struct soaddr *soa)
 864 {
 865         const struct sonode *so = &st->st_sonode;
 866         const char none[] = " (none)";
 867 
 868         if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) {
 869                 if (st->st_info.sti_faddr_noxlate) {
 870                         mdb_printf("%-14s ", " (socketpair)");
 871                 } else {
 872                         if (soa->soa_len > sizeof (sa_family_t)) {
 873                                 char addr[MAXPATHLEN + 1];
 874 
 875                                 if (mdb_readstr(addr, sizeof (addr),
 876                                     (uintptr_t)&soa->soa_sa->sa_data) == -1) {
 877                                         mdb_warn("failed to read unix address "
 878                                             "at %p", &soa->soa_sa->sa_data);
 879                                         return (-1);
 880                                 }
 881 
 882                                 mdb_printf("%-14s ", addr);
 883                         } else {
 884                                 mdb_printf("%-14s ", none);
 885                         }
 886                 }
 887         } else {
 888                 mdb_printf("%-14s ", none);
 889         }
 890 
 891         return (0);
 892 }
 893 
 894 /* based on sockfs_snapshot */
 895 /*ARGSUSED*/
 896 static int
 897 netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
 898 {
 899         const struct sotpi_sonode *st = walk_data;
 900         const struct sonode *so = &st->st_sonode;
 901         const struct sotpi_info *sti = &st->st_info;
 902 
 903         if (so->so_count == 0)
 904                 return (WALK_NEXT);
 905 
 906         if (so->so_family != AF_UNIX) {
 907                 mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr);
 908                 return (WALK_ERR);
 909         }
 910 
 911         mdb_printf("%-?p ", kaddr);
 912 
 913         switch (sti->sti_serv_type) {
 914         case T_CLTS:
 915                 mdb_printf("%-10s ", "dgram");
 916                 break;
 917         case T_COTS:
 918                 mdb_printf("%-10s ", "stream");
 919                 break;
 920         case T_COTS_ORD:
 921                 mdb_printf("%-10s ", "stream-ord");
 922                 break;
 923         default:
 924                 mdb_printf("%-10i ", sti->sti_serv_type);
 925         }
 926 
 927         if ((so->so_state & SS_ISBOUND) &&
 928             (sti->sti_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
 929                 mdb_printf("%0?p ", sti->sti_ux_laddr.soua_vp);
 930         } else {
 931                 mdb_printf("%0?p ", NULL);
 932         }
 933 
 934         if ((so->so_state & SS_ISCONNECTED) &&
 935             (sti->sti_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
 936                 mdb_printf("%0?p ", sti->sti_ux_faddr.soua_vp);
 937         } else {
 938                 mdb_printf("%0?p ", NULL);
 939         }
 940 
 941         if (netstat_unix_name_pr(st, &sti->sti_laddr) == -1)
 942                 return (WALK_ERR);
 943 
 944         if (netstat_unix_name_pr(st, &sti->sti_faddr) == -1)
 945                 return (WALK_ERR);
 946 
 947         mdb_printf("%4i\n", so->so_zoneid);
 948 
 949         return (WALK_NEXT);
 950 }
 951 
 952 static void
 953 netstat_tcp_verbose_header_pr(void)
 954 {
 955         mdb_printf("       %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n",
 956             "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss");
 957 }
 958 
 959 static void
 960 get_ifname(const ire_t *ire, char *intf)
 961 {
 962         ill_t ill;
 963 
 964         *intf = '\0';
 965         if (ire->ire_ill != NULL) {
 966                 if (mdb_vread(&ill, sizeof (ill),
 967                     (uintptr_t)ire->ire_ill) == -1)
 968                         return;
 969                 (void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
 970                     (uintptr_t)ill.ill_name);
 971         }
 972 }
 973 
 974 const in6_addr_t ipv6_all_ones =
 975         { 0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU };
 976 
 977 static void
 978 get_ireflags(const ire_t *ire, char *flags)
 979 {
 980         (void) strcpy(flags, "U");
 981         /* RTF_INDIRECT wins over RTF_GATEWAY - don't display both */
 982         if (ire->ire_flags & RTF_INDIRECT)
 983                 (void) strcat(flags, "I");
 984         else if (ire->ire_type & IRE_OFFLINK)
 985                 (void) strcat(flags, "G");
 986 
 987         /* IRE_IF_CLONE wins over RTF_HOST - don't display both */
 988         if (ire->ire_type & IRE_IF_CLONE)
 989                 (void) strcat(flags, "C");
 990         else if (ire->ire_ipversion == IPV4_VERSION) {
 991                 if (ire->ire_mask == IP_HOST_MASK)
 992                         (void) strcat(flags, "H");
 993         } else {
 994                 if (IN6_ARE_ADDR_EQUAL(&ire->ire_mask_v6, &ipv6_all_ones))
 995                         (void) strcat(flags, "H");
 996         }
 997 
 998         if (ire->ire_flags & RTF_DYNAMIC)
 999                 (void) strcat(flags, "D");
1000         if (ire->ire_type == IRE_BROADCAST)
1001                 (void) strcat(flags, "b");
1002         if (ire->ire_type == IRE_MULTICAST)
1003                 (void) strcat(flags, "m");
1004         if (ire->ire_type == IRE_LOCAL)
1005                 (void) strcat(flags, "L");
1006         if (ire->ire_type == IRE_NOROUTE)
1007                 (void) strcat(flags, "N");
1008         if (ire->ire_flags & RTF_MULTIRT)
1009                 (void) strcat(flags, "M");
1010         if (ire->ire_flags & RTF_SETSRC)
1011                 (void) strcat(flags, "S");
1012         if (ire->ire_flags & RTF_REJECT)
1013                 (void) strcat(flags, "R");
1014         if (ire->ire_flags & RTF_BLACKHOLE)
1015                 (void) strcat(flags, "B");
1016 }
1017 
1018 static int
1019 netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
1020 {
1021         const ire_t *ire = walk_data;
1022         uint_t *opts = cb_data;
1023         ipaddr_t gate;
1024         char flags[10], intf[LIFNAMSIZ + 1];
1025 
1026         if (ire->ire_ipversion != IPV4_VERSION)
1027                 return (WALK_NEXT);
1028 
1029         /* Skip certain IREs by default */
1030         if (!(*opts & NETSTAT_ALL) &&
1031             (ire->ire_type &
1032             (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE)))
1033                 return (WALK_NEXT);
1034 
1035         if (*opts & NETSTAT_FIRST) {
1036                 *opts &= ~NETSTAT_FIRST;
1037                 mdb_printf("%<u>%s Table: IPv4%</u>\n",
1038                     (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
1039                 if (*opts & NETSTAT_VERBOSE) {
1040                         mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt  "
1041                             " Ref Flg Out   In/Fwd%</u>\n",
1042                             "Address", ADDR_V4_WIDTH, "Destination",
1043                             ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway");
1044                 } else {
1045                         mdb_printf("%<u>%-?s %-*s %-*s Flags Ref  Use   "
1046                             "Interface%</u>\n",
1047                             "Address", ADDR_V4_WIDTH, "Destination",
1048                             ADDR_V4_WIDTH, "Gateway");
1049                 }
1050         }
1051 
1052         gate = ire->ire_gateway_addr;
1053 
1054         get_ireflags(ire, flags);
1055 
1056         get_ifname(ire, intf);
1057 
1058         if (*opts & NETSTAT_VERBOSE) {
1059                 mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u "
1060                     "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH,
1061                     ire->ire_mask, ADDR_V4_WIDTH, gate, intf,
1062                     0, ' ',
1063                     ire->ire_metrics.iulp_rtt, ire->ire_refcnt, flags,
1064                     ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
1065         } else {
1066                 mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr,
1067                     ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags,
1068                     ire->ire_refcnt,
1069                     ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
1070         }
1071 
1072         return (WALK_NEXT);
1073 }
1074 
1075 int
1076 ip_mask_to_plen_v6(const in6_addr_t *v6mask)
1077 {
1078         int plen;
1079         int i;
1080         uint32_t val;
1081 
1082         for (i = 3; i >= 0; i--)
1083                 if (v6mask->s6_addr32[i] != 0)
1084                         break;
1085         if (i < 0)
1086                 return (0);
1087         plen = 32 + 32 * i;
1088         val = v6mask->s6_addr32[i];
1089         while (!(val & 1)) {
1090                 val >>= 1;
1091                 plen--;
1092         }
1093 
1094         return (plen);
1095 }
1096 
1097 static int
1098 netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
1099 {
1100         const ire_t *ire = walk_data;
1101         uint_t *opts = cb_data;
1102         const in6_addr_t *gatep;
1103         char deststr[ADDR_V6_WIDTH + 5];
1104         char flags[10], intf[LIFNAMSIZ + 1];
1105         int masklen;
1106 
1107         if (ire->ire_ipversion != IPV6_VERSION)
1108                 return (WALK_NEXT);
1109 
1110         /* Skip certain IREs by default */
1111         if (!(*opts & NETSTAT_ALL) &&
1112             (ire->ire_type &
1113             (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE)))
1114                 return (WALK_NEXT);
1115 
1116         if (*opts & NETSTAT_FIRST) {
1117                 *opts &= ~NETSTAT_FIRST;
1118                 mdb_printf("\n%<u>%s Table: IPv6%</u>\n",
1119                     (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
1120                 if (*opts & NETSTAT_VERBOSE) {
1121                         mdb_printf("%<u>%-?s %-*s %-*s If    PMTU   Rtt   Ref "
1122                             "Flags Out    In/Fwd%</u>\n",
1123                             "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
1124                             ADDR_V6_WIDTH, "Gateway");
1125                 } else {
1126                         mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use    If"
1127                             "%</u>\n",
1128                             "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
1129                             ADDR_V6_WIDTH, "Gateway");
1130                 }
1131         }
1132 
1133         gatep = &ire->ire_gateway_addr_v6;
1134 
1135         masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6);
1136         (void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d",
1137             &ire->ire_addr_v6, masklen);
1138 
1139         get_ireflags(ire, flags);
1140 
1141         get_ifname(ire, intf);
1142 
1143         if (*opts & NETSTAT_VERBOSE) {
1144                 mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n",
1145                     kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep,
1146                     intf, 0, ' ',
1147                     ire->ire_metrics.iulp_rtt, ire->ire_refcnt,
1148                     flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
1149         } else {
1150                 mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr,
1151                     ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags,
1152                     ire->ire_refcnt,
1153                     ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
1154         }
1155 
1156         return (WALK_NEXT);
1157 }
1158 
1159 static void
1160 netstat_header_v4(int proto)
1161 {
1162         if (proto == IPPROTO_TCP)
1163                 mdb_printf("%<u>%-?s ", "TCPv4");
1164         else if (proto == IPPROTO_UDP)
1165                 mdb_printf("%<u>%-?s ", "UDPv4");
1166         else if (proto == IPPROTO_ICMP)
1167                 mdb_printf("%<u>%-?s ", "ICMPv4");
1168         mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
1169             "", ADDR_V4_WIDTH, "Local Address",
1170             "", ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone");
1171 }
1172 
1173 static void
1174 netstat_header_v6(int proto)
1175 {
1176         if (proto == IPPROTO_TCP)
1177                 mdb_printf("%<u>%-?s ", "TCPv6");
1178         else if (proto == IPPROTO_UDP)
1179                 mdb_printf("%<u>%-?s ", "UDPv6");
1180         else if (proto == IPPROTO_ICMP)
1181                 mdb_printf("%<u>%-?s ", "ICMPv6");
1182         mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
1183             "", ADDR_V6_WIDTH, "Local Address",
1184             "", ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone");
1185 }
1186 
1187 static int
1188 netstat_print_conn(const char *cache, int proto, mdb_walk_cb_t cbfunc,
1189     void *cbdata)
1190 {
1191         netstat_cb_data_t *ncb = cbdata;
1192 
1193         if ((ncb->opts & NETSTAT_VERBOSE) && proto == IPPROTO_TCP)
1194                 netstat_tcp_verbose_header_pr();
1195         if (mdb_walk(cache, cbfunc, cbdata) == -1) {
1196                 mdb_warn("failed to walk %s", cache);
1197                 return (DCMD_ERR);
1198         }
1199         return (DCMD_OK);
1200 }
1201 
1202 static int
1203 netstat_print_common(const char *cache, int proto, mdb_walk_cb_t cbfunc,
1204     void *cbdata)
1205 {
1206         netstat_cb_data_t *ncb = cbdata;
1207         int af = ncb->af;
1208         int status = DCMD_OK;
1209 
1210         if (af != AF_INET6) {
1211                 ncb->af = AF_INET;
1212                 netstat_header_v4(proto);
1213                 status = netstat_print_conn(cache, proto, cbfunc, cbdata);
1214         }
1215         if (status == DCMD_OK && af != AF_INET) {
1216                 ncb->af = AF_INET6;
1217                 netstat_header_v6(proto);
1218                 status = netstat_print_conn(cache, proto, cbfunc, cbdata);
1219         }
1220         ncb->af = af;
1221         return (status);
1222 }
1223 
1224 /*ARGSUSED*/
1225 int
1226 netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1227 {
1228         uint_t opts = 0;
1229         const char *optf = NULL;
1230         const char *optP = NULL;
1231         netstat_cb_data_t *cbdata;
1232         int status;
1233         int af = 0;
1234 
1235         if (mdb_getopts(argc, argv,
1236             'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts,
1237             'f', MDB_OPT_STR, &optf,
1238             'P', MDB_OPT_STR, &optP,
1239             'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts,
1240             'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts,
1241             NULL) != argc)
1242                 return (DCMD_USAGE);
1243 
1244         if (optP != NULL) {
1245                 if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0) &&
1246                     (strcmp("icmp", optP) != 0))
1247                         return (DCMD_USAGE);
1248                 if (opts & NETSTAT_ROUTE)
1249                         return (DCMD_USAGE);
1250         }
1251 
1252         if (optf == NULL)
1253                 opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX;
1254         else if (strcmp("inet", optf) == 0)
1255                 opts |= NETSTAT_V4;
1256         else if (strcmp("inet6", optf) == 0)
1257                 opts |= NETSTAT_V6;
1258         else if (strcmp("unix", optf) == 0)
1259                 opts |= NETSTAT_UNIX;
1260         else
1261                 return (DCMD_USAGE);
1262 
1263         if (opts & NETSTAT_ROUTE) {
1264                 if (!(opts & (NETSTAT_V4|NETSTAT_V6)))
1265                         return (DCMD_USAGE);
1266                 if (opts & NETSTAT_V4) {
1267                         opts |= NETSTAT_FIRST;
1268                         if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) {
1269                                 mdb_warn("failed to walk ip`ire");
1270                                 return (DCMD_ERR);
1271                         }
1272                 }
1273                 if (opts & NETSTAT_V6) {
1274                         opts |= NETSTAT_FIRST;
1275                         if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) {
1276                                 mdb_warn("failed to walk ip`ire");
1277                                 return (DCMD_ERR);
1278                         }
1279                 }
1280                 return (DCMD_OK);
1281         }
1282 
1283         if ((opts & NETSTAT_UNIX) && (optP == NULL)) {
1284                 /* Print Unix Domain Sockets */
1285                 mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n",
1286                     "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr",
1287                     "Remote Addr", "Zone");
1288 
1289                 if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) {
1290                         mdb_warn("failed to walk genunix`sonode");
1291                         return (DCMD_ERR);
1292                 }
1293                 if (!(opts & (NETSTAT_V4 | NETSTAT_V6)))
1294                         return (DCMD_OK);
1295         }
1296 
1297         cbdata = mdb_alloc(sizeof (netstat_cb_data_t), UM_SLEEP);
1298         cbdata->opts = opts;
1299         if ((optf != NULL) && (opts & NETSTAT_V4))
1300                 af = AF_INET;
1301         else if ((optf != NULL) && (opts & NETSTAT_V6))
1302                 af = AF_INET6;
1303 
1304         cbdata->af = af;
1305         if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
1306                 status = netstat_print_common("tcp_conn_cache", IPPROTO_TCP,
1307                     netstat_tcp_cb, cbdata);
1308                 if (status != DCMD_OK)
1309                         goto out;
1310         }
1311 
1312         if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
1313                 status = netstat_print_common("udp_conn_cache", IPPROTO_UDP,
1314                     netstat_udp_cb, cbdata);
1315                 if (status != DCMD_OK)
1316                         goto out;
1317         }
1318 
1319         if ((optP == NULL) || (strcmp("icmp", optP) == 0)) {
1320                 status = netstat_print_common("rawip_conn_cache", IPPROTO_ICMP,
1321                     netstat_icmp_cb, cbdata);
1322                 if (status != DCMD_OK)
1323                         goto out;
1324         }
1325 
1326         if ((optP == NULL) || (strcmp("dccp", optP) == 0)) {
1327                 status = netstat_print_common("dccp_conn_cache", IPPROTO_DCCP,
1328                     netstat_dccp_cb, cbdata);
1329                 if (status != DCMD_OK)
1330                         goto out;
1331         }
1332 out:
1333         mdb_free(cbdata, sizeof (netstat_cb_data_t));
1334         return (status);
1335 }
1336 
1337 /*
1338  * "::dladm show-bridge" support
1339  */
1340 typedef struct {
1341         uint_t opt_l;
1342         uint_t opt_f;
1343         uint_t opt_t;
1344         const char *name;
1345         clock_t lbolt;
1346         boolean_t found;
1347         uint_t nlinks;
1348         uint_t nfwd;
1349 
1350         /*
1351          * These structures are kept inside the 'args' for allocation reasons.
1352          * They're all large data structures (over 1K), and may cause the stack
1353          * to explode.  mdb and kmdb will fail in these cases, and thus we
1354          * allocate them from the heap.
1355          */
1356         trill_inst_t ti;
1357         bridge_link_t bl;
1358         mac_impl_t mi;
1359 } show_bridge_args_t;
1360 
1361 static void
1362 show_vlans(const uint8_t *vlans)
1363 {
1364         int i, bit;
1365         uint8_t val;
1366         int rstart = -1, rnext = -1;
1367 
1368         for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) {
1369                 val = vlans[i];
1370                 if (i == 0)
1371                         val &= ~1;
1372                 while ((bit = mdb_ffs(val)) != 0) {
1373                         bit--;
1374                         val &= ~(1 << bit);
1375                         bit += i * sizeof (*vlans) * NBBY;
1376                         if (bit != rnext) {
1377                                 if (rnext != -1 && rstart + 1 != rnext)
1378                                         mdb_printf("-%d", rnext - 1);
1379                                 if (rstart != -1)
1380                                         mdb_printf(",");
1381                                 mdb_printf("%d", bit);
1382                                 rstart = bit;
1383                         }
1384                         rnext = bit + 1;
1385                 }
1386         }
1387         if (rnext != -1 && rstart + 1 != rnext)
1388                 mdb_printf("-%d", rnext - 1);
1389         mdb_printf("\n");
1390 }
1391 
1392 /*
1393  * This callback is invoked by a walk of the links attached to a bridge.  If
1394  * we're showing link details, then they're printed here.  If not, then we just
1395  * count up the links for the bridge summary.
1396  */
1397 static int
1398 do_bridge_links(uintptr_t addr, const void *data, void *ptr)
1399 {
1400         show_bridge_args_t *args = ptr;
1401         const bridge_link_t *blp = data;
1402         char macaddr[ETHERADDRL * 3];
1403         const char *name;
1404 
1405         args->nlinks++;
1406 
1407         if (!args->opt_l)
1408                 return (WALK_NEXT);
1409 
1410         if (mdb_vread(&args->mi, sizeof (args->mi),
1411             (uintptr_t)blp->bl_mh) == -1) {
1412                 mdb_warn("cannot read mac data at %p", blp->bl_mh);
1413                 name = "?";
1414         } else  {
1415                 name = args->mi.mi_name;
1416         }
1417 
1418         mdb_mac_addr(blp->bl_local_mac, ETHERADDRL, macaddr,
1419             sizeof (macaddr));
1420 
1421         mdb_printf("%-?p %-16s %-17s %03X %-4d ", addr, name, macaddr,
1422             blp->bl_flags, blp->bl_pvid);
1423 
1424         if (blp->bl_trilldata == NULL) {
1425                 switch (blp->bl_state) {
1426                 case BLS_BLOCKLISTEN:
1427                         name = "BLOCK";
1428                         break;
1429                 case BLS_LEARNING:
1430                         name = "LEARN";
1431                         break;
1432                 case BLS_FORWARDING:
1433                         name = "FWD";
1434                         break;
1435                 default:
1436                         name = "?";
1437                 }
1438                 mdb_printf("%-5s ", name);
1439                 show_vlans(blp->bl_vlans);
1440         } else {
1441                 show_vlans(blp->bl_afs);
1442         }
1443 
1444         return (WALK_NEXT);
1445 }
1446 
1447 /*
1448  * It seems a shame to duplicate this code, but merging it with the link
1449  * printing code above is more trouble than it would be worth.
1450  */
1451 static void
1452 print_link_name(show_bridge_args_t *args, uintptr_t addr, char sep)
1453 {
1454         const char *name;
1455 
1456         if (mdb_vread(&args->bl, sizeof (args->bl), addr) == -1) {
1457                 mdb_warn("cannot read bridge link at %p", addr);
1458                 return;
1459         }
1460 
1461         if (mdb_vread(&args->mi, sizeof (args->mi),
1462             (uintptr_t)args->bl.bl_mh) == -1) {
1463                 name = "?";
1464         } else  {
1465                 name = args->mi.mi_name;
1466         }
1467 
1468         mdb_printf("%s%c", name, sep);
1469 }
1470 
1471 static int
1472 do_bridge_fwd(uintptr_t addr, const void *data, void *ptr)
1473 {
1474         show_bridge_args_t *args = ptr;
1475         const bridge_fwd_t *bfp = data;
1476         char macaddr[ETHERADDRL * 3];
1477         int i;
1478 #define MAX_FWD_LINKS   16
1479         bridge_link_t *links[MAX_FWD_LINKS];
1480         uint_t nlinks;
1481 
1482         args->nfwd++;
1483 
1484         if (!args->opt_f)
1485                 return (WALK_NEXT);
1486 
1487         if ((nlinks = bfp->bf_nlinks) > MAX_FWD_LINKS)
1488                 nlinks = MAX_FWD_LINKS;
1489 
1490         if (mdb_vread(links, sizeof (links[0]) * nlinks,
1491             (uintptr_t)bfp->bf_links) == -1) {
1492                 mdb_warn("cannot read bridge forwarding links at %p",
1493                     bfp->bf_links);
1494                 return (WALK_ERR);
1495         }
1496 
1497         mdb_mac_addr(bfp->bf_dest, ETHERADDRL, macaddr, sizeof (macaddr));
1498 
1499         mdb_printf("%-?p %-17s ", addr, macaddr);
1500         if (bfp->bf_flags & BFF_LOCALADDR)
1501                 mdb_printf("%-7s", "[self]");
1502         else
1503                 mdb_printf("t-%-5d", args->lbolt - bfp->bf_lastheard);
1504         mdb_printf(" %-7u ", bfp->bf_refs);
1505 
1506         if (bfp->bf_trill_nick != 0) {
1507                 mdb_printf("%d\n", bfp->bf_trill_nick);
1508         } else {
1509                 for (i = 0; i < bfp->bf_nlinks; i++) {
1510                         print_link_name(args, (uintptr_t)links[i],
1511                             i == bfp->bf_nlinks - 1 ? '\n' : ' ');
1512                 }
1513         }
1514 
1515         return (WALK_NEXT);
1516 }
1517 
1518 static int
1519 do_show_bridge(uintptr_t addr, const void *data, void *ptr)
1520 {
1521         show_bridge_args_t *args = ptr;
1522         bridge_inst_t bi;
1523         const bridge_inst_t *bip;
1524         trill_node_t tn;
1525         trill_sock_t tsp;
1526         trill_nickinfo_t tni;
1527         char bname[MAXLINKNAMELEN];
1528         char macaddr[ETHERADDRL * 3];
1529         char *cp;
1530         uint_t nnicks;
1531         int i;
1532 
1533         if (data != NULL) {
1534                 bip = data;
1535         } else {
1536                 if (mdb_vread(&bi, sizeof (bi), addr) == -1) {
1537                         mdb_warn("cannot read bridge instance at %p", addr);
1538                         return (WALK_ERR);
1539                 }
1540                 bip = &bi;
1541         }
1542 
1543         (void) strncpy(bname, bip->bi_name, sizeof (bname) - 1);
1544         bname[MAXLINKNAMELEN - 1] = '\0';
1545         cp = bname + strlen(bname);
1546         if (cp > bname && cp[-1] == '0')
1547                 cp[-1] = '\0';
1548 
1549         if (args->name != NULL && strcmp(args->name, bname) != 0)
1550                 return (WALK_NEXT);
1551 
1552         args->found = B_TRUE;
1553         args->nlinks = args->nfwd = 0;
1554 
1555         if (args->opt_l) {
1556                 mdb_printf("%-?s %-16s %-17s %3s %-4s ", "ADDR", "LINK",
1557                     "MAC-ADDR", "FLG", "PVID");
1558                 if (bip->bi_trilldata == NULL)
1559                         mdb_printf("%-5s %s\n", "STATE", "VLANS");
1560                 else
1561                         mdb_printf("%s\n", "FWD-VLANS");
1562         }
1563 
1564         if (!args->opt_f && !args->opt_t &&
1565             mdb_pwalk("list", do_bridge_links, args,
1566             addr + offsetof(bridge_inst_t, bi_links)) != DCMD_OK)
1567                 return (WALK_ERR);
1568 
1569         if (args->opt_f)
1570                 mdb_printf("%-?s %-17s %-7s %-7s %s\n", "ADDR", "DEST", "TIME",
1571                     "REFS", "OUTPUT");
1572 
1573         if (!args->opt_l && !args->opt_t &&
1574             mdb_pwalk("avl", do_bridge_fwd, args,
1575             addr + offsetof(bridge_inst_t, bi_fwd)) != DCMD_OK)
1576                 return (WALK_ERR);
1577 
1578         nnicks = 0;
1579         if (bip->bi_trilldata != NULL && !args->opt_l && !args->opt_f) {
1580                 if (mdb_vread(&args->ti, sizeof (args->ti),
1581                     (uintptr_t)bip->bi_trilldata) == -1) {
1582                         mdb_warn("cannot read trill instance at %p",
1583                             bip->bi_trilldata);
1584                         return (WALK_ERR);
1585                 }
1586                 if (args->opt_t)
1587                         mdb_printf("%-?s %-5s %-17s %s\n", "ADDR",
1588                             "NICK", "NEXT-HOP", "LINK");
1589                 for (i = 0; i < RBRIDGE_NICKNAME_MAX; i++) {
1590                         if (args->ti.ti_nodes[i] == NULL)
1591                                 continue;
1592                         if (args->opt_t) {
1593                                 if (mdb_vread(&tn, sizeof (tn),
1594                                     (uintptr_t)args->ti.ti_nodes[i]) == -1) {
1595                                         mdb_warn("cannot read trill node %d at "
1596                                             "%p", i, args->ti.ti_nodes[i]);
1597                                         return (WALK_ERR);
1598                                 }
1599                                 if (mdb_vread(&tni, sizeof (tni),
1600                                     (uintptr_t)tn.tn_ni) == -1) {
1601                                         mdb_warn("cannot read trill node info "
1602                                             "%d at %p", i, tn.tn_ni);
1603                                         return (WALK_ERR);
1604                                 }
1605                                 mdb_mac_addr(tni.tni_adjsnpa, ETHERADDRL,
1606                                     macaddr, sizeof (macaddr));
1607                                 if (tni.tni_nick == args->ti.ti_nick) {
1608                                         (void) strcpy(macaddr, "[self]");
1609                                 }
1610                                 mdb_printf("%-?p %-5u %-17s ",
1611                                     args->ti.ti_nodes[i], tni.tni_nick,
1612                                     macaddr);
1613                                 if (tn.tn_tsp != NULL) {
1614                                         if (mdb_vread(&tsp, sizeof (tsp),
1615                                             (uintptr_t)tn.tn_tsp) == -1) {
1616                                                 mdb_warn("cannot read trill "
1617                                                     "socket info at %p",
1618                                                     tn.tn_tsp);
1619                                                 return (WALK_ERR);
1620                                         }
1621                                         if (tsp.ts_link != NULL) {
1622                                                 print_link_name(args,
1623                                                     (uintptr_t)tsp.ts_link,
1624                                                     '\n');
1625                                                 continue;
1626                                         }
1627                                 }
1628                                 mdb_printf("--\n");
1629                         } else {
1630                                 nnicks++;
1631                         }
1632                 }
1633         } else {
1634                 if (args->opt_t)
1635                         mdb_printf("bridge is not running TRILL\n");
1636         }
1637 
1638         if (!args->opt_l && !args->opt_f && !args->opt_t) {
1639                 mdb_printf("%-?p %-7s %-16s %-7u %-7u", addr,
1640                     bip->bi_trilldata == NULL ? "stp" : "trill", bname,
1641                     args->nlinks, args->nfwd);
1642                 if (bip->bi_trilldata != NULL)
1643                         mdb_printf(" %-7u %u\n", nnicks, args->ti.ti_nick);
1644                 else
1645                         mdb_printf(" %-7s %s\n", "--", "--");
1646         }
1647         return (WALK_NEXT);
1648 }
1649 
1650 static int
1651 dladm_show_bridge(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1652 {
1653         show_bridge_args_t *args;
1654         GElf_Sym sym;
1655         int i;
1656 
1657         args = mdb_zalloc(sizeof (*args), UM_SLEEP);
1658 
1659         i = mdb_getopts(argc, argv,
1660             'l', MDB_OPT_SETBITS, 1, &args->opt_l,
1661             'f', MDB_OPT_SETBITS, 1, &args->opt_f,
1662             't', MDB_OPT_SETBITS, 1, &args->opt_t,
1663             NULL);
1664 
1665         argc -= i;
1666         argv += i;
1667 
1668         if (argc > 1 || (argc == 1 && argv[0].a_type != MDB_TYPE_STRING)) {
1669                 mdb_free(args, sizeof (*args));
1670                 return (DCMD_USAGE);
1671         }
1672         if (argc == 1)
1673                 args->name = argv[0].a_un.a_str;
1674 
1675         if ((args->lbolt = mdb_get_lbolt()) == -1) {
1676                 mdb_warn("failed to read lbolt");
1677                 goto err;
1678         }
1679 
1680         if (flags & DCMD_ADDRSPEC) {
1681                 if (args->name != NULL) {
1682                         mdb_printf("bridge name and address are mutually "
1683                             "exclusive\n");
1684                         goto err;
1685                 }
1686                 if (!args->opt_l && !args->opt_f && !args->opt_t)
1687                         mdb_printf("%-?s %-7s %-16s %-7s %-7s\n", "ADDR",
1688                             "PROTECT", "NAME", "NLINKS", "NFWD");
1689                 if (do_show_bridge(addr, NULL, args) != WALK_NEXT)
1690                         goto err;
1691                 mdb_free(args, sizeof (*args));
1692                 return (DCMD_OK);
1693         } else {
1694                 if ((args->opt_l || args->opt_f || args->opt_t) &&
1695                     args->name == NULL) {
1696                         mdb_printf("need bridge name or address with -[lft]\n");
1697                         goto err;
1698                 }
1699                 if (mdb_lookup_by_obj("bridge", "inst_list", &sym) == -1) {
1700                         mdb_warn("failed to find 'bridge`inst_list'");
1701                         goto err;
1702                 }
1703                 if (!args->opt_l && !args->opt_f && !args->opt_t)
1704                         mdb_printf("%-?s %-7s %-16s %-7s %-7s %-7s %s\n",
1705                             "ADDR", "PROTECT", "NAME", "NLINKS", "NFWD",
1706                             "NNICKS", "NICK");
1707                 if (mdb_pwalk("list", do_show_bridge, args,
1708                     (uintptr_t)sym.st_value) != DCMD_OK)
1709                         goto err;
1710                 if (!args->found && args->name != NULL) {
1711                         mdb_printf("bridge instance %s not found\n",
1712                             args->name);
1713                         goto err;
1714                 }
1715                 mdb_free(args, sizeof (*args));
1716                 return (DCMD_OK);
1717         }
1718 
1719 err:
1720         mdb_free(args, sizeof (*args));
1721         return (DCMD_ERR);
1722 }
1723 
1724 /*
1725  * Support for the "::dladm" dcmd
1726  */
1727 int
1728 dladm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1729 {
1730         if (argc < 1 || argv[0].a_type != MDB_TYPE_STRING)
1731                 return (DCMD_USAGE);
1732 
1733         /*
1734          * This could be a bit more elaborate, once we support more of the
1735          * dladm show-* subcommands.
1736          */
1737         argc--;
1738         argv++;
1739         if (strcmp(argv[-1].a_un.a_str, "show-bridge") == 0)
1740                 return (dladm_show_bridge(addr, flags, argc, argv));
1741 
1742         return (DCMD_USAGE);
1743 }
1744 
1745 void
1746 dladm_help(void)
1747 {
1748         mdb_printf("Subcommands:\n"
1749             "  show-bridge [-flt] [<name>]\n"
1750             "\t     Show bridge information; -l for links and -f for "
1751             "forwarding\n"
1752             "\t     entries, and -t for TRILL nicknames.  Address is required "
1753             "if name\n"
1754             "\t     is not specified.\n");
1755 }