12546Scarlsonj /* 22546Scarlsonj * CDDL HEADER START 32546Scarlsonj * 42546Scarlsonj * The contents of this file are subject to the terms of the 52546Scarlsonj * Common Development and Distribution License (the "License"). 62546Scarlsonj * You may not use this file except in compliance with the License. 72546Scarlsonj * 82546Scarlsonj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92546Scarlsonj * or http://www.opensolaris.org/os/licensing. 102546Scarlsonj * See the License for the specific language governing permissions 112546Scarlsonj * and limitations under the License. 122546Scarlsonj * 132546Scarlsonj * When distributing Covered Code, include this CDDL HEADER in each 142546Scarlsonj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152546Scarlsonj * If applicable, add the following below this CDDL HEADER, with the 162546Scarlsonj * fields enclosed by brackets "[]" replaced with your own identifying 172546Scarlsonj * information: Portions Copyright [yyyy] [name of copyright owner] 182546Scarlsonj * 192546Scarlsonj * CDDL HEADER END 202546Scarlsonj */ 212546Scarlsonj /* 22*3865Szf203873 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 232546Scarlsonj * Use is subject to license terms. 242546Scarlsonj */ 252546Scarlsonj 262546Scarlsonj #pragma ident "%Z%%M% %I% %E% SMI" 272546Scarlsonj 282546Scarlsonj #include <stdio.h> 292546Scarlsonj #include <sys/types.h> 302546Scarlsonj #include <sys/stropts.h> 312546Scarlsonj #include <sys/stream.h> 322546Scarlsonj #include <sys/dlpi.h> 332958Sdr146992 #include <sys/hook.h> 342958Sdr146992 #include <sys/hook_event.h> 352546Scarlsonj #include <inet/led.h> 362546Scarlsonj #include <inet/common.h> 372546Scarlsonj #include <inet/mi.h> 382546Scarlsonj #include <inet/arp.h> 392546Scarlsonj #include <inet/arp_impl.h> 402546Scarlsonj #include <inet/ip.h> 412546Scarlsonj #include <netinet/arp.h> 422546Scarlsonj 432546Scarlsonj #include <mdb/mdb_modapi.h> 442546Scarlsonj #include <mdb/mdb_ks.h> 452546Scarlsonj 462546Scarlsonj typedef struct { 472546Scarlsonj uint32_t act_cmd; 482546Scarlsonj char *act_name; 492546Scarlsonj char *act_type; 502546Scarlsonj } arp_cmd_tbl; 512546Scarlsonj 522546Scarlsonj /* 532546Scarlsonj * Table of ARP commands and structure types used for messages between ARP and 542546Scarlsonj * IP. 552546Scarlsonj */ 562546Scarlsonj static const arp_cmd_tbl act_list[] = { 572546Scarlsonj { AR_ENTRY_ADD, "AR_ENTRY_ADD", "arp`area_t" }, 582546Scarlsonj { AR_ENTRY_DELETE, "AR_ENTRY_DELETE", "arp`ared_t" }, 592546Scarlsonj { AR_ENTRY_QUERY, "AR_ENTRY_QUERY", "arp`areq_t" }, 602546Scarlsonj { AR_ENTRY_SQUERY, "AR_ENTRY_SQUERY", "arp`area_t" }, 612546Scarlsonj { AR_MAPPING_ADD, "AR_MAPPING_ADD", "arp`arma_t" }, 622546Scarlsonj { AR_CLIENT_NOTIFY, "AR_CLIENT_NOTIFY", "arp`arcn_t" }, 632546Scarlsonj { AR_INTERFACE_UP, "AR_INTERFACE_UP", "arp`arc_t" }, 642546Scarlsonj { AR_INTERFACE_DOWN, "AR_INTERFACE_DOWN", "arp`arc_t" }, 652546Scarlsonj { AR_INTERFACE_ON, "AR_INTERFACE_ON", "arp`arc_t" }, 662546Scarlsonj { AR_INTERFACE_OFF, "AR_INTERFACE_OFF", "arp`arc_t" }, 672546Scarlsonj { AR_DLPIOP_DONE, "AR_DLPIOP_DONE", "arp`arc_t" }, 682546Scarlsonj { AR_ARP_CLOSING, "AR_ARP_CLOSING", "arp`arc_t" }, 692546Scarlsonj { AR_ARP_EXTEND, "AR_ARP_EXTEND", "arp`arc_t" }, 702546Scarlsonj { 0, "unknown command", "arp`arc_t" } 712546Scarlsonj }; 722546Scarlsonj 732546Scarlsonj /* 742546Scarlsonj * State information kept during walk over ACE hash table and unhashed mask 752546Scarlsonj * list. 762546Scarlsonj */ 772546Scarlsonj typedef struct ace_walk_data { 782546Scarlsonj ace_t *awd_hash_tbl[ARP_HASH_SIZE]; 792546Scarlsonj ace_t *awd_masks; 802546Scarlsonj int awd_idx; 812546Scarlsonj } ace_walk_data_t; 822546Scarlsonj 83*3865Szf203873 /* 84*3865Szf203873 * Given the kernel address of an arl_t, return the stackid 85*3865Szf203873 */ 862546Scarlsonj static int 87*3865Szf203873 arl_to_stackid(uintptr_t addr) 882546Scarlsonj { 89*3865Szf203873 arl_t arl; 90*3865Szf203873 queue_t rq; 91*3865Szf203873 ar_t ar; 92*3865Szf203873 arp_stack_t ass; 93*3865Szf203873 netstack_t nss; 94*3865Szf203873 95*3865Szf203873 if (mdb_vread(&arl, sizeof (arl), addr) == -1) { 96*3865Szf203873 mdb_warn("failed to read arl_t %p", addr); 97*3865Szf203873 return (0); 98*3865Szf203873 } 99*3865Szf203873 100*3865Szf203873 addr = (uintptr_t)arl.arl_rq; 101*3865Szf203873 if (mdb_vread(&rq, sizeof (rq), addr) == -1) { 102*3865Szf203873 mdb_warn("failed to read queue_t %p", addr); 103*3865Szf203873 return (0); 104*3865Szf203873 } 105*3865Szf203873 106*3865Szf203873 addr = (uintptr_t)rq.q_ptr; 107*3865Szf203873 if (mdb_vread(&ar, sizeof (ar), addr) == -1) { 108*3865Szf203873 mdb_warn("failed to read ar_t %p", addr); 109*3865Szf203873 return (0); 110*3865Szf203873 } 111*3865Szf203873 112*3865Szf203873 addr = (uintptr_t)ar.ar_as; 113*3865Szf203873 if (mdb_vread(&ass, sizeof (ass), addr) == -1) { 114*3865Szf203873 mdb_warn("failed to read arp_stack_t %p", addr); 115*3865Szf203873 return (0); 116*3865Szf203873 } 117*3865Szf203873 addr = (uintptr_t)ass.as_netstack; 118*3865Szf203873 if (mdb_vread(&nss, sizeof (nss), addr) == -1) { 119*3865Szf203873 mdb_warn("failed to read netstack_t %p", addr); 120*3865Szf203873 return (0); 121*3865Szf203873 } 122*3865Szf203873 return (nss.netstack_stackid); 123*3865Szf203873 } 124*3865Szf203873 125*3865Szf203873 static int 126*3865Szf203873 arp_stacks_walk_init(mdb_walk_state_t *wsp) 127*3865Szf203873 { 128*3865Szf203873 if (mdb_layered_walk("netstack", wsp) == -1) { 129*3865Szf203873 mdb_warn("can't walk 'netstack'"); 130*3865Szf203873 return (WALK_ERR); 131*3865Szf203873 } 132*3865Szf203873 return (WALK_NEXT); 133*3865Szf203873 } 134*3865Szf203873 135*3865Szf203873 static int 136*3865Szf203873 arp_stacks_walk_step(mdb_walk_state_t *wsp) 137*3865Szf203873 { 138*3865Szf203873 uintptr_t addr; 139*3865Szf203873 netstack_t nss; 140*3865Szf203873 141*3865Szf203873 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 142*3865Szf203873 mdb_warn("can't read netstack at %p", wsp->walk_addr); 143*3865Szf203873 return (WALK_ERR); 144*3865Szf203873 } 145*3865Szf203873 addr = (uintptr_t)nss.netstack_modules[NS_ARP]; 146*3865Szf203873 147*3865Szf203873 return (wsp->walk_callback(addr, wsp->walk_layer, wsp->walk_cbdata)); 148*3865Szf203873 } 149*3865Szf203873 150*3865Szf203873 static int 151*3865Szf203873 arl_stack_walk_init(mdb_walk_state_t *wsp) 152*3865Szf203873 { 153*3865Szf203873 uintptr_t addr; 154*3865Szf203873 155*3865Szf203873 if (wsp->walk_addr == NULL) { 156*3865Szf203873 mdb_warn("arl_stack supports only local walks\n"); 157*3865Szf203873 return (WALK_ERR); 158*3865Szf203873 } 159*3865Szf203873 160*3865Szf203873 addr = wsp->walk_addr + OFFSETOF(arp_stack_t, as_arl_head); 161*3865Szf203873 if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr), 162*3865Szf203873 addr) == -1) { 1632546Scarlsonj mdb_warn("failed to read 'arl_g_head'"); 1642546Scarlsonj return (WALK_ERR); 1652546Scarlsonj } 1662546Scarlsonj return (WALK_NEXT); 1672546Scarlsonj } 1682546Scarlsonj 1692546Scarlsonj static int 170*3865Szf203873 arl_stack_walk_step(mdb_walk_state_t *wsp) 1712546Scarlsonj { 1722546Scarlsonj uintptr_t addr = wsp->walk_addr; 1732546Scarlsonj arl_t arl; 1742546Scarlsonj 1752546Scarlsonj if (wsp->walk_addr == NULL) 1762546Scarlsonj return (WALK_DONE); 1772546Scarlsonj 1782546Scarlsonj if (mdb_vread(&arl, sizeof (arl), addr) == -1) { 1792546Scarlsonj mdb_warn("failed to read arl_t at %p", addr); 1802546Scarlsonj return (WALK_ERR); 1812546Scarlsonj } 1822546Scarlsonj 1832546Scarlsonj wsp->walk_addr = (uintptr_t)arl.arl_next; 1842546Scarlsonj 1852546Scarlsonj return ((*wsp->walk_callback)(addr, &arl, wsp->walk_cbdata)); 1862546Scarlsonj } 1872546Scarlsonj 1882546Scarlsonj static int 189*3865Szf203873 arl_walk_init(mdb_walk_state_t *wsp) 190*3865Szf203873 { 191*3865Szf203873 if (mdb_layered_walk("arp_stacks", wsp) == -1) { 192*3865Szf203873 mdb_warn("can't walk 'arp_stacks'"); 193*3865Szf203873 return (WALK_ERR); 194*3865Szf203873 } 195*3865Szf203873 196*3865Szf203873 return (WALK_NEXT); 197*3865Szf203873 } 198*3865Szf203873 199*3865Szf203873 static int 200*3865Szf203873 arl_walk_step(mdb_walk_state_t *wsp) 201*3865Szf203873 { 202*3865Szf203873 if (mdb_pwalk("arl_stack", wsp->walk_callback, 203*3865Szf203873 wsp->walk_cbdata, wsp->walk_addr) == -1) { 204*3865Szf203873 mdb_warn("couldn't walk 'arl_stack' at %p", wsp->walk_addr); 205*3865Szf203873 return (WALK_ERR); 206*3865Szf203873 } 207*3865Szf203873 return (WALK_NEXT); 208*3865Szf203873 } 209*3865Szf203873 210*3865Szf203873 /* 211*3865Szf203873 * Called with walk_addr being the address of arp_stack_t 212*3865Szf203873 */ 213*3865Szf203873 static int 214*3865Szf203873 ace_stack_walk_init(mdb_walk_state_t *wsp) 2152546Scarlsonj { 2162546Scarlsonj ace_walk_data_t *aw; 217*3865Szf203873 uintptr_t addr; 2182546Scarlsonj 219*3865Szf203873 if (wsp->walk_addr == NULL) { 220*3865Szf203873 mdb_warn("ace_stack supports only local walks\n"); 2212546Scarlsonj return (WALK_ERR); 2222546Scarlsonj } 2232546Scarlsonj 2242546Scarlsonj aw = mdb_alloc(sizeof (ace_walk_data_t), UM_SLEEP); 2252546Scarlsonj 226*3865Szf203873 addr = wsp->walk_addr + OFFSETOF(arp_stack_t, as_ce_hash_tbl); 227*3865Szf203873 if (mdb_vread(aw->awd_hash_tbl, sizeof (aw->awd_hash_tbl), 228*3865Szf203873 addr) == -1) { 229*3865Szf203873 mdb_warn("failed to read 'as_ce_hash_tbl'"); 2302546Scarlsonj mdb_free(aw, sizeof (ace_walk_data_t)); 2312546Scarlsonj return (WALK_ERR); 2322546Scarlsonj } 2332546Scarlsonj 234*3865Szf203873 addr = wsp->walk_addr + OFFSETOF(arp_stack_t, as_ce_mask_entries); 235*3865Szf203873 if (mdb_vread(&aw->awd_masks, sizeof (aw->awd_masks), 236*3865Szf203873 addr) == -1) { 237*3865Szf203873 mdb_warn("failed to read 'as_ce_mask_entries'"); 2382546Scarlsonj mdb_free(aw, sizeof (ace_walk_data_t)); 2392546Scarlsonj return (WALK_ERR); 2402546Scarlsonj } 2412546Scarlsonj 2422546Scarlsonj /* The step routine will start off by incrementing to index 0 */ 2432546Scarlsonj aw->awd_idx = -1; 2442546Scarlsonj wsp->walk_addr = 0; 2452546Scarlsonj wsp->walk_data = aw; 2462546Scarlsonj 2472546Scarlsonj return (WALK_NEXT); 2482546Scarlsonj } 2492546Scarlsonj 2502546Scarlsonj static int 251*3865Szf203873 ace_stack_walk_step(mdb_walk_state_t *wsp) 2522546Scarlsonj { 2532546Scarlsonj uintptr_t addr; 2542546Scarlsonj ace_walk_data_t *aw = wsp->walk_data; 2552546Scarlsonj ace_t ace; 2562546Scarlsonj 2572546Scarlsonj /* 2582546Scarlsonj * If we're at the end of the previous list, then find the start of the 2592546Scarlsonj * next list to process. 2602546Scarlsonj */ 2612546Scarlsonj while (wsp->walk_addr == NULL) { 2622546Scarlsonj if (aw->awd_idx == ARP_HASH_SIZE) 2632546Scarlsonj return (WALK_DONE); 2642546Scarlsonj if (++aw->awd_idx == ARP_HASH_SIZE) { 2652546Scarlsonj wsp->walk_addr = (uintptr_t)aw->awd_masks; 2662546Scarlsonj } else { 2672546Scarlsonj wsp->walk_addr = 2682546Scarlsonj (uintptr_t)aw->awd_hash_tbl[aw->awd_idx]; 2692546Scarlsonj } 2702546Scarlsonj } 2712546Scarlsonj 2722546Scarlsonj addr = wsp->walk_addr; 2732546Scarlsonj if (mdb_vread(&ace, sizeof (ace), addr) == -1) { 2742546Scarlsonj mdb_warn("failed to read ace_t at %p", addr); 2752546Scarlsonj return (WALK_ERR); 2762546Scarlsonj } 2772546Scarlsonj 2782546Scarlsonj wsp->walk_addr = (uintptr_t)ace.ace_next; 2792546Scarlsonj 2802546Scarlsonj return (wsp->walk_callback(addr, &ace, wsp->walk_cbdata)); 2812546Scarlsonj } 2822546Scarlsonj 2832546Scarlsonj static void 284*3865Szf203873 ace_stack_walk_fini(mdb_walk_state_t *wsp) 2852546Scarlsonj { 2862546Scarlsonj mdb_free(wsp->walk_data, sizeof (ace_walk_data_t)); 2872546Scarlsonj } 2882546Scarlsonj 289*3865Szf203873 static int 290*3865Szf203873 ace_walk_init(mdb_walk_state_t *wsp) 291*3865Szf203873 { 292*3865Szf203873 if (mdb_layered_walk("arp_stacks", wsp) == -1) { 293*3865Szf203873 mdb_warn("can't walk 'arp_stacks'"); 294*3865Szf203873 return (WALK_ERR); 295*3865Szf203873 } 296*3865Szf203873 297*3865Szf203873 return (WALK_NEXT); 298*3865Szf203873 } 299*3865Szf203873 300*3865Szf203873 static int 301*3865Szf203873 ace_walk_step(mdb_walk_state_t *wsp) 302*3865Szf203873 { 303*3865Szf203873 if (mdb_pwalk("ace_stack", wsp->walk_callback, 304*3865Szf203873 wsp->walk_cbdata, wsp->walk_addr) == -1) { 305*3865Szf203873 mdb_warn("couldn't walk 'ace_stack' at %p", wsp->walk_addr); 306*3865Szf203873 return (WALK_ERR); 307*3865Szf203873 } 308*3865Szf203873 return (WALK_NEXT); 309*3865Szf203873 } 310*3865Szf203873 311*3865Szf203873 3122546Scarlsonj /* Common routine to produce an 'ar' text description */ 3132546Scarlsonj static void 3142546Scarlsonj ar_describe(const ar_t *ar, char *buf, size_t nbytes, boolean_t addmac) 3152546Scarlsonj { 3162546Scarlsonj if (ar->ar_arl == NULL) { 3172546Scarlsonj queue_t wq, ipq; 3182546Scarlsonj ill_t ill; 3192546Scarlsonj char name[LIFNAMSIZ]; 3202546Scarlsonj GElf_Sym sym; 3212546Scarlsonj boolean_t nextip; 3222546Scarlsonj 3232546Scarlsonj if (mdb_vread(&wq, sizeof (wq), (uintptr_t)ar->ar_wq) == -1 || 3242546Scarlsonj mdb_vread(&ipq, sizeof (ipq), (uintptr_t)wq.q_next) == -1) 3252546Scarlsonj return; 3262546Scarlsonj 3272546Scarlsonj nextip = 3282546Scarlsonj (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0 && 3292546Scarlsonj (uintptr_t)sym.st_value == (uintptr_t)ipq.q_qinfo); 3302546Scarlsonj 3312546Scarlsonj if (!ar->ar_on_ill_stream) { 3322546Scarlsonj (void) strcpy(buf, nextip ? "Client" : "Unknown"); 3332546Scarlsonj return; 3342546Scarlsonj } 3352546Scarlsonj 3362546Scarlsonj if (!nextip || 3372546Scarlsonj mdb_vread(&ill, sizeof (ill), (uintptr_t)ipq.q_ptr) == -1 || 3382546Scarlsonj mdb_readstr(name, sizeof (name), 3392546Scarlsonj (uintptr_t)ill.ill_name) == -1) { 3402546Scarlsonj return; 3412546Scarlsonj } 3422546Scarlsonj (void) mdb_snprintf(buf, nbytes, "IP %s", name); 3432546Scarlsonj } else { 3442546Scarlsonj arl_t arl; 3453065Smeem arlphy_t ap; 3462546Scarlsonj ssize_t retv; 3472546Scarlsonj uint32_t alen; 3482546Scarlsonj uchar_t macaddr[ARP_MAX_ADDR_LEN]; 3492546Scarlsonj 3502546Scarlsonj if (mdb_vread(&arl, sizeof (arl), (uintptr_t)ar->ar_arl) == -1) 3512546Scarlsonj return; 3522546Scarlsonj retv = mdb_snprintf(buf, nbytes, "ARP %s ", arl.arl_name); 3532546Scarlsonj if (retv >= nbytes || !addmac) 3542546Scarlsonj return; 3553065Smeem if (mdb_vread(&ap, sizeof (ap), (uintptr_t)arl.arl_phy) == -1) 3563065Smeem return; 3573065Smeem alen = ap.ap_hw_addrlen; 3583065Smeem if (ap.ap_hw_addr == NULL || alen == 0 || 3592546Scarlsonj alen > sizeof (macaddr)) 3602546Scarlsonj return; 3613065Smeem if (mdb_vread(macaddr, alen, (uintptr_t)ap.ap_hw_addr) == -1) 3622546Scarlsonj return; 3632546Scarlsonj mdb_mac_addr(macaddr, alen, buf + retv, nbytes - retv); 3642546Scarlsonj } 3652546Scarlsonj } 3662546Scarlsonj 3672546Scarlsonj /* ARGSUSED2 */ 3682546Scarlsonj static int 3692546Scarlsonj ar_cb(uintptr_t addr, const void *arptr, void *dummy) 3702546Scarlsonj { 3712546Scarlsonj const ar_t *ar = arptr; 3722546Scarlsonj char ardesc[sizeof ("ARP ") + LIFNAMSIZ]; 3732546Scarlsonj 3742546Scarlsonj ar_describe(ar, ardesc, sizeof (ardesc), B_FALSE); 3752546Scarlsonj mdb_printf("%?p %?p %?p %s\n", addr, ar->ar_wq, ar->ar_arl, ardesc); 3762546Scarlsonj return (WALK_NEXT); 3772546Scarlsonj } 3782546Scarlsonj 3792546Scarlsonj /* 3802546Scarlsonj * Print out ARP client structures. 3812546Scarlsonj */ 3822546Scarlsonj /* ARGSUSED2 */ 3832546Scarlsonj static int 3842546Scarlsonj ar_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3852546Scarlsonj { 3862546Scarlsonj ar_t ar; 3872546Scarlsonj 3882546Scarlsonj if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 3892546Scarlsonj mdb_printf("%<u>%?s %?s %?s %s%</u>\n", 3902546Scarlsonj "AR", "WQ", "ARL", "TYPE"); 3912546Scarlsonj } 3922546Scarlsonj 3932546Scarlsonj if (flags & DCMD_ADDRSPEC) { 3942546Scarlsonj if (mdb_vread(&ar, sizeof (ar), addr) == -1) { 3952546Scarlsonj mdb_warn("failed to read ar_t at %p", addr); 3962546Scarlsonj return (DCMD_ERR); 3972546Scarlsonj } 3982546Scarlsonj (void) ar_cb(addr, &ar, NULL); 3992546Scarlsonj } else { 4002546Scarlsonj if (mdb_walk("ar", ar_cb, NULL) == -1) { 4012546Scarlsonj mdb_warn("cannot walk ar_t structures"); 4022546Scarlsonj return (DCMD_ERR); 4032546Scarlsonj } 4042546Scarlsonj } 4052546Scarlsonj return (DCMD_OK); 4062546Scarlsonj } 4072546Scarlsonj 4082546Scarlsonj /* ARGSUSED2 */ 4092546Scarlsonj static int 4102546Scarlsonj arl_cb(uintptr_t addr, const void *arlptr, void *dummy) 4112546Scarlsonj { 4122546Scarlsonj const arl_t *arl = arlptr; 4133065Smeem arlphy_t ap; 4142546Scarlsonj uchar_t macaddr[ARP_MAX_ADDR_LEN]; 4152546Scarlsonj char macstr[ARP_MAX_ADDR_LEN*3]; 4162546Scarlsonj char flags[4]; 4172546Scarlsonj const char *primstr; 4182546Scarlsonj 4192546Scarlsonj mdb_printf("%?p ", addr); 4202546Scarlsonj if (arl->arl_dlpi_pending == DL_PRIM_INVAL) 4212546Scarlsonj mdb_printf("%16s", "--"); 4222546Scarlsonj else if ((primstr = mdb_dlpi_prim(arl->arl_dlpi_pending)) != NULL) 4232546Scarlsonj mdb_printf("%16s", primstr); 4242546Scarlsonj else 4252546Scarlsonj mdb_printf("%16x", arl->arl_dlpi_pending); 4263065Smeem 4273065Smeem if (mdb_vread(&ap, sizeof (ap), (uintptr_t)arl->arl_phy) == -1 || 4283065Smeem ap.ap_hw_addrlen == 0 || ap.ap_hw_addrlen > sizeof (macaddr)) { 4292546Scarlsonj (void) strcpy(macstr, "--"); 4303065Smeem } else if (mdb_vread(macaddr, ap.ap_hw_addrlen, 4313065Smeem (uintptr_t)ap.ap_hw_addr) == -1) { 4322546Scarlsonj (void) strcpy(macstr, "?"); 4332546Scarlsonj } else { 4343065Smeem mdb_mac_addr(macaddr, ap.ap_hw_addrlen, macstr, 4352546Scarlsonj sizeof (macstr)); 4362546Scarlsonj } 4372546Scarlsonj 4382546Scarlsonj /* Print both the link-layer state and the NOARP flag */ 4392546Scarlsonj flags[0] = '\0'; 4402546Scarlsonj if (arl->arl_flags & ARL_F_NOARP) 4412546Scarlsonj (void) strcat(flags, "N"); 4422546Scarlsonj switch (arl->arl_state) { 4432546Scarlsonj case ARL_S_DOWN: 4442546Scarlsonj (void) strcat(flags, "d"); 4452546Scarlsonj break; 4462546Scarlsonj case ARL_S_PENDING: 4472546Scarlsonj (void) strcat(flags, "P"); 4482546Scarlsonj break; 4492546Scarlsonj case ARL_S_UP: 4502546Scarlsonj (void) strcat(flags, "U"); 4512546Scarlsonj break; 4522546Scarlsonj default: 4532546Scarlsonj (void) strcat(flags, "?"); 4542546Scarlsonj break; 4552546Scarlsonj } 456*3865Szf203873 mdb_printf(" %8d %-3s %-9s %-17s %5d\n", 4572546Scarlsonj mdb_mblk_count(arl->arl_dlpi_deferred), flags, arl->arl_name, 458*3865Szf203873 macstr, arl_to_stackid((uintptr_t)addr)); 4592546Scarlsonj return (WALK_NEXT); 4602546Scarlsonj } 4612546Scarlsonj 4622546Scarlsonj /* 4632546Scarlsonj * Print out ARP link-layer elements. 4642546Scarlsonj */ 4652546Scarlsonj /* ARGSUSED2 */ 4662546Scarlsonj static int 4672546Scarlsonj arl_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4682546Scarlsonj { 4692546Scarlsonj arl_t arl; 4702546Scarlsonj 4712546Scarlsonj if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 472*3865Szf203873 mdb_printf("%<u>%?s %16s %8s %3s %9s %-17s %5s%</u>\n", 4732546Scarlsonj "ARL", "DLPI REQ", "DLPI CNT", "FLG", "INTERFACE", 474*3865Szf203873 "HWADDR", "STACK"); 4752546Scarlsonj } 4762546Scarlsonj 4772546Scarlsonj if (flags & DCMD_ADDRSPEC) { 4782546Scarlsonj if (mdb_vread(&arl, sizeof (arl), addr) == -1) { 4792546Scarlsonj mdb_warn("failed to read arl_t at %p", addr); 4802546Scarlsonj return (DCMD_ERR); 4812546Scarlsonj } 4822546Scarlsonj (void) arl_cb(addr, &arl, NULL); 4832546Scarlsonj } else { 4842546Scarlsonj if (mdb_walk("arl", arl_cb, NULL) == -1) { 4852546Scarlsonj mdb_warn("cannot walk arl_t structures"); 4862546Scarlsonj return (DCMD_ERR); 4872546Scarlsonj } 4882546Scarlsonj } 4892546Scarlsonj return (DCMD_OK); 4902546Scarlsonj } 4912546Scarlsonj 4922546Scarlsonj /* ARGSUSED2 */ 4932546Scarlsonj static int 4942546Scarlsonj ace_cb(uintptr_t addr, const void *aceptr, void *dummy) 4952546Scarlsonj { 4962546Scarlsonj const ace_t *ace = aceptr; 4972546Scarlsonj uchar_t macaddr[ARP_MAX_ADDR_LEN]; 4982546Scarlsonj char macstr[ARP_MAX_ADDR_LEN*3]; 4992546Scarlsonj /* The %b format isn't compact enough for long listings */ 5002546Scarlsonj static const char ace_flags[] = "SPDRMLdA ofya"; 5012546Scarlsonj const char *cp; 5022546Scarlsonj char flags[sizeof (ace_flags)], *fp; 5032546Scarlsonj int flg; 5042546Scarlsonj in_addr_t inaddr, mask; 5052546Scarlsonj char addrstr[sizeof ("255.255.255.255/32")]; 5062546Scarlsonj 5072546Scarlsonj /* Walk the list of flags and produce a string */ 5082546Scarlsonj cp = ace_flags; 5092546Scarlsonj fp = flags; 5102546Scarlsonj for (flg = 1; *cp != '\0'; flg <<= 1, cp++) { 5112546Scarlsonj if ((flg & ace->ace_flags) && *cp != ' ') 5122546Scarlsonj *fp++ = *cp; 5132546Scarlsonj } 5142546Scarlsonj *fp = '\0'; 5152546Scarlsonj 5162546Scarlsonj /* If it's not resolved, then it has no hardware address */ 5172546Scarlsonj if (!(ace->ace_flags & ACE_F_RESOLVED) || 5182546Scarlsonj ace->ace_hw_addr_length == 0 || 5192546Scarlsonj ace->ace_hw_addr_length > sizeof (macaddr)) { 5202546Scarlsonj (void) strcpy(macstr, "--"); 5212546Scarlsonj } else if (mdb_vread(macaddr, ace->ace_hw_addr_length, 5222546Scarlsonj (uintptr_t)ace->ace_hw_addr) == -1) { 5232546Scarlsonj (void) strcpy(macstr, "?"); 5242546Scarlsonj } else { 5252546Scarlsonj mdb_mac_addr(macaddr, ace->ace_hw_addr_length, macstr, 5262546Scarlsonj sizeof (macstr)); 5272546Scarlsonj } 5282546Scarlsonj 5292546Scarlsonj /* 5302546Scarlsonj * Nothing other than IP uses ARP these days, so we don't try very hard 5312546Scarlsonj * here to switch out on ARP protocol type. (Note that ARP protocol 5322546Scarlsonj * types are roughly Ethertypes, but are allocated separately at IANA.) 5332546Scarlsonj */ 5342546Scarlsonj if (ace->ace_proto != IP_ARP_PROTO_TYPE) { 5352546Scarlsonj (void) mdb_snprintf(addrstr, sizeof (addrstr), 5362546Scarlsonj "Unknown proto %x", ace->ace_proto); 5372546Scarlsonj } else if (mdb_vread(&inaddr, sizeof (inaddr), 5382546Scarlsonj (uintptr_t)ace->ace_proto_addr) != -1 && 5392546Scarlsonj mdb_vread(&mask, sizeof (mask), (uintptr_t)ace->ace_proto_mask) != 5402546Scarlsonj -1) { 5412546Scarlsonj /* 5422546Scarlsonj * If it's the standard host mask, then print it normally. 5432546Scarlsonj * Otherwise, use "/n" notation. 5442546Scarlsonj */ 5452546Scarlsonj if (mask == (in_addr_t)~0) { 5462546Scarlsonj (void) mdb_snprintf(addrstr, sizeof (addrstr), "%I", 5472546Scarlsonj inaddr); 5482546Scarlsonj } else { 5492546Scarlsonj (void) mdb_snprintf(addrstr, sizeof (addrstr), "%I/%d", 5502546Scarlsonj inaddr, mask == 0 ? 0 : 33 - mdb_ffs(mask)); 5512546Scarlsonj } 5522546Scarlsonj } else { 5532546Scarlsonj (void) strcpy(addrstr, "?"); 5542546Scarlsonj } 555*3865Szf203873 mdb_printf("%?p %-18s %-8s %-17s %5d\n", addr, addrstr, flags, 556*3865Szf203873 macstr, arl_to_stackid((uintptr_t)ace->ace_arl)); 5572546Scarlsonj return (WALK_NEXT); 5582546Scarlsonj } 5592546Scarlsonj 5602546Scarlsonj /* 5612546Scarlsonj * Print out ARP cache entry (ace_t) elements. 5622546Scarlsonj */ 5632546Scarlsonj /* ARGSUSED2 */ 5642546Scarlsonj static int 5652546Scarlsonj ace_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 5662546Scarlsonj { 5672546Scarlsonj ace_t ace; 5682546Scarlsonj 5692546Scarlsonj if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 570*3865Szf203873 mdb_printf("%<u>%?s %-18s %-8s %-17s %5s%</u>\n", 571*3865Szf203873 "ACE", "PROTOADDR", "FLAGS", "HWADDR", "STACK"); 5722546Scarlsonj } 5732546Scarlsonj 5742546Scarlsonj if (flags & DCMD_ADDRSPEC) { 5752546Scarlsonj if (mdb_vread(&ace, sizeof (ace), addr) == -1) { 5762546Scarlsonj mdb_warn("failed to read ace_t at %p", addr); 5772546Scarlsonj return (DCMD_ERR); 5782546Scarlsonj } 5792546Scarlsonj (void) ace_cb(addr, &ace, NULL); 5802546Scarlsonj } else { 5812546Scarlsonj if (mdb_walk("ace", ace_cb, NULL) == -1) { 5822546Scarlsonj mdb_warn("cannot walk ace_t structures"); 5832546Scarlsonj return (DCMD_ERR); 5842546Scarlsonj } 5852546Scarlsonj } 5862546Scarlsonj return (DCMD_OK); 5872546Scarlsonj } 5882546Scarlsonj 5892546Scarlsonj /* 5902546Scarlsonj * Print an ARP hardware and protocol address pair; used when printing an ARP 5912546Scarlsonj * message. 5922546Scarlsonj */ 5932546Scarlsonj static void 5942546Scarlsonj print_arp(char field_id, const uchar_t *buf, const arh_t *arh, uint16_t ptype) 5952546Scarlsonj { 5962546Scarlsonj char macstr[ARP_MAX_ADDR_LEN*3]; 5972546Scarlsonj in_addr_t inaddr; 5982546Scarlsonj 5992546Scarlsonj if (arh->arh_hlen == 0) 6002546Scarlsonj (void) strcpy(macstr, "(none)"); 6012546Scarlsonj else 6022546Scarlsonj mdb_mac_addr(buf, arh->arh_hlen, macstr, sizeof (macstr)); 6032546Scarlsonj mdb_printf("%?s ar$%cha %s\n", "", field_id, macstr); 6042546Scarlsonj if (arh->arh_plen == 0) { 6052546Scarlsonj mdb_printf("%?s ar$%cpa (none)\n", "", field_id); 6062546Scarlsonj } else if (ptype == IP_ARP_PROTO_TYPE) { 6072546Scarlsonj mdb_printf("%?s ar$%cpa (unknown)\n", "", field_id); 6082546Scarlsonj } else if (arh->arh_plen == sizeof (in_addr_t)) { 6092546Scarlsonj (void) memcpy(&inaddr, buf + arh->arh_hlen, sizeof (inaddr)); 6102546Scarlsonj mdb_printf("%?s ar$%cpa %I\n", "", field_id, inaddr); 6112546Scarlsonj } else { 6122546Scarlsonj mdb_printf("%?s ar$%cpa (malformed IP)\n", "", field_id); 6132546Scarlsonj } 6142546Scarlsonj } 6152546Scarlsonj 6162546Scarlsonj /* 6172546Scarlsonj * Decode an ARP message and display it. 6182546Scarlsonj */ 6192546Scarlsonj /* ARGSUSED2 */ 6202546Scarlsonj static int 6212546Scarlsonj arphdr_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 6222546Scarlsonj { 6232546Scarlsonj struct { 6242546Scarlsonj arh_t arh; 6252546Scarlsonj uchar_t addrs[4 * ARP_MAX_ADDR_LEN]; 6262546Scarlsonj } arp; 6272546Scarlsonj size_t blen; 6282546Scarlsonj uint16_t htype, ptype, op; 6292546Scarlsonj const char *cp; 6302546Scarlsonj 6312546Scarlsonj if (!(flags & DCMD_ADDRSPEC)) { 6322546Scarlsonj mdb_warn("address required to print ARP header\n"); 6332546Scarlsonj return (DCMD_ERR); 6342546Scarlsonj } 6352546Scarlsonj 6362546Scarlsonj if (mdb_vread(&arp.arh, sizeof (arp.arh), addr) == -1) { 6372546Scarlsonj mdb_warn("unable to read ARP header at %p", addr); 6382546Scarlsonj return (DCMD_ERR); 6392546Scarlsonj } 6402546Scarlsonj mdb_nhconvert(&htype, arp.arh.arh_hardware, sizeof (htype)); 6412546Scarlsonj mdb_nhconvert(&ptype, arp.arh.arh_proto, sizeof (ptype)); 6422546Scarlsonj mdb_nhconvert(&op, arp.arh.arh_operation, sizeof (op)); 6432546Scarlsonj 6442546Scarlsonj switch (htype) { 6452546Scarlsonj case ARPHRD_ETHER: 6462546Scarlsonj cp = "Ether"; 6472546Scarlsonj break; 6482546Scarlsonj case ARPHRD_IEEE802: 6492546Scarlsonj cp = "IEEE802"; 6502546Scarlsonj break; 6512546Scarlsonj case ARPHRD_IB: 6522546Scarlsonj cp = "InfiniBand"; 6532546Scarlsonj break; 6542546Scarlsonj default: 6552546Scarlsonj cp = "Unknown"; 6562546Scarlsonj break; 6572546Scarlsonj } 6582546Scarlsonj mdb_printf("%?p: ar$hrd %x (%s)\n", addr, htype, cp); 6592546Scarlsonj mdb_printf("%?s ar$pro %x (%s)\n", "", ptype, 6602546Scarlsonj ptype == IP_ARP_PROTO_TYPE ? "IP" : "Unknown"); 6612546Scarlsonj 6622546Scarlsonj switch (op) { 6632546Scarlsonj case ARPOP_REQUEST: 6642546Scarlsonj cp = "ares_op$REQUEST"; 6652546Scarlsonj break; 6662546Scarlsonj case ARPOP_REPLY: 6672546Scarlsonj cp = "ares_op$REPLY"; 6682546Scarlsonj break; 6692546Scarlsonj case REVARP_REQUEST: 6702546Scarlsonj cp = "arev_op$REQUEST"; 6712546Scarlsonj break; 6722546Scarlsonj case REVARP_REPLY: 6732546Scarlsonj cp = "arev_op$REPLY"; 6742546Scarlsonj break; 6752546Scarlsonj default: 6762546Scarlsonj cp = "Unknown"; 6772546Scarlsonj break; 6782546Scarlsonj } 6792546Scarlsonj mdb_printf("%?s ar$op %d (%s)\n", "", op, cp); 6802546Scarlsonj 6812546Scarlsonj /* 6822546Scarlsonj * Note that we go to some length to attempt to print out the fixed 6832546Scarlsonj * header data before trying to decode the variable-length data. This 6842546Scarlsonj * is done to maximize the amount of useful information shown when the 6852546Scarlsonj * buffer is truncated or otherwise corrupt. 6862546Scarlsonj */ 6872546Scarlsonj blen = 2 * (arp.arh.arh_hlen + arp.arh.arh_plen); 6882546Scarlsonj if (mdb_vread(&arp.addrs, blen, addr + sizeof (arp.arh)) == -1) { 6892546Scarlsonj mdb_warn("unable to read ARP body at %p", addr); 6902546Scarlsonj return (DCMD_ERR); 6912546Scarlsonj } 6922546Scarlsonj 6932546Scarlsonj print_arp('s', arp.addrs, &arp.arh, ptype); 6942546Scarlsonj print_arp('t', arp.addrs + arp.arh.arh_hlen + arp.arh.arh_plen, 6952546Scarlsonj &arp.arh, ptype); 6962546Scarlsonj return (DCMD_OK); 6972546Scarlsonj } 6982546Scarlsonj 6992546Scarlsonj /* 7002546Scarlsonj * Print out an arp command formatted in a reasonable manner. This implements 7012546Scarlsonj * the type switch used by ARP. 7022546Scarlsonj * 7032546Scarlsonj * It could also dump the data that follows the header (using offset and length 7042546Scarlsonj * in the various structures), but it currently does not. 7052546Scarlsonj */ 7062546Scarlsonj /* ARGSUSED2 */ 7072546Scarlsonj static int 7082546Scarlsonj arpcmd_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 7092546Scarlsonj { 7102546Scarlsonj arc_t arc; 7112546Scarlsonj const arp_cmd_tbl *tp; 7122546Scarlsonj mdb_arg_t subargv; 7132546Scarlsonj 7142546Scarlsonj if (!(flags & DCMD_ADDRSPEC)) { 7152546Scarlsonj mdb_warn("address required to print ARP command\n"); 7162546Scarlsonj return (DCMD_ERR); 7172546Scarlsonj } 7182546Scarlsonj if (mdb_vread(&arc, sizeof (arc), addr) == -1) { 7192546Scarlsonj mdb_warn("unable to read arc_t at %p", addr); 7202546Scarlsonj return (DCMD_ERR); 7212546Scarlsonj } 7222546Scarlsonj for (tp = act_list; tp->act_cmd != 0; tp++) 7232546Scarlsonj if (tp->act_cmd == arc.arc_cmd) 7242546Scarlsonj break; 7252546Scarlsonj mdb_printf("%p %s (%s) = ", addr, tp->act_name, tp->act_type); 7262546Scarlsonj subargv.a_type = MDB_TYPE_STRING; 7272546Scarlsonj subargv.a_un.a_str = tp->act_type; 7282546Scarlsonj if (mdb_call_dcmd("print", addr, DCMD_ADDRSPEC, 1, &subargv) == -1) 7292546Scarlsonj return (DCMD_ERR); 7302546Scarlsonj else 7312546Scarlsonj return (DCMD_OK); 7322546Scarlsonj } 7332546Scarlsonj 7342546Scarlsonj static size_t 7352546Scarlsonj mi_osize(const queue_t *q) 7362546Scarlsonj { 7372546Scarlsonj /* 7382546Scarlsonj * The code in common/inet/mi.c allocates an extra word to store the 7392546Scarlsonj * size of the allocation. An mi_o_s is thus a size_t plus an mi_o_s. 7402546Scarlsonj */ 7412546Scarlsonj struct mi_block { 7422546Scarlsonj size_t mi_nbytes; 7432546Scarlsonj struct mi_o_s mi_o; 7442546Scarlsonj } m; 7452546Scarlsonj 7462546Scarlsonj if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr - sizeof (m)) != -1) 7472546Scarlsonj return (m.mi_nbytes - sizeof (m)); 7482546Scarlsonj 7492546Scarlsonj return (0); 7502546Scarlsonj } 7512546Scarlsonj 7522546Scarlsonj /* 7532546Scarlsonj * This is called when ::stream is used and an ARP module is seen on the 7542546Scarlsonj * stream. Determine what sort of ARP usage is involved and show an 7552546Scarlsonj * appropriate message. 7562546Scarlsonj */ 7572546Scarlsonj static void 7582546Scarlsonj arp_qinfo(const queue_t *qp, char *buf, size_t nbytes) 7592546Scarlsonj { 7602546Scarlsonj size_t size = mi_osize(qp); 7612546Scarlsonj ar_t ar; 7622546Scarlsonj 7632546Scarlsonj if (size != sizeof (ar_t)) 7642546Scarlsonj return; 7652546Scarlsonj if (mdb_vread(&ar, sizeof (ar), (uintptr_t)qp->q_ptr) == -1) 7662546Scarlsonj return; 7672546Scarlsonj ar_describe(&ar, buf, nbytes, B_TRUE); 7682546Scarlsonj } 7692546Scarlsonj 7702546Scarlsonj static uintptr_t 7712546Scarlsonj arp_rnext(const queue_t *q) 7722546Scarlsonj { 7732546Scarlsonj size_t size = mi_osize(q); 7742546Scarlsonj ar_t ar; 7752546Scarlsonj 7762546Scarlsonj if (size == sizeof (ar_t) && mdb_vread(&ar, sizeof (ar), 7772546Scarlsonj (uintptr_t)q->q_ptr) != -1) 7782546Scarlsonj return ((uintptr_t)ar.ar_rq); 7792546Scarlsonj 7802546Scarlsonj return (NULL); 7812546Scarlsonj } 7822546Scarlsonj 7832546Scarlsonj static uintptr_t 7842546Scarlsonj arp_wnext(const queue_t *q) 7852546Scarlsonj { 7862546Scarlsonj size_t size = mi_osize(q); 7872546Scarlsonj ar_t ar; 7882546Scarlsonj 7892546Scarlsonj if (size == sizeof (ar_t) && mdb_vread(&ar, sizeof (ar), 7902546Scarlsonj (uintptr_t)q->q_ptr) != -1) 7912546Scarlsonj return ((uintptr_t)ar.ar_wq); 7922546Scarlsonj 7932546Scarlsonj return (NULL); 7942546Scarlsonj } 7952546Scarlsonj 7962546Scarlsonj static const mdb_dcmd_t dcmds[] = { 797*3865Szf203873 { "ar", "?", "display ARP client streams for all stacks", 798*3865Szf203873 ar_cmd, NULL }, 799*3865Szf203873 { "arl", "?", "display ARP link layers for all stacks", arl_cmd, NULL }, 800*3865Szf203873 { "ace", "?", "display ARP cache entries for all stacks", 801*3865Szf203873 ace_cmd, NULL }, 8022546Scarlsonj { "arphdr", ":", "display an ARP header", arphdr_cmd, NULL }, 8032546Scarlsonj { "arpcmd", ":", "display an ARP command", arpcmd_cmd, NULL }, 8042546Scarlsonj { NULL } 8052546Scarlsonj }; 8062546Scarlsonj 8072546Scarlsonj /* Note: ar_t walker is in genunix.c and net.c; generic MI walker */ 8082546Scarlsonj static const mdb_walker_t walkers[] = { 809*3865Szf203873 { "arl", "walk list of arl_t links for all stacks", 8102546Scarlsonj arl_walk_init, arl_walk_step, NULL }, 811*3865Szf203873 { "arl_stack", "walk list of arl_t links", 812*3865Szf203873 arl_stack_walk_init, arl_stack_walk_step, NULL }, 813*3865Szf203873 { "ace", "walk list of ace_t entries for all stacks", 814*3865Szf203873 ace_walk_init, ace_walk_step, NULL }, 815*3865Szf203873 { "ace_stack", "walk list of ace_t entries", 816*3865Szf203873 ace_stack_walk_init, ace_stack_walk_step, ace_stack_walk_fini }, 817*3865Szf203873 { "arp_stacks", "walk all the arp_stack_t", 818*3865Szf203873 arp_stacks_walk_init, arp_stacks_walk_step, NULL }, 8192546Scarlsonj { NULL } 8202546Scarlsonj }; 8212546Scarlsonj 8222546Scarlsonj static const mdb_qops_t arp_qops = { arp_qinfo, arp_rnext, arp_wnext }; 8232546Scarlsonj static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 8242546Scarlsonj 8252546Scarlsonj const mdb_modinfo_t * 8262546Scarlsonj _mdb_init(void) 8272546Scarlsonj { 8282546Scarlsonj GElf_Sym sym; 8292546Scarlsonj 8302546Scarlsonj if (mdb_lookup_by_obj("arp", "winit", &sym) == 0) 8312546Scarlsonj mdb_qops_install(&arp_qops, (uintptr_t)sym.st_value); 8322546Scarlsonj 8332546Scarlsonj return (&modinfo); 8342546Scarlsonj } 8352546Scarlsonj 8362546Scarlsonj void 8372546Scarlsonj _mdb_fini(void) 8382546Scarlsonj { 8392546Scarlsonj GElf_Sym sym; 8402546Scarlsonj 8412546Scarlsonj if (mdb_lookup_by_obj("arp", "winit", &sym) == 0) 8422546Scarlsonj mdb_qops_remove(&arp_qops, (uintptr_t)sym.st_value); 8432546Scarlsonj } 844