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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <sys/types.h> 30 #include <sys/stropts.h> 31 #include <sys/stream.h> 32 #include <sys/dlpi.h> 33 #include <sys/hook.h> 34 #include <sys/hook_event.h> 35 #include <inet/led.h> 36 #include <inet/common.h> 37 #include <inet/mi.h> 38 #include <inet/arp.h> 39 #include <inet/arp_impl.h> 40 #include <inet/ip.h> 41 #include <netinet/arp.h> 42 43 #include <mdb/mdb_modapi.h> 44 #include <mdb/mdb_ks.h> 45 46 typedef struct { 47 uint32_t act_cmd; 48 char *act_name; 49 char *act_type; 50 } arp_cmd_tbl; 51 52 /* 53 * Table of ARP commands and structure types used for messages between ARP and 54 * IP. 55 */ 56 static const arp_cmd_tbl act_list[] = { 57 { AR_ENTRY_ADD, "AR_ENTRY_ADD", "arp`area_t" }, 58 { AR_ENTRY_DELETE, "AR_ENTRY_DELETE", "arp`ared_t" }, 59 { AR_ENTRY_QUERY, "AR_ENTRY_QUERY", "arp`areq_t" }, 60 { AR_ENTRY_SQUERY, "AR_ENTRY_SQUERY", "arp`area_t" }, 61 { AR_MAPPING_ADD, "AR_MAPPING_ADD", "arp`arma_t" }, 62 { AR_CLIENT_NOTIFY, "AR_CLIENT_NOTIFY", "arp`arcn_t" }, 63 { AR_INTERFACE_UP, "AR_INTERFACE_UP", "arp`arc_t" }, 64 { AR_INTERFACE_DOWN, "AR_INTERFACE_DOWN", "arp`arc_t" }, 65 { AR_INTERFACE_ON, "AR_INTERFACE_ON", "arp`arc_t" }, 66 { AR_INTERFACE_OFF, "AR_INTERFACE_OFF", "arp`arc_t" }, 67 { AR_DLPIOP_DONE, "AR_DLPIOP_DONE", "arp`arc_t" }, 68 { AR_ARP_CLOSING, "AR_ARP_CLOSING", "arp`arc_t" }, 69 { AR_ARP_EXTEND, "AR_ARP_EXTEND", "arp`arc_t" }, 70 { 0, "unknown command", "arp`arc_t" } 71 }; 72 73 /* 74 * State information kept during walk over ACE hash table and unhashed mask 75 * list. 76 */ 77 typedef struct ace_walk_data { 78 ace_t *awd_hash_tbl[ARP_HASH_SIZE]; 79 ace_t *awd_masks; 80 int awd_idx; 81 } ace_walk_data_t; 82 83 static int 84 arl_walk_init(mdb_walk_state_t *wsp) 85 { 86 if (wsp->walk_addr == NULL && 87 mdb_readvar(&wsp->walk_addr, "arl_g_head") == -1) { 88 mdb_warn("failed to read 'arl_g_head'"); 89 return (WALK_ERR); 90 } 91 return (WALK_NEXT); 92 } 93 94 static int 95 arl_walk_step(mdb_walk_state_t *wsp) 96 { 97 uintptr_t addr = wsp->walk_addr; 98 arl_t arl; 99 100 if (wsp->walk_addr == NULL) 101 return (WALK_DONE); 102 103 if (mdb_vread(&arl, sizeof (arl), addr) == -1) { 104 mdb_warn("failed to read arl_t at %p", addr); 105 return (WALK_ERR); 106 } 107 108 wsp->walk_addr = (uintptr_t)arl.arl_next; 109 110 return ((*wsp->walk_callback)(addr, &arl, wsp->walk_cbdata)); 111 } 112 113 static int 114 ace_walk_init(mdb_walk_state_t *wsp) 115 { 116 ace_walk_data_t *aw; 117 118 if (wsp->walk_addr != NULL) { 119 mdb_warn("ace supports only global walks\n"); 120 return (WALK_ERR); 121 } 122 123 aw = mdb_alloc(sizeof (ace_walk_data_t), UM_SLEEP); 124 125 if (mdb_readsym(aw->awd_hash_tbl, sizeof (aw->awd_hash_tbl), 126 "ar_ce_hash_tbl") == -1) { 127 mdb_warn("failed to read 'ar_ce_hash_tbl'"); 128 mdb_free(aw, sizeof (ace_walk_data_t)); 129 return (WALK_ERR); 130 } 131 132 if (mdb_readvar(&aw->awd_masks, "ar_ce_mask_entries") == -1) { 133 mdb_warn("failed to read 'ar_ce_mask_entries'"); 134 mdb_free(aw, sizeof (ace_walk_data_t)); 135 return (WALK_ERR); 136 } 137 138 /* The step routine will start off by incrementing to index 0 */ 139 aw->awd_idx = -1; 140 wsp->walk_addr = 0; 141 wsp->walk_data = aw; 142 143 return (WALK_NEXT); 144 } 145 146 static int 147 ace_walk_step(mdb_walk_state_t *wsp) 148 { 149 uintptr_t addr; 150 ace_walk_data_t *aw = wsp->walk_data; 151 ace_t ace; 152 153 /* 154 * If we're at the end of the previous list, then find the start of the 155 * next list to process. 156 */ 157 while (wsp->walk_addr == NULL) { 158 if (aw->awd_idx == ARP_HASH_SIZE) 159 return (WALK_DONE); 160 if (++aw->awd_idx == ARP_HASH_SIZE) { 161 wsp->walk_addr = (uintptr_t)aw->awd_masks; 162 } else { 163 wsp->walk_addr = 164 (uintptr_t)aw->awd_hash_tbl[aw->awd_idx]; 165 } 166 } 167 168 addr = wsp->walk_addr; 169 if (mdb_vread(&ace, sizeof (ace), addr) == -1) { 170 mdb_warn("failed to read ace_t at %p", addr); 171 return (WALK_ERR); 172 } 173 174 wsp->walk_addr = (uintptr_t)ace.ace_next; 175 176 return (wsp->walk_callback(addr, &ace, wsp->walk_cbdata)); 177 } 178 179 static void 180 ace_walk_fini(mdb_walk_state_t *wsp) 181 { 182 mdb_free(wsp->walk_data, sizeof (ace_walk_data_t)); 183 } 184 185 /* Common routine to produce an 'ar' text description */ 186 static void 187 ar_describe(const ar_t *ar, char *buf, size_t nbytes, boolean_t addmac) 188 { 189 if (ar->ar_arl == NULL) { 190 queue_t wq, ipq; 191 ill_t ill; 192 char name[LIFNAMSIZ]; 193 GElf_Sym sym; 194 boolean_t nextip; 195 196 if (mdb_vread(&wq, sizeof (wq), (uintptr_t)ar->ar_wq) == -1 || 197 mdb_vread(&ipq, sizeof (ipq), (uintptr_t)wq.q_next) == -1) 198 return; 199 200 nextip = 201 (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0 && 202 (uintptr_t)sym.st_value == (uintptr_t)ipq.q_qinfo); 203 204 if (!ar->ar_on_ill_stream) { 205 (void) strcpy(buf, nextip ? "Client" : "Unknown"); 206 return; 207 } 208 209 if (!nextip || 210 mdb_vread(&ill, sizeof (ill), (uintptr_t)ipq.q_ptr) == -1 || 211 mdb_readstr(name, sizeof (name), 212 (uintptr_t)ill.ill_name) == -1) { 213 return; 214 } 215 (void) mdb_snprintf(buf, nbytes, "IP %s", name); 216 } else { 217 arl_t arl; 218 ssize_t retv; 219 uint32_t alen; 220 uchar_t macaddr[ARP_MAX_ADDR_LEN]; 221 222 if (mdb_vread(&arl, sizeof (arl), (uintptr_t)ar->ar_arl) == -1) 223 return; 224 retv = mdb_snprintf(buf, nbytes, "ARP %s ", arl.arl_name); 225 if (retv >= nbytes || !addmac) 226 return; 227 alen = arl.arl_hw_addr_length; 228 if (arl.arl_hw_addr == NULL || alen == 0 || 229 alen > sizeof (macaddr)) 230 return; 231 if (mdb_vread(macaddr, alen, (uintptr_t)arl.arl_hw_addr) == -1) 232 return; 233 mdb_mac_addr(macaddr, alen, buf + retv, nbytes - retv); 234 } 235 } 236 237 /* ARGSUSED2 */ 238 static int 239 ar_cb(uintptr_t addr, const void *arptr, void *dummy) 240 { 241 const ar_t *ar = arptr; 242 char ardesc[sizeof ("ARP ") + LIFNAMSIZ]; 243 244 ar_describe(ar, ardesc, sizeof (ardesc), B_FALSE); 245 mdb_printf("%?p %?p %?p %s\n", addr, ar->ar_wq, ar->ar_arl, ardesc); 246 return (WALK_NEXT); 247 } 248 249 /* 250 * Print out ARP client structures. 251 */ 252 /* ARGSUSED2 */ 253 static int 254 ar_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 255 { 256 ar_t ar; 257 258 if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 259 mdb_printf("%<u>%?s %?s %?s %s%</u>\n", 260 "AR", "WQ", "ARL", "TYPE"); 261 } 262 263 if (flags & DCMD_ADDRSPEC) { 264 if (mdb_vread(&ar, sizeof (ar), addr) == -1) { 265 mdb_warn("failed to read ar_t at %p", addr); 266 return (DCMD_ERR); 267 } 268 (void) ar_cb(addr, &ar, NULL); 269 } else { 270 if (mdb_walk("ar", ar_cb, NULL) == -1) { 271 mdb_warn("cannot walk ar_t structures"); 272 return (DCMD_ERR); 273 } 274 } 275 return (DCMD_OK); 276 } 277 278 /* ARGSUSED2 */ 279 static int 280 arl_cb(uintptr_t addr, const void *arlptr, void *dummy) 281 { 282 const arl_t *arl = arlptr; 283 uchar_t macaddr[ARP_MAX_ADDR_LEN]; 284 char macstr[ARP_MAX_ADDR_LEN*3]; 285 char flags[4]; 286 const char *primstr; 287 288 mdb_printf("%?p ", addr); 289 if (arl->arl_dlpi_pending == DL_PRIM_INVAL) 290 mdb_printf("%16s", "--"); 291 else if ((primstr = mdb_dlpi_prim(arl->arl_dlpi_pending)) != NULL) 292 mdb_printf("%16s", primstr); 293 else 294 mdb_printf("%16x", arl->arl_dlpi_pending); 295 if (arl->arl_hw_addr_length == 0 || 296 arl->arl_hw_addr_length > sizeof (macaddr)) { 297 (void) strcpy(macstr, "--"); 298 } else if (mdb_vread(macaddr, arl->arl_hw_addr_length, 299 (uintptr_t)arl->arl_hw_addr) == -1) { 300 (void) strcpy(macstr, "?"); 301 } else { 302 mdb_mac_addr(macaddr, arl->arl_hw_addr_length, macstr, 303 sizeof (macstr)); 304 } 305 306 /* Print both the link-layer state and the NOARP flag */ 307 flags[0] = '\0'; 308 if (arl->arl_flags & ARL_F_NOARP) 309 (void) strcat(flags, "N"); 310 switch (arl->arl_state) { 311 case ARL_S_DOWN: 312 (void) strcat(flags, "d"); 313 break; 314 case ARL_S_PENDING: 315 (void) strcat(flags, "P"); 316 break; 317 case ARL_S_UP: 318 (void) strcat(flags, "U"); 319 break; 320 default: 321 (void) strcat(flags, "?"); 322 break; 323 } 324 mdb_printf(" %8d %-3s %-9s %s\n", 325 mdb_mblk_count(arl->arl_dlpi_deferred), flags, arl->arl_name, 326 macstr); 327 return (WALK_NEXT); 328 } 329 330 /* 331 * Print out ARP link-layer elements. 332 */ 333 /* ARGSUSED2 */ 334 static int 335 arl_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 336 { 337 arl_t arl; 338 339 if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 340 mdb_printf("%<u>%?s %16s %8s %3s %9s %s%</u>\n", 341 "ARL", "DLPI REQ", "DLPI CNT", "FLG", "INTERFACE", 342 "HW ADDR"); 343 } 344 345 if (flags & DCMD_ADDRSPEC) { 346 if (mdb_vread(&arl, sizeof (arl), addr) == -1) { 347 mdb_warn("failed to read arl_t at %p", addr); 348 return (DCMD_ERR); 349 } 350 (void) arl_cb(addr, &arl, NULL); 351 } else { 352 if (mdb_walk("arl", arl_cb, NULL) == -1) { 353 mdb_warn("cannot walk arl_t structures"); 354 return (DCMD_ERR); 355 } 356 } 357 return (DCMD_OK); 358 } 359 360 /* ARGSUSED2 */ 361 static int 362 ace_cb(uintptr_t addr, const void *aceptr, void *dummy) 363 { 364 const ace_t *ace = aceptr; 365 uchar_t macaddr[ARP_MAX_ADDR_LEN]; 366 char macstr[ARP_MAX_ADDR_LEN*3]; 367 /* The %b format isn't compact enough for long listings */ 368 static const char ace_flags[] = "SPDRMLdA ofya"; 369 const char *cp; 370 char flags[sizeof (ace_flags)], *fp; 371 int flg; 372 in_addr_t inaddr, mask; 373 char addrstr[sizeof ("255.255.255.255/32")]; 374 375 /* Walk the list of flags and produce a string */ 376 cp = ace_flags; 377 fp = flags; 378 for (flg = 1; *cp != '\0'; flg <<= 1, cp++) { 379 if ((flg & ace->ace_flags) && *cp != ' ') 380 *fp++ = *cp; 381 } 382 *fp = '\0'; 383 384 /* If it's not resolved, then it has no hardware address */ 385 if (!(ace->ace_flags & ACE_F_RESOLVED) || 386 ace->ace_hw_addr_length == 0 || 387 ace->ace_hw_addr_length > sizeof (macaddr)) { 388 (void) strcpy(macstr, "--"); 389 } else if (mdb_vread(macaddr, ace->ace_hw_addr_length, 390 (uintptr_t)ace->ace_hw_addr) == -1) { 391 (void) strcpy(macstr, "?"); 392 } else { 393 mdb_mac_addr(macaddr, ace->ace_hw_addr_length, macstr, 394 sizeof (macstr)); 395 } 396 397 /* 398 * Nothing other than IP uses ARP these days, so we don't try very hard 399 * here to switch out on ARP protocol type. (Note that ARP protocol 400 * types are roughly Ethertypes, but are allocated separately at IANA.) 401 */ 402 if (ace->ace_proto != IP_ARP_PROTO_TYPE) { 403 (void) mdb_snprintf(addrstr, sizeof (addrstr), 404 "Unknown proto %x", ace->ace_proto); 405 } else if (mdb_vread(&inaddr, sizeof (inaddr), 406 (uintptr_t)ace->ace_proto_addr) != -1 && 407 mdb_vread(&mask, sizeof (mask), (uintptr_t)ace->ace_proto_mask) != 408 -1) { 409 /* 410 * If it's the standard host mask, then print it normally. 411 * Otherwise, use "/n" notation. 412 */ 413 if (mask == (in_addr_t)~0) { 414 (void) mdb_snprintf(addrstr, sizeof (addrstr), "%I", 415 inaddr); 416 } else { 417 (void) mdb_snprintf(addrstr, sizeof (addrstr), "%I/%d", 418 inaddr, mask == 0 ? 0 : 33 - mdb_ffs(mask)); 419 } 420 } else { 421 (void) strcpy(addrstr, "?"); 422 } 423 mdb_printf("%?p %-18s %-8s %s\n", addr, addrstr, flags, macstr); 424 return (WALK_NEXT); 425 } 426 427 /* 428 * Print out ARP cache entry (ace_t) elements. 429 */ 430 /* ARGSUSED2 */ 431 static int 432 ace_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 433 { 434 ace_t ace; 435 436 if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 437 mdb_printf("%<u>%?s %-18s %-8s %s%</u>\n", 438 "ACE", "PROTOADDR", "FLAGS", "HWADDR"); 439 } 440 441 if (flags & DCMD_ADDRSPEC) { 442 if (mdb_vread(&ace, sizeof (ace), addr) == -1) { 443 mdb_warn("failed to read ace_t at %p", addr); 444 return (DCMD_ERR); 445 } 446 (void) ace_cb(addr, &ace, NULL); 447 } else { 448 if (mdb_walk("ace", ace_cb, NULL) == -1) { 449 mdb_warn("cannot walk ace_t structures"); 450 return (DCMD_ERR); 451 } 452 } 453 return (DCMD_OK); 454 } 455 456 /* 457 * Print an ARP hardware and protocol address pair; used when printing an ARP 458 * message. 459 */ 460 static void 461 print_arp(char field_id, const uchar_t *buf, const arh_t *arh, uint16_t ptype) 462 { 463 char macstr[ARP_MAX_ADDR_LEN*3]; 464 in_addr_t inaddr; 465 466 if (arh->arh_hlen == 0) 467 (void) strcpy(macstr, "(none)"); 468 else 469 mdb_mac_addr(buf, arh->arh_hlen, macstr, sizeof (macstr)); 470 mdb_printf("%?s ar$%cha %s\n", "", field_id, macstr); 471 if (arh->arh_plen == 0) { 472 mdb_printf("%?s ar$%cpa (none)\n", "", field_id); 473 } else if (ptype == IP_ARP_PROTO_TYPE) { 474 mdb_printf("%?s ar$%cpa (unknown)\n", "", field_id); 475 } else if (arh->arh_plen == sizeof (in_addr_t)) { 476 (void) memcpy(&inaddr, buf + arh->arh_hlen, sizeof (inaddr)); 477 mdb_printf("%?s ar$%cpa %I\n", "", field_id, inaddr); 478 } else { 479 mdb_printf("%?s ar$%cpa (malformed IP)\n", "", field_id); 480 } 481 } 482 483 /* 484 * Decode an ARP message and display it. 485 */ 486 /* ARGSUSED2 */ 487 static int 488 arphdr_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 489 { 490 struct { 491 arh_t arh; 492 uchar_t addrs[4 * ARP_MAX_ADDR_LEN]; 493 } arp; 494 size_t blen; 495 uint16_t htype, ptype, op; 496 const char *cp; 497 498 if (!(flags & DCMD_ADDRSPEC)) { 499 mdb_warn("address required to print ARP header\n"); 500 return (DCMD_ERR); 501 } 502 503 if (mdb_vread(&arp.arh, sizeof (arp.arh), addr) == -1) { 504 mdb_warn("unable to read ARP header at %p", addr); 505 return (DCMD_ERR); 506 } 507 mdb_nhconvert(&htype, arp.arh.arh_hardware, sizeof (htype)); 508 mdb_nhconvert(&ptype, arp.arh.arh_proto, sizeof (ptype)); 509 mdb_nhconvert(&op, arp.arh.arh_operation, sizeof (op)); 510 511 switch (htype) { 512 case ARPHRD_ETHER: 513 cp = "Ether"; 514 break; 515 case ARPHRD_IEEE802: 516 cp = "IEEE802"; 517 break; 518 case ARPHRD_IB: 519 cp = "InfiniBand"; 520 break; 521 default: 522 cp = "Unknown"; 523 break; 524 } 525 mdb_printf("%?p: ar$hrd %x (%s)\n", addr, htype, cp); 526 mdb_printf("%?s ar$pro %x (%s)\n", "", ptype, 527 ptype == IP_ARP_PROTO_TYPE ? "IP" : "Unknown"); 528 529 switch (op) { 530 case ARPOP_REQUEST: 531 cp = "ares_op$REQUEST"; 532 break; 533 case ARPOP_REPLY: 534 cp = "ares_op$REPLY"; 535 break; 536 case REVARP_REQUEST: 537 cp = "arev_op$REQUEST"; 538 break; 539 case REVARP_REPLY: 540 cp = "arev_op$REPLY"; 541 break; 542 default: 543 cp = "Unknown"; 544 break; 545 } 546 mdb_printf("%?s ar$op %d (%s)\n", "", op, cp); 547 548 /* 549 * Note that we go to some length to attempt to print out the fixed 550 * header data before trying to decode the variable-length data. This 551 * is done to maximize the amount of useful information shown when the 552 * buffer is truncated or otherwise corrupt. 553 */ 554 blen = 2 * (arp.arh.arh_hlen + arp.arh.arh_plen); 555 if (mdb_vread(&arp.addrs, blen, addr + sizeof (arp.arh)) == -1) { 556 mdb_warn("unable to read ARP body at %p", addr); 557 return (DCMD_ERR); 558 } 559 560 print_arp('s', arp.addrs, &arp.arh, ptype); 561 print_arp('t', arp.addrs + arp.arh.arh_hlen + arp.arh.arh_plen, 562 &arp.arh, ptype); 563 return (DCMD_OK); 564 } 565 566 /* 567 * Print out an arp command formatted in a reasonable manner. This implements 568 * the type switch used by ARP. 569 * 570 * It could also dump the data that follows the header (using offset and length 571 * in the various structures), but it currently does not. 572 */ 573 /* ARGSUSED2 */ 574 static int 575 arpcmd_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 576 { 577 arc_t arc; 578 const arp_cmd_tbl *tp; 579 mdb_arg_t subargv; 580 581 if (!(flags & DCMD_ADDRSPEC)) { 582 mdb_warn("address required to print ARP command\n"); 583 return (DCMD_ERR); 584 } 585 if (mdb_vread(&arc, sizeof (arc), addr) == -1) { 586 mdb_warn("unable to read arc_t at %p", addr); 587 return (DCMD_ERR); 588 } 589 for (tp = act_list; tp->act_cmd != 0; tp++) 590 if (tp->act_cmd == arc.arc_cmd) 591 break; 592 mdb_printf("%p %s (%s) = ", addr, tp->act_name, tp->act_type); 593 subargv.a_type = MDB_TYPE_STRING; 594 subargv.a_un.a_str = tp->act_type; 595 if (mdb_call_dcmd("print", addr, DCMD_ADDRSPEC, 1, &subargv) == -1) 596 return (DCMD_ERR); 597 else 598 return (DCMD_OK); 599 } 600 601 static size_t 602 mi_osize(const queue_t *q) 603 { 604 /* 605 * The code in common/inet/mi.c allocates an extra word to store the 606 * size of the allocation. An mi_o_s is thus a size_t plus an mi_o_s. 607 */ 608 struct mi_block { 609 size_t mi_nbytes; 610 struct mi_o_s mi_o; 611 } m; 612 613 if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr - sizeof (m)) != -1) 614 return (m.mi_nbytes - sizeof (m)); 615 616 return (0); 617 } 618 619 /* 620 * This is called when ::stream is used and an ARP module is seen on the 621 * stream. Determine what sort of ARP usage is involved and show an 622 * appropriate message. 623 */ 624 static void 625 arp_qinfo(const queue_t *qp, char *buf, size_t nbytes) 626 { 627 size_t size = mi_osize(qp); 628 ar_t ar; 629 630 if (size != sizeof (ar_t)) 631 return; 632 if (mdb_vread(&ar, sizeof (ar), (uintptr_t)qp->q_ptr) == -1) 633 return; 634 ar_describe(&ar, buf, nbytes, B_TRUE); 635 } 636 637 static uintptr_t 638 arp_rnext(const queue_t *q) 639 { 640 size_t size = mi_osize(q); 641 ar_t ar; 642 643 if (size == sizeof (ar_t) && mdb_vread(&ar, sizeof (ar), 644 (uintptr_t)q->q_ptr) != -1) 645 return ((uintptr_t)ar.ar_rq); 646 647 return (NULL); 648 } 649 650 static uintptr_t 651 arp_wnext(const queue_t *q) 652 { 653 size_t size = mi_osize(q); 654 ar_t ar; 655 656 if (size == sizeof (ar_t) && mdb_vread(&ar, sizeof (ar), 657 (uintptr_t)q->q_ptr) != -1) 658 return ((uintptr_t)ar.ar_wq); 659 660 return (NULL); 661 } 662 663 static const mdb_dcmd_t dcmds[] = { 664 { "ar", "?", "display ARP client streams", ar_cmd, NULL }, 665 { "arl", "?", "display ARP link layers", arl_cmd, NULL }, 666 { "ace", "?", "display ARP cache entries", ace_cmd, NULL }, 667 { "arphdr", ":", "display an ARP header", arphdr_cmd, NULL }, 668 { "arpcmd", ":", "display an ARP command", arpcmd_cmd, NULL }, 669 { NULL } 670 }; 671 672 /* Note: ar_t walker is in genunix.c and net.c; generic MI walker */ 673 static const mdb_walker_t walkers[] = { 674 { "arl", "walk list of arl_t links", 675 arl_walk_init, arl_walk_step, NULL }, 676 { "ace", "walk list of ace_t entries", 677 ace_walk_init, ace_walk_step, ace_walk_fini }, 678 { NULL } 679 }; 680 681 static const mdb_qops_t arp_qops = { arp_qinfo, arp_rnext, arp_wnext }; 682 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 683 684 const mdb_modinfo_t * 685 _mdb_init(void) 686 { 687 GElf_Sym sym; 688 689 if (mdb_lookup_by_obj("arp", "winit", &sym) == 0) 690 mdb_qops_install(&arp_qops, (uintptr_t)sym.st_value); 691 692 return (&modinfo); 693 } 694 695 void 696 _mdb_fini(void) 697 { 698 GElf_Sym sym; 699 700 if (mdb_lookup_by_obj("arp", "winit", &sym) == 0) 701 mdb_qops_remove(&arp_qops, (uintptr_t)sym.st_value); 702 } 703