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