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 arlphy_t ap; 219 ssize_t retv; 220 uint32_t alen; 221 uchar_t macaddr[ARP_MAX_ADDR_LEN]; 222 223 if (mdb_vread(&arl, sizeof (arl), (uintptr_t)ar->ar_arl) == -1) 224 return; 225 retv = mdb_snprintf(buf, nbytes, "ARP %s ", arl.arl_name); 226 if (retv >= nbytes || !addmac) 227 return; 228 if (mdb_vread(&ap, sizeof (ap), (uintptr_t)arl.arl_phy) == -1) 229 return; 230 alen = ap.ap_hw_addrlen; 231 if (ap.ap_hw_addr == NULL || alen == 0 || 232 alen > sizeof (macaddr)) 233 return; 234 if (mdb_vread(macaddr, alen, (uintptr_t)ap.ap_hw_addr) == -1) 235 return; 236 mdb_mac_addr(macaddr, alen, buf + retv, nbytes - retv); 237 } 238 } 239 240 /* ARGSUSED2 */ 241 static int 242 ar_cb(uintptr_t addr, const void *arptr, void *dummy) 243 { 244 const ar_t *ar = arptr; 245 char ardesc[sizeof ("ARP ") + LIFNAMSIZ]; 246 247 ar_describe(ar, ardesc, sizeof (ardesc), B_FALSE); 248 mdb_printf("%?p %?p %?p %s\n", addr, ar->ar_wq, ar->ar_arl, ardesc); 249 return (WALK_NEXT); 250 } 251 252 /* 253 * Print out ARP client structures. 254 */ 255 /* ARGSUSED2 */ 256 static int 257 ar_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 258 { 259 ar_t ar; 260 261 if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 262 mdb_printf("%<u>%?s %?s %?s %s%</u>\n", 263 "AR", "WQ", "ARL", "TYPE"); 264 } 265 266 if (flags & DCMD_ADDRSPEC) { 267 if (mdb_vread(&ar, sizeof (ar), addr) == -1) { 268 mdb_warn("failed to read ar_t at %p", addr); 269 return (DCMD_ERR); 270 } 271 (void) ar_cb(addr, &ar, NULL); 272 } else { 273 if (mdb_walk("ar", ar_cb, NULL) == -1) { 274 mdb_warn("cannot walk ar_t structures"); 275 return (DCMD_ERR); 276 } 277 } 278 return (DCMD_OK); 279 } 280 281 /* ARGSUSED2 */ 282 static int 283 arl_cb(uintptr_t addr, const void *arlptr, void *dummy) 284 { 285 const arl_t *arl = arlptr; 286 arlphy_t ap; 287 uchar_t macaddr[ARP_MAX_ADDR_LEN]; 288 char macstr[ARP_MAX_ADDR_LEN*3]; 289 char flags[4]; 290 const char *primstr; 291 292 mdb_printf("%?p ", addr); 293 if (arl->arl_dlpi_pending == DL_PRIM_INVAL) 294 mdb_printf("%16s", "--"); 295 else if ((primstr = mdb_dlpi_prim(arl->arl_dlpi_pending)) != NULL) 296 mdb_printf("%16s", primstr); 297 else 298 mdb_printf("%16x", arl->arl_dlpi_pending); 299 300 if (mdb_vread(&ap, sizeof (ap), (uintptr_t)arl->arl_phy) == -1 || 301 ap.ap_hw_addrlen == 0 || ap.ap_hw_addrlen > sizeof (macaddr)) { 302 (void) strcpy(macstr, "--"); 303 } else if (mdb_vread(macaddr, ap.ap_hw_addrlen, 304 (uintptr_t)ap.ap_hw_addr) == -1) { 305 (void) strcpy(macstr, "?"); 306 } else { 307 mdb_mac_addr(macaddr, ap.ap_hw_addrlen, macstr, 308 sizeof (macstr)); 309 } 310 311 /* Print both the link-layer state and the NOARP flag */ 312 flags[0] = '\0'; 313 if (arl->arl_flags & ARL_F_NOARP) 314 (void) strcat(flags, "N"); 315 switch (arl->arl_state) { 316 case ARL_S_DOWN: 317 (void) strcat(flags, "d"); 318 break; 319 case ARL_S_PENDING: 320 (void) strcat(flags, "P"); 321 break; 322 case ARL_S_UP: 323 (void) strcat(flags, "U"); 324 break; 325 default: 326 (void) strcat(flags, "?"); 327 break; 328 } 329 mdb_printf(" %8d %-3s %-9s %s\n", 330 mdb_mblk_count(arl->arl_dlpi_deferred), flags, arl->arl_name, 331 macstr); 332 return (WALK_NEXT); 333 } 334 335 /* 336 * Print out ARP link-layer elements. 337 */ 338 /* ARGSUSED2 */ 339 static int 340 arl_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 341 { 342 arl_t arl; 343 344 if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 345 mdb_printf("%<u>%?s %16s %8s %3s %9s %s%</u>\n", 346 "ARL", "DLPI REQ", "DLPI CNT", "FLG", "INTERFACE", 347 "HWADDR"); 348 } 349 350 if (flags & DCMD_ADDRSPEC) { 351 if (mdb_vread(&arl, sizeof (arl), addr) == -1) { 352 mdb_warn("failed to read arl_t at %p", addr); 353 return (DCMD_ERR); 354 } 355 (void) arl_cb(addr, &arl, NULL); 356 } else { 357 if (mdb_walk("arl", arl_cb, NULL) == -1) { 358 mdb_warn("cannot walk arl_t structures"); 359 return (DCMD_ERR); 360 } 361 } 362 return (DCMD_OK); 363 } 364 365 /* ARGSUSED2 */ 366 static int 367 ace_cb(uintptr_t addr, const void *aceptr, void *dummy) 368 { 369 const ace_t *ace = aceptr; 370 uchar_t macaddr[ARP_MAX_ADDR_LEN]; 371 char macstr[ARP_MAX_ADDR_LEN*3]; 372 /* The %b format isn't compact enough for long listings */ 373 static const char ace_flags[] = "SPDRMLdA ofya"; 374 const char *cp; 375 char flags[sizeof (ace_flags)], *fp; 376 int flg; 377 in_addr_t inaddr, mask; 378 char addrstr[sizeof ("255.255.255.255/32")]; 379 380 /* Walk the list of flags and produce a string */ 381 cp = ace_flags; 382 fp = flags; 383 for (flg = 1; *cp != '\0'; flg <<= 1, cp++) { 384 if ((flg & ace->ace_flags) && *cp != ' ') 385 *fp++ = *cp; 386 } 387 *fp = '\0'; 388 389 /* If it's not resolved, then it has no hardware address */ 390 if (!(ace->ace_flags & ACE_F_RESOLVED) || 391 ace->ace_hw_addr_length == 0 || 392 ace->ace_hw_addr_length > sizeof (macaddr)) { 393 (void) strcpy(macstr, "--"); 394 } else if (mdb_vread(macaddr, ace->ace_hw_addr_length, 395 (uintptr_t)ace->ace_hw_addr) == -1) { 396 (void) strcpy(macstr, "?"); 397 } else { 398 mdb_mac_addr(macaddr, ace->ace_hw_addr_length, macstr, 399 sizeof (macstr)); 400 } 401 402 /* 403 * Nothing other than IP uses ARP these days, so we don't try very hard 404 * here to switch out on ARP protocol type. (Note that ARP protocol 405 * types are roughly Ethertypes, but are allocated separately at IANA.) 406 */ 407 if (ace->ace_proto != IP_ARP_PROTO_TYPE) { 408 (void) mdb_snprintf(addrstr, sizeof (addrstr), 409 "Unknown proto %x", ace->ace_proto); 410 } else if (mdb_vread(&inaddr, sizeof (inaddr), 411 (uintptr_t)ace->ace_proto_addr) != -1 && 412 mdb_vread(&mask, sizeof (mask), (uintptr_t)ace->ace_proto_mask) != 413 -1) { 414 /* 415 * If it's the standard host mask, then print it normally. 416 * Otherwise, use "/n" notation. 417 */ 418 if (mask == (in_addr_t)~0) { 419 (void) mdb_snprintf(addrstr, sizeof (addrstr), "%I", 420 inaddr); 421 } else { 422 (void) mdb_snprintf(addrstr, sizeof (addrstr), "%I/%d", 423 inaddr, mask == 0 ? 0 : 33 - mdb_ffs(mask)); 424 } 425 } else { 426 (void) strcpy(addrstr, "?"); 427 } 428 mdb_printf("%?p %-18s %-8s %s\n", addr, addrstr, flags, macstr); 429 return (WALK_NEXT); 430 } 431 432 /* 433 * Print out ARP cache entry (ace_t) elements. 434 */ 435 /* ARGSUSED2 */ 436 static int 437 ace_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 438 { 439 ace_t ace; 440 441 if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 442 mdb_printf("%<u>%?s %-18s %-8s %s%</u>\n", 443 "ACE", "PROTOADDR", "FLAGS", "HWADDR"); 444 } 445 446 if (flags & DCMD_ADDRSPEC) { 447 if (mdb_vread(&ace, sizeof (ace), addr) == -1) { 448 mdb_warn("failed to read ace_t at %p", addr); 449 return (DCMD_ERR); 450 } 451 (void) ace_cb(addr, &ace, NULL); 452 } else { 453 if (mdb_walk("ace", ace_cb, NULL) == -1) { 454 mdb_warn("cannot walk ace_t structures"); 455 return (DCMD_ERR); 456 } 457 } 458 return (DCMD_OK); 459 } 460 461 /* 462 * Print an ARP hardware and protocol address pair; used when printing an ARP 463 * message. 464 */ 465 static void 466 print_arp(char field_id, const uchar_t *buf, const arh_t *arh, uint16_t ptype) 467 { 468 char macstr[ARP_MAX_ADDR_LEN*3]; 469 in_addr_t inaddr; 470 471 if (arh->arh_hlen == 0) 472 (void) strcpy(macstr, "(none)"); 473 else 474 mdb_mac_addr(buf, arh->arh_hlen, macstr, sizeof (macstr)); 475 mdb_printf("%?s ar$%cha %s\n", "", field_id, macstr); 476 if (arh->arh_plen == 0) { 477 mdb_printf("%?s ar$%cpa (none)\n", "", field_id); 478 } else if (ptype == IP_ARP_PROTO_TYPE) { 479 mdb_printf("%?s ar$%cpa (unknown)\n", "", field_id); 480 } else if (arh->arh_plen == sizeof (in_addr_t)) { 481 (void) memcpy(&inaddr, buf + arh->arh_hlen, sizeof (inaddr)); 482 mdb_printf("%?s ar$%cpa %I\n", "", field_id, inaddr); 483 } else { 484 mdb_printf("%?s ar$%cpa (malformed IP)\n", "", field_id); 485 } 486 } 487 488 /* 489 * Decode an ARP message and display it. 490 */ 491 /* ARGSUSED2 */ 492 static int 493 arphdr_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 494 { 495 struct { 496 arh_t arh; 497 uchar_t addrs[4 * ARP_MAX_ADDR_LEN]; 498 } arp; 499 size_t blen; 500 uint16_t htype, ptype, op; 501 const char *cp; 502 503 if (!(flags & DCMD_ADDRSPEC)) { 504 mdb_warn("address required to print ARP header\n"); 505 return (DCMD_ERR); 506 } 507 508 if (mdb_vread(&arp.arh, sizeof (arp.arh), addr) == -1) { 509 mdb_warn("unable to read ARP header at %p", addr); 510 return (DCMD_ERR); 511 } 512 mdb_nhconvert(&htype, arp.arh.arh_hardware, sizeof (htype)); 513 mdb_nhconvert(&ptype, arp.arh.arh_proto, sizeof (ptype)); 514 mdb_nhconvert(&op, arp.arh.arh_operation, sizeof (op)); 515 516 switch (htype) { 517 case ARPHRD_ETHER: 518 cp = "Ether"; 519 break; 520 case ARPHRD_IEEE802: 521 cp = "IEEE802"; 522 break; 523 case ARPHRD_IB: 524 cp = "InfiniBand"; 525 break; 526 default: 527 cp = "Unknown"; 528 break; 529 } 530 mdb_printf("%?p: ar$hrd %x (%s)\n", addr, htype, cp); 531 mdb_printf("%?s ar$pro %x (%s)\n", "", ptype, 532 ptype == IP_ARP_PROTO_TYPE ? "IP" : "Unknown"); 533 534 switch (op) { 535 case ARPOP_REQUEST: 536 cp = "ares_op$REQUEST"; 537 break; 538 case ARPOP_REPLY: 539 cp = "ares_op$REPLY"; 540 break; 541 case REVARP_REQUEST: 542 cp = "arev_op$REQUEST"; 543 break; 544 case REVARP_REPLY: 545 cp = "arev_op$REPLY"; 546 break; 547 default: 548 cp = "Unknown"; 549 break; 550 } 551 mdb_printf("%?s ar$op %d (%s)\n", "", op, cp); 552 553 /* 554 * Note that we go to some length to attempt to print out the fixed 555 * header data before trying to decode the variable-length data. This 556 * is done to maximize the amount of useful information shown when the 557 * buffer is truncated or otherwise corrupt. 558 */ 559 blen = 2 * (arp.arh.arh_hlen + arp.arh.arh_plen); 560 if (mdb_vread(&arp.addrs, blen, addr + sizeof (arp.arh)) == -1) { 561 mdb_warn("unable to read ARP body at %p", addr); 562 return (DCMD_ERR); 563 } 564 565 print_arp('s', arp.addrs, &arp.arh, ptype); 566 print_arp('t', arp.addrs + arp.arh.arh_hlen + arp.arh.arh_plen, 567 &arp.arh, ptype); 568 return (DCMD_OK); 569 } 570 571 /* 572 * Print out an arp command formatted in a reasonable manner. This implements 573 * the type switch used by ARP. 574 * 575 * It could also dump the data that follows the header (using offset and length 576 * in the various structures), but it currently does not. 577 */ 578 /* ARGSUSED2 */ 579 static int 580 arpcmd_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 581 { 582 arc_t arc; 583 const arp_cmd_tbl *tp; 584 mdb_arg_t subargv; 585 586 if (!(flags & DCMD_ADDRSPEC)) { 587 mdb_warn("address required to print ARP command\n"); 588 return (DCMD_ERR); 589 } 590 if (mdb_vread(&arc, sizeof (arc), addr) == -1) { 591 mdb_warn("unable to read arc_t at %p", addr); 592 return (DCMD_ERR); 593 } 594 for (tp = act_list; tp->act_cmd != 0; tp++) 595 if (tp->act_cmd == arc.arc_cmd) 596 break; 597 mdb_printf("%p %s (%s) = ", addr, tp->act_name, tp->act_type); 598 subargv.a_type = MDB_TYPE_STRING; 599 subargv.a_un.a_str = tp->act_type; 600 if (mdb_call_dcmd("print", addr, DCMD_ADDRSPEC, 1, &subargv) == -1) 601 return (DCMD_ERR); 602 else 603 return (DCMD_OK); 604 } 605 606 static size_t 607 mi_osize(const queue_t *q) 608 { 609 /* 610 * The code in common/inet/mi.c allocates an extra word to store the 611 * size of the allocation. An mi_o_s is thus a size_t plus an mi_o_s. 612 */ 613 struct mi_block { 614 size_t mi_nbytes; 615 struct mi_o_s mi_o; 616 } m; 617 618 if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr - sizeof (m)) != -1) 619 return (m.mi_nbytes - sizeof (m)); 620 621 return (0); 622 } 623 624 /* 625 * This is called when ::stream is used and an ARP module is seen on the 626 * stream. Determine what sort of ARP usage is involved and show an 627 * appropriate message. 628 */ 629 static void 630 arp_qinfo(const queue_t *qp, char *buf, size_t nbytes) 631 { 632 size_t size = mi_osize(qp); 633 ar_t ar; 634 635 if (size != sizeof (ar_t)) 636 return; 637 if (mdb_vread(&ar, sizeof (ar), (uintptr_t)qp->q_ptr) == -1) 638 return; 639 ar_describe(&ar, buf, nbytes, B_TRUE); 640 } 641 642 static uintptr_t 643 arp_rnext(const queue_t *q) 644 { 645 size_t size = mi_osize(q); 646 ar_t ar; 647 648 if (size == sizeof (ar_t) && mdb_vread(&ar, sizeof (ar), 649 (uintptr_t)q->q_ptr) != -1) 650 return ((uintptr_t)ar.ar_rq); 651 652 return (NULL); 653 } 654 655 static uintptr_t 656 arp_wnext(const queue_t *q) 657 { 658 size_t size = mi_osize(q); 659 ar_t ar; 660 661 if (size == sizeof (ar_t) && mdb_vread(&ar, sizeof (ar), 662 (uintptr_t)q->q_ptr) != -1) 663 return ((uintptr_t)ar.ar_wq); 664 665 return (NULL); 666 } 667 668 static const mdb_dcmd_t dcmds[] = { 669 { "ar", "?", "display ARP client streams", ar_cmd, NULL }, 670 { "arl", "?", "display ARP link layers", arl_cmd, NULL }, 671 { "ace", "?", "display ARP cache entries", ace_cmd, NULL }, 672 { "arphdr", ":", "display an ARP header", arphdr_cmd, NULL }, 673 { "arpcmd", ":", "display an ARP command", arpcmd_cmd, NULL }, 674 { NULL } 675 }; 676 677 /* Note: ar_t walker is in genunix.c and net.c; generic MI walker */ 678 static const mdb_walker_t walkers[] = { 679 { "arl", "walk list of arl_t links", 680 arl_walk_init, arl_walk_step, NULL }, 681 { "ace", "walk list of ace_t entries", 682 ace_walk_init, ace_walk_step, ace_walk_fini }, 683 { NULL } 684 }; 685 686 static const mdb_qops_t arp_qops = { arp_qinfo, arp_rnext, arp_wnext }; 687 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 688 689 const mdb_modinfo_t * 690 _mdb_init(void) 691 { 692 GElf_Sym sym; 693 694 if (mdb_lookup_by_obj("arp", "winit", &sym) == 0) 695 mdb_qops_install(&arp_qops, (uintptr_t)sym.st_value); 696 697 return (&modinfo); 698 } 699 700 void 701 _mdb_fini(void) 702 { 703 GElf_Sym sym; 704 705 if (mdb_lookup_by_obj("arp", "winit", &sym) == 0) 706 mdb_qops_remove(&arp_qops, (uintptr_t)sym.st_value); 707 } 708