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 /* 222546Scarlsonj * Copyright 2006 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> 33*2958Sdr146992 #include <sys/hook.h> 34*2958Sdr146992 #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 832546Scarlsonj static int 842546Scarlsonj arl_walk_init(mdb_walk_state_t *wsp) 852546Scarlsonj { 862546Scarlsonj if (wsp->walk_addr == NULL && 872546Scarlsonj mdb_readvar(&wsp->walk_addr, "arl_g_head") == -1) { 882546Scarlsonj mdb_warn("failed to read 'arl_g_head'"); 892546Scarlsonj return (WALK_ERR); 902546Scarlsonj } 912546Scarlsonj return (WALK_NEXT); 922546Scarlsonj } 932546Scarlsonj 942546Scarlsonj static int 952546Scarlsonj arl_walk_step(mdb_walk_state_t *wsp) 962546Scarlsonj { 972546Scarlsonj uintptr_t addr = wsp->walk_addr; 982546Scarlsonj arl_t arl; 992546Scarlsonj 1002546Scarlsonj if (wsp->walk_addr == NULL) 1012546Scarlsonj return (WALK_DONE); 1022546Scarlsonj 1032546Scarlsonj if (mdb_vread(&arl, sizeof (arl), addr) == -1) { 1042546Scarlsonj mdb_warn("failed to read arl_t at %p", addr); 1052546Scarlsonj return (WALK_ERR); 1062546Scarlsonj } 1072546Scarlsonj 1082546Scarlsonj wsp->walk_addr = (uintptr_t)arl.arl_next; 1092546Scarlsonj 1102546Scarlsonj return ((*wsp->walk_callback)(addr, &arl, wsp->walk_cbdata)); 1112546Scarlsonj } 1122546Scarlsonj 1132546Scarlsonj static int 1142546Scarlsonj ace_walk_init(mdb_walk_state_t *wsp) 1152546Scarlsonj { 1162546Scarlsonj ace_walk_data_t *aw; 1172546Scarlsonj 1182546Scarlsonj if (wsp->walk_addr != NULL) { 1192546Scarlsonj mdb_warn("ace supports only global walks\n"); 1202546Scarlsonj return (WALK_ERR); 1212546Scarlsonj } 1222546Scarlsonj 1232546Scarlsonj aw = mdb_alloc(sizeof (ace_walk_data_t), UM_SLEEP); 1242546Scarlsonj 1252546Scarlsonj if (mdb_readsym(aw->awd_hash_tbl, sizeof (aw->awd_hash_tbl), 1262546Scarlsonj "ar_ce_hash_tbl") == -1) { 1272546Scarlsonj mdb_warn("failed to read 'ar_ce_hash_tbl'"); 1282546Scarlsonj mdb_free(aw, sizeof (ace_walk_data_t)); 1292546Scarlsonj return (WALK_ERR); 1302546Scarlsonj } 1312546Scarlsonj 1322546Scarlsonj if (mdb_readvar(&aw->awd_masks, "ar_ce_mask_entries") == -1) { 1332546Scarlsonj mdb_warn("failed to read 'ar_ce_mask_entries'"); 1342546Scarlsonj mdb_free(aw, sizeof (ace_walk_data_t)); 1352546Scarlsonj return (WALK_ERR); 1362546Scarlsonj } 1372546Scarlsonj 1382546Scarlsonj /* The step routine will start off by incrementing to index 0 */ 1392546Scarlsonj aw->awd_idx = -1; 1402546Scarlsonj wsp->walk_addr = 0; 1412546Scarlsonj wsp->walk_data = aw; 1422546Scarlsonj 1432546Scarlsonj return (WALK_NEXT); 1442546Scarlsonj } 1452546Scarlsonj 1462546Scarlsonj static int 1472546Scarlsonj ace_walk_step(mdb_walk_state_t *wsp) 1482546Scarlsonj { 1492546Scarlsonj uintptr_t addr; 1502546Scarlsonj ace_walk_data_t *aw = wsp->walk_data; 1512546Scarlsonj ace_t ace; 1522546Scarlsonj 1532546Scarlsonj /* 1542546Scarlsonj * If we're at the end of the previous list, then find the start of the 1552546Scarlsonj * next list to process. 1562546Scarlsonj */ 1572546Scarlsonj while (wsp->walk_addr == NULL) { 1582546Scarlsonj if (aw->awd_idx == ARP_HASH_SIZE) 1592546Scarlsonj return (WALK_DONE); 1602546Scarlsonj if (++aw->awd_idx == ARP_HASH_SIZE) { 1612546Scarlsonj wsp->walk_addr = (uintptr_t)aw->awd_masks; 1622546Scarlsonj } else { 1632546Scarlsonj wsp->walk_addr = 1642546Scarlsonj (uintptr_t)aw->awd_hash_tbl[aw->awd_idx]; 1652546Scarlsonj } 1662546Scarlsonj } 1672546Scarlsonj 1682546Scarlsonj addr = wsp->walk_addr; 1692546Scarlsonj if (mdb_vread(&ace, sizeof (ace), addr) == -1) { 1702546Scarlsonj mdb_warn("failed to read ace_t at %p", addr); 1712546Scarlsonj return (WALK_ERR); 1722546Scarlsonj } 1732546Scarlsonj 1742546Scarlsonj wsp->walk_addr = (uintptr_t)ace.ace_next; 1752546Scarlsonj 1762546Scarlsonj return (wsp->walk_callback(addr, &ace, wsp->walk_cbdata)); 1772546Scarlsonj } 1782546Scarlsonj 1792546Scarlsonj static void 1802546Scarlsonj ace_walk_fini(mdb_walk_state_t *wsp) 1812546Scarlsonj { 1822546Scarlsonj mdb_free(wsp->walk_data, sizeof (ace_walk_data_t)); 1832546Scarlsonj } 1842546Scarlsonj 1852546Scarlsonj /* Common routine to produce an 'ar' text description */ 1862546Scarlsonj static void 1872546Scarlsonj ar_describe(const ar_t *ar, char *buf, size_t nbytes, boolean_t addmac) 1882546Scarlsonj { 1892546Scarlsonj if (ar->ar_arl == NULL) { 1902546Scarlsonj queue_t wq, ipq; 1912546Scarlsonj ill_t ill; 1922546Scarlsonj char name[LIFNAMSIZ]; 1932546Scarlsonj GElf_Sym sym; 1942546Scarlsonj boolean_t nextip; 1952546Scarlsonj 1962546Scarlsonj if (mdb_vread(&wq, sizeof (wq), (uintptr_t)ar->ar_wq) == -1 || 1972546Scarlsonj mdb_vread(&ipq, sizeof (ipq), (uintptr_t)wq.q_next) == -1) 1982546Scarlsonj return; 1992546Scarlsonj 2002546Scarlsonj nextip = 2012546Scarlsonj (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0 && 2022546Scarlsonj (uintptr_t)sym.st_value == (uintptr_t)ipq.q_qinfo); 2032546Scarlsonj 2042546Scarlsonj if (!ar->ar_on_ill_stream) { 2052546Scarlsonj (void) strcpy(buf, nextip ? "Client" : "Unknown"); 2062546Scarlsonj return; 2072546Scarlsonj } 2082546Scarlsonj 2092546Scarlsonj if (!nextip || 2102546Scarlsonj mdb_vread(&ill, sizeof (ill), (uintptr_t)ipq.q_ptr) == -1 || 2112546Scarlsonj mdb_readstr(name, sizeof (name), 2122546Scarlsonj (uintptr_t)ill.ill_name) == -1) { 2132546Scarlsonj return; 2142546Scarlsonj } 2152546Scarlsonj (void) mdb_snprintf(buf, nbytes, "IP %s", name); 2162546Scarlsonj } else { 2172546Scarlsonj arl_t arl; 2182546Scarlsonj ssize_t retv; 2192546Scarlsonj uint32_t alen; 2202546Scarlsonj uchar_t macaddr[ARP_MAX_ADDR_LEN]; 2212546Scarlsonj 2222546Scarlsonj if (mdb_vread(&arl, sizeof (arl), (uintptr_t)ar->ar_arl) == -1) 2232546Scarlsonj return; 2242546Scarlsonj retv = mdb_snprintf(buf, nbytes, "ARP %s ", arl.arl_name); 2252546Scarlsonj if (retv >= nbytes || !addmac) 2262546Scarlsonj return; 2272546Scarlsonj alen = arl.arl_hw_addr_length; 2282546Scarlsonj if (arl.arl_hw_addr == NULL || alen == 0 || 2292546Scarlsonj alen > sizeof (macaddr)) 2302546Scarlsonj return; 2312546Scarlsonj if (mdb_vread(macaddr, alen, (uintptr_t)arl.arl_hw_addr) == -1) 2322546Scarlsonj return; 2332546Scarlsonj mdb_mac_addr(macaddr, alen, buf + retv, nbytes - retv); 2342546Scarlsonj } 2352546Scarlsonj } 2362546Scarlsonj 2372546Scarlsonj /* ARGSUSED2 */ 2382546Scarlsonj static int 2392546Scarlsonj ar_cb(uintptr_t addr, const void *arptr, void *dummy) 2402546Scarlsonj { 2412546Scarlsonj const ar_t *ar = arptr; 2422546Scarlsonj char ardesc[sizeof ("ARP ") + LIFNAMSIZ]; 2432546Scarlsonj 2442546Scarlsonj ar_describe(ar, ardesc, sizeof (ardesc), B_FALSE); 2452546Scarlsonj mdb_printf("%?p %?p %?p %s\n", addr, ar->ar_wq, ar->ar_arl, ardesc); 2462546Scarlsonj return (WALK_NEXT); 2472546Scarlsonj } 2482546Scarlsonj 2492546Scarlsonj /* 2502546Scarlsonj * Print out ARP client structures. 2512546Scarlsonj */ 2522546Scarlsonj /* ARGSUSED2 */ 2532546Scarlsonj static int 2542546Scarlsonj ar_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2552546Scarlsonj { 2562546Scarlsonj ar_t ar; 2572546Scarlsonj 2582546Scarlsonj if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 2592546Scarlsonj mdb_printf("%<u>%?s %?s %?s %s%</u>\n", 2602546Scarlsonj "AR", "WQ", "ARL", "TYPE"); 2612546Scarlsonj } 2622546Scarlsonj 2632546Scarlsonj if (flags & DCMD_ADDRSPEC) { 2642546Scarlsonj if (mdb_vread(&ar, sizeof (ar), addr) == -1) { 2652546Scarlsonj mdb_warn("failed to read ar_t at %p", addr); 2662546Scarlsonj return (DCMD_ERR); 2672546Scarlsonj } 2682546Scarlsonj (void) ar_cb(addr, &ar, NULL); 2692546Scarlsonj } else { 2702546Scarlsonj if (mdb_walk("ar", ar_cb, NULL) == -1) { 2712546Scarlsonj mdb_warn("cannot walk ar_t structures"); 2722546Scarlsonj return (DCMD_ERR); 2732546Scarlsonj } 2742546Scarlsonj } 2752546Scarlsonj return (DCMD_OK); 2762546Scarlsonj } 2772546Scarlsonj 2782546Scarlsonj /* ARGSUSED2 */ 2792546Scarlsonj static int 2802546Scarlsonj arl_cb(uintptr_t addr, const void *arlptr, void *dummy) 2812546Scarlsonj { 2822546Scarlsonj const arl_t *arl = arlptr; 2832546Scarlsonj uchar_t macaddr[ARP_MAX_ADDR_LEN]; 2842546Scarlsonj char macstr[ARP_MAX_ADDR_LEN*3]; 2852546Scarlsonj char flags[4]; 2862546Scarlsonj const char *primstr; 2872546Scarlsonj 2882546Scarlsonj mdb_printf("%?p ", addr); 2892546Scarlsonj if (arl->arl_dlpi_pending == DL_PRIM_INVAL) 2902546Scarlsonj mdb_printf("%16s", "--"); 2912546Scarlsonj else if ((primstr = mdb_dlpi_prim(arl->arl_dlpi_pending)) != NULL) 2922546Scarlsonj mdb_printf("%16s", primstr); 2932546Scarlsonj else 2942546Scarlsonj mdb_printf("%16x", arl->arl_dlpi_pending); 2952546Scarlsonj if (arl->arl_hw_addr_length == 0 || 2962546Scarlsonj arl->arl_hw_addr_length > sizeof (macaddr)) { 2972546Scarlsonj (void) strcpy(macstr, "--"); 2982546Scarlsonj } else if (mdb_vread(macaddr, arl->arl_hw_addr_length, 2992546Scarlsonj (uintptr_t)arl->arl_hw_addr) == -1) { 3002546Scarlsonj (void) strcpy(macstr, "?"); 3012546Scarlsonj } else { 3022546Scarlsonj mdb_mac_addr(macaddr, arl->arl_hw_addr_length, macstr, 3032546Scarlsonj sizeof (macstr)); 3042546Scarlsonj } 3052546Scarlsonj 3062546Scarlsonj /* Print both the link-layer state and the NOARP flag */ 3072546Scarlsonj flags[0] = '\0'; 3082546Scarlsonj if (arl->arl_flags & ARL_F_NOARP) 3092546Scarlsonj (void) strcat(flags, "N"); 3102546Scarlsonj switch (arl->arl_state) { 3112546Scarlsonj case ARL_S_DOWN: 3122546Scarlsonj (void) strcat(flags, "d"); 3132546Scarlsonj break; 3142546Scarlsonj case ARL_S_PENDING: 3152546Scarlsonj (void) strcat(flags, "P"); 3162546Scarlsonj break; 3172546Scarlsonj case ARL_S_UP: 3182546Scarlsonj (void) strcat(flags, "U"); 3192546Scarlsonj break; 3202546Scarlsonj default: 3212546Scarlsonj (void) strcat(flags, "?"); 3222546Scarlsonj break; 3232546Scarlsonj } 3242546Scarlsonj mdb_printf(" %8d %-3s %-9s %s\n", 3252546Scarlsonj mdb_mblk_count(arl->arl_dlpi_deferred), flags, arl->arl_name, 3262546Scarlsonj macstr); 3272546Scarlsonj return (WALK_NEXT); 3282546Scarlsonj } 3292546Scarlsonj 3302546Scarlsonj /* 3312546Scarlsonj * Print out ARP link-layer elements. 3322546Scarlsonj */ 3332546Scarlsonj /* ARGSUSED2 */ 3342546Scarlsonj static int 3352546Scarlsonj arl_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3362546Scarlsonj { 3372546Scarlsonj arl_t arl; 3382546Scarlsonj 3392546Scarlsonj if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 3402546Scarlsonj mdb_printf("%<u>%?s %16s %8s %3s %9s %s%</u>\n", 3412546Scarlsonj "ARL", "DLPI REQ", "DLPI CNT", "FLG", "INTERFACE", 3422546Scarlsonj "HW ADDR"); 3432546Scarlsonj } 3442546Scarlsonj 3452546Scarlsonj if (flags & DCMD_ADDRSPEC) { 3462546Scarlsonj if (mdb_vread(&arl, sizeof (arl), addr) == -1) { 3472546Scarlsonj mdb_warn("failed to read arl_t at %p", addr); 3482546Scarlsonj return (DCMD_ERR); 3492546Scarlsonj } 3502546Scarlsonj (void) arl_cb(addr, &arl, NULL); 3512546Scarlsonj } else { 3522546Scarlsonj if (mdb_walk("arl", arl_cb, NULL) == -1) { 3532546Scarlsonj mdb_warn("cannot walk arl_t structures"); 3542546Scarlsonj return (DCMD_ERR); 3552546Scarlsonj } 3562546Scarlsonj } 3572546Scarlsonj return (DCMD_OK); 3582546Scarlsonj } 3592546Scarlsonj 3602546Scarlsonj /* ARGSUSED2 */ 3612546Scarlsonj static int 3622546Scarlsonj ace_cb(uintptr_t addr, const void *aceptr, void *dummy) 3632546Scarlsonj { 3642546Scarlsonj const ace_t *ace = aceptr; 3652546Scarlsonj uchar_t macaddr[ARP_MAX_ADDR_LEN]; 3662546Scarlsonj char macstr[ARP_MAX_ADDR_LEN*3]; 3672546Scarlsonj /* The %b format isn't compact enough for long listings */ 3682546Scarlsonj static const char ace_flags[] = "SPDRMLdA ofya"; 3692546Scarlsonj const char *cp; 3702546Scarlsonj char flags[sizeof (ace_flags)], *fp; 3712546Scarlsonj int flg; 3722546Scarlsonj in_addr_t inaddr, mask; 3732546Scarlsonj char addrstr[sizeof ("255.255.255.255/32")]; 3742546Scarlsonj 3752546Scarlsonj /* Walk the list of flags and produce a string */ 3762546Scarlsonj cp = ace_flags; 3772546Scarlsonj fp = flags; 3782546Scarlsonj for (flg = 1; *cp != '\0'; flg <<= 1, cp++) { 3792546Scarlsonj if ((flg & ace->ace_flags) && *cp != ' ') 3802546Scarlsonj *fp++ = *cp; 3812546Scarlsonj } 3822546Scarlsonj *fp = '\0'; 3832546Scarlsonj 3842546Scarlsonj /* If it's not resolved, then it has no hardware address */ 3852546Scarlsonj if (!(ace->ace_flags & ACE_F_RESOLVED) || 3862546Scarlsonj ace->ace_hw_addr_length == 0 || 3872546Scarlsonj ace->ace_hw_addr_length > sizeof (macaddr)) { 3882546Scarlsonj (void) strcpy(macstr, "--"); 3892546Scarlsonj } else if (mdb_vread(macaddr, ace->ace_hw_addr_length, 3902546Scarlsonj (uintptr_t)ace->ace_hw_addr) == -1) { 3912546Scarlsonj (void) strcpy(macstr, "?"); 3922546Scarlsonj } else { 3932546Scarlsonj mdb_mac_addr(macaddr, ace->ace_hw_addr_length, macstr, 3942546Scarlsonj sizeof (macstr)); 3952546Scarlsonj } 3962546Scarlsonj 3972546Scarlsonj /* 3982546Scarlsonj * Nothing other than IP uses ARP these days, so we don't try very hard 3992546Scarlsonj * here to switch out on ARP protocol type. (Note that ARP protocol 4002546Scarlsonj * types are roughly Ethertypes, but are allocated separately at IANA.) 4012546Scarlsonj */ 4022546Scarlsonj if (ace->ace_proto != IP_ARP_PROTO_TYPE) { 4032546Scarlsonj (void) mdb_snprintf(addrstr, sizeof (addrstr), 4042546Scarlsonj "Unknown proto %x", ace->ace_proto); 4052546Scarlsonj } else if (mdb_vread(&inaddr, sizeof (inaddr), 4062546Scarlsonj (uintptr_t)ace->ace_proto_addr) != -1 && 4072546Scarlsonj mdb_vread(&mask, sizeof (mask), (uintptr_t)ace->ace_proto_mask) != 4082546Scarlsonj -1) { 4092546Scarlsonj /* 4102546Scarlsonj * If it's the standard host mask, then print it normally. 4112546Scarlsonj * Otherwise, use "/n" notation. 4122546Scarlsonj */ 4132546Scarlsonj if (mask == (in_addr_t)~0) { 4142546Scarlsonj (void) mdb_snprintf(addrstr, sizeof (addrstr), "%I", 4152546Scarlsonj inaddr); 4162546Scarlsonj } else { 4172546Scarlsonj (void) mdb_snprintf(addrstr, sizeof (addrstr), "%I/%d", 4182546Scarlsonj inaddr, mask == 0 ? 0 : 33 - mdb_ffs(mask)); 4192546Scarlsonj } 4202546Scarlsonj } else { 4212546Scarlsonj (void) strcpy(addrstr, "?"); 4222546Scarlsonj } 4232546Scarlsonj mdb_printf("%?p %-18s %-8s %s\n", addr, addrstr, flags, macstr); 4242546Scarlsonj return (WALK_NEXT); 4252546Scarlsonj } 4262546Scarlsonj 4272546Scarlsonj /* 4282546Scarlsonj * Print out ARP cache entry (ace_t) elements. 4292546Scarlsonj */ 4302546Scarlsonj /* ARGSUSED2 */ 4312546Scarlsonj static int 4322546Scarlsonj ace_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4332546Scarlsonj { 4342546Scarlsonj ace_t ace; 4352546Scarlsonj 4362546Scarlsonj if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 4372546Scarlsonj mdb_printf("%<u>%?s %-18s %-8s %s%</u>\n", 4382546Scarlsonj "ACE", "PROTOADDR", "FLAGS", "HWADDR"); 4392546Scarlsonj } 4402546Scarlsonj 4412546Scarlsonj if (flags & DCMD_ADDRSPEC) { 4422546Scarlsonj if (mdb_vread(&ace, sizeof (ace), addr) == -1) { 4432546Scarlsonj mdb_warn("failed to read ace_t at %p", addr); 4442546Scarlsonj return (DCMD_ERR); 4452546Scarlsonj } 4462546Scarlsonj (void) ace_cb(addr, &ace, NULL); 4472546Scarlsonj } else { 4482546Scarlsonj if (mdb_walk("ace", ace_cb, NULL) == -1) { 4492546Scarlsonj mdb_warn("cannot walk ace_t structures"); 4502546Scarlsonj return (DCMD_ERR); 4512546Scarlsonj } 4522546Scarlsonj } 4532546Scarlsonj return (DCMD_OK); 4542546Scarlsonj } 4552546Scarlsonj 4562546Scarlsonj /* 4572546Scarlsonj * Print an ARP hardware and protocol address pair; used when printing an ARP 4582546Scarlsonj * message. 4592546Scarlsonj */ 4602546Scarlsonj static void 4612546Scarlsonj print_arp(char field_id, const uchar_t *buf, const arh_t *arh, uint16_t ptype) 4622546Scarlsonj { 4632546Scarlsonj char macstr[ARP_MAX_ADDR_LEN*3]; 4642546Scarlsonj in_addr_t inaddr; 4652546Scarlsonj 4662546Scarlsonj if (arh->arh_hlen == 0) 4672546Scarlsonj (void) strcpy(macstr, "(none)"); 4682546Scarlsonj else 4692546Scarlsonj mdb_mac_addr(buf, arh->arh_hlen, macstr, sizeof (macstr)); 4702546Scarlsonj mdb_printf("%?s ar$%cha %s\n", "", field_id, macstr); 4712546Scarlsonj if (arh->arh_plen == 0) { 4722546Scarlsonj mdb_printf("%?s ar$%cpa (none)\n", "", field_id); 4732546Scarlsonj } else if (ptype == IP_ARP_PROTO_TYPE) { 4742546Scarlsonj mdb_printf("%?s ar$%cpa (unknown)\n", "", field_id); 4752546Scarlsonj } else if (arh->arh_plen == sizeof (in_addr_t)) { 4762546Scarlsonj (void) memcpy(&inaddr, buf + arh->arh_hlen, sizeof (inaddr)); 4772546Scarlsonj mdb_printf("%?s ar$%cpa %I\n", "", field_id, inaddr); 4782546Scarlsonj } else { 4792546Scarlsonj mdb_printf("%?s ar$%cpa (malformed IP)\n", "", field_id); 4802546Scarlsonj } 4812546Scarlsonj } 4822546Scarlsonj 4832546Scarlsonj /* 4842546Scarlsonj * Decode an ARP message and display it. 4852546Scarlsonj */ 4862546Scarlsonj /* ARGSUSED2 */ 4872546Scarlsonj static int 4882546Scarlsonj arphdr_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4892546Scarlsonj { 4902546Scarlsonj struct { 4912546Scarlsonj arh_t arh; 4922546Scarlsonj uchar_t addrs[4 * ARP_MAX_ADDR_LEN]; 4932546Scarlsonj } arp; 4942546Scarlsonj size_t blen; 4952546Scarlsonj uint16_t htype, ptype, op; 4962546Scarlsonj const char *cp; 4972546Scarlsonj 4982546Scarlsonj if (!(flags & DCMD_ADDRSPEC)) { 4992546Scarlsonj mdb_warn("address required to print ARP header\n"); 5002546Scarlsonj return (DCMD_ERR); 5012546Scarlsonj } 5022546Scarlsonj 5032546Scarlsonj if (mdb_vread(&arp.arh, sizeof (arp.arh), addr) == -1) { 5042546Scarlsonj mdb_warn("unable to read ARP header at %p", addr); 5052546Scarlsonj return (DCMD_ERR); 5062546Scarlsonj } 5072546Scarlsonj mdb_nhconvert(&htype, arp.arh.arh_hardware, sizeof (htype)); 5082546Scarlsonj mdb_nhconvert(&ptype, arp.arh.arh_proto, sizeof (ptype)); 5092546Scarlsonj mdb_nhconvert(&op, arp.arh.arh_operation, sizeof (op)); 5102546Scarlsonj 5112546Scarlsonj switch (htype) { 5122546Scarlsonj case ARPHRD_ETHER: 5132546Scarlsonj cp = "Ether"; 5142546Scarlsonj break; 5152546Scarlsonj case ARPHRD_IEEE802: 5162546Scarlsonj cp = "IEEE802"; 5172546Scarlsonj break; 5182546Scarlsonj case ARPHRD_IB: 5192546Scarlsonj cp = "InfiniBand"; 5202546Scarlsonj break; 5212546Scarlsonj default: 5222546Scarlsonj cp = "Unknown"; 5232546Scarlsonj break; 5242546Scarlsonj } 5252546Scarlsonj mdb_printf("%?p: ar$hrd %x (%s)\n", addr, htype, cp); 5262546Scarlsonj mdb_printf("%?s ar$pro %x (%s)\n", "", ptype, 5272546Scarlsonj ptype == IP_ARP_PROTO_TYPE ? "IP" : "Unknown"); 5282546Scarlsonj 5292546Scarlsonj switch (op) { 5302546Scarlsonj case ARPOP_REQUEST: 5312546Scarlsonj cp = "ares_op$REQUEST"; 5322546Scarlsonj break; 5332546Scarlsonj case ARPOP_REPLY: 5342546Scarlsonj cp = "ares_op$REPLY"; 5352546Scarlsonj break; 5362546Scarlsonj case REVARP_REQUEST: 5372546Scarlsonj cp = "arev_op$REQUEST"; 5382546Scarlsonj break; 5392546Scarlsonj case REVARP_REPLY: 5402546Scarlsonj cp = "arev_op$REPLY"; 5412546Scarlsonj break; 5422546Scarlsonj default: 5432546Scarlsonj cp = "Unknown"; 5442546Scarlsonj break; 5452546Scarlsonj } 5462546Scarlsonj mdb_printf("%?s ar$op %d (%s)\n", "", op, cp); 5472546Scarlsonj 5482546Scarlsonj /* 5492546Scarlsonj * Note that we go to some length to attempt to print out the fixed 5502546Scarlsonj * header data before trying to decode the variable-length data. This 5512546Scarlsonj * is done to maximize the amount of useful information shown when the 5522546Scarlsonj * buffer is truncated or otherwise corrupt. 5532546Scarlsonj */ 5542546Scarlsonj blen = 2 * (arp.arh.arh_hlen + arp.arh.arh_plen); 5552546Scarlsonj if (mdb_vread(&arp.addrs, blen, addr + sizeof (arp.arh)) == -1) { 5562546Scarlsonj mdb_warn("unable to read ARP body at %p", addr); 5572546Scarlsonj return (DCMD_ERR); 5582546Scarlsonj } 5592546Scarlsonj 5602546Scarlsonj print_arp('s', arp.addrs, &arp.arh, ptype); 5612546Scarlsonj print_arp('t', arp.addrs + arp.arh.arh_hlen + arp.arh.arh_plen, 5622546Scarlsonj &arp.arh, ptype); 5632546Scarlsonj return (DCMD_OK); 5642546Scarlsonj } 5652546Scarlsonj 5662546Scarlsonj /* 5672546Scarlsonj * Print out an arp command formatted in a reasonable manner. This implements 5682546Scarlsonj * the type switch used by ARP. 5692546Scarlsonj * 5702546Scarlsonj * It could also dump the data that follows the header (using offset and length 5712546Scarlsonj * in the various structures), but it currently does not. 5722546Scarlsonj */ 5732546Scarlsonj /* ARGSUSED2 */ 5742546Scarlsonj static int 5752546Scarlsonj arpcmd_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 5762546Scarlsonj { 5772546Scarlsonj arc_t arc; 5782546Scarlsonj const arp_cmd_tbl *tp; 5792546Scarlsonj mdb_arg_t subargv; 5802546Scarlsonj 5812546Scarlsonj if (!(flags & DCMD_ADDRSPEC)) { 5822546Scarlsonj mdb_warn("address required to print ARP command\n"); 5832546Scarlsonj return (DCMD_ERR); 5842546Scarlsonj } 5852546Scarlsonj if (mdb_vread(&arc, sizeof (arc), addr) == -1) { 5862546Scarlsonj mdb_warn("unable to read arc_t at %p", addr); 5872546Scarlsonj return (DCMD_ERR); 5882546Scarlsonj } 5892546Scarlsonj for (tp = act_list; tp->act_cmd != 0; tp++) 5902546Scarlsonj if (tp->act_cmd == arc.arc_cmd) 5912546Scarlsonj break; 5922546Scarlsonj mdb_printf("%p %s (%s) = ", addr, tp->act_name, tp->act_type); 5932546Scarlsonj subargv.a_type = MDB_TYPE_STRING; 5942546Scarlsonj subargv.a_un.a_str = tp->act_type; 5952546Scarlsonj if (mdb_call_dcmd("print", addr, DCMD_ADDRSPEC, 1, &subargv) == -1) 5962546Scarlsonj return (DCMD_ERR); 5972546Scarlsonj else 5982546Scarlsonj return (DCMD_OK); 5992546Scarlsonj } 6002546Scarlsonj 6012546Scarlsonj static size_t 6022546Scarlsonj mi_osize(const queue_t *q) 6032546Scarlsonj { 6042546Scarlsonj /* 6052546Scarlsonj * The code in common/inet/mi.c allocates an extra word to store the 6062546Scarlsonj * size of the allocation. An mi_o_s is thus a size_t plus an mi_o_s. 6072546Scarlsonj */ 6082546Scarlsonj struct mi_block { 6092546Scarlsonj size_t mi_nbytes; 6102546Scarlsonj struct mi_o_s mi_o; 6112546Scarlsonj } m; 6122546Scarlsonj 6132546Scarlsonj if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr - sizeof (m)) != -1) 6142546Scarlsonj return (m.mi_nbytes - sizeof (m)); 6152546Scarlsonj 6162546Scarlsonj return (0); 6172546Scarlsonj } 6182546Scarlsonj 6192546Scarlsonj /* 6202546Scarlsonj * This is called when ::stream is used and an ARP module is seen on the 6212546Scarlsonj * stream. Determine what sort of ARP usage is involved and show an 6222546Scarlsonj * appropriate message. 6232546Scarlsonj */ 6242546Scarlsonj static void 6252546Scarlsonj arp_qinfo(const queue_t *qp, char *buf, size_t nbytes) 6262546Scarlsonj { 6272546Scarlsonj size_t size = mi_osize(qp); 6282546Scarlsonj ar_t ar; 6292546Scarlsonj 6302546Scarlsonj if (size != sizeof (ar_t)) 6312546Scarlsonj return; 6322546Scarlsonj if (mdb_vread(&ar, sizeof (ar), (uintptr_t)qp->q_ptr) == -1) 6332546Scarlsonj return; 6342546Scarlsonj ar_describe(&ar, buf, nbytes, B_TRUE); 6352546Scarlsonj } 6362546Scarlsonj 6372546Scarlsonj static uintptr_t 6382546Scarlsonj arp_rnext(const queue_t *q) 6392546Scarlsonj { 6402546Scarlsonj size_t size = mi_osize(q); 6412546Scarlsonj ar_t ar; 6422546Scarlsonj 6432546Scarlsonj if (size == sizeof (ar_t) && mdb_vread(&ar, sizeof (ar), 6442546Scarlsonj (uintptr_t)q->q_ptr) != -1) 6452546Scarlsonj return ((uintptr_t)ar.ar_rq); 6462546Scarlsonj 6472546Scarlsonj return (NULL); 6482546Scarlsonj } 6492546Scarlsonj 6502546Scarlsonj static uintptr_t 6512546Scarlsonj arp_wnext(const queue_t *q) 6522546Scarlsonj { 6532546Scarlsonj size_t size = mi_osize(q); 6542546Scarlsonj ar_t ar; 6552546Scarlsonj 6562546Scarlsonj if (size == sizeof (ar_t) && mdb_vread(&ar, sizeof (ar), 6572546Scarlsonj (uintptr_t)q->q_ptr) != -1) 6582546Scarlsonj return ((uintptr_t)ar.ar_wq); 6592546Scarlsonj 6602546Scarlsonj return (NULL); 6612546Scarlsonj } 6622546Scarlsonj 6632546Scarlsonj static const mdb_dcmd_t dcmds[] = { 6642546Scarlsonj { "ar", "?", "display ARP client streams", ar_cmd, NULL }, 6652546Scarlsonj { "arl", "?", "display ARP link layers", arl_cmd, NULL }, 6662546Scarlsonj { "ace", "?", "display ARP cache entries", ace_cmd, NULL }, 6672546Scarlsonj { "arphdr", ":", "display an ARP header", arphdr_cmd, NULL }, 6682546Scarlsonj { "arpcmd", ":", "display an ARP command", arpcmd_cmd, NULL }, 6692546Scarlsonj { NULL } 6702546Scarlsonj }; 6712546Scarlsonj 6722546Scarlsonj /* Note: ar_t walker is in genunix.c and net.c; generic MI walker */ 6732546Scarlsonj static const mdb_walker_t walkers[] = { 6742546Scarlsonj { "arl", "walk list of arl_t links", 6752546Scarlsonj arl_walk_init, arl_walk_step, NULL }, 6762546Scarlsonj { "ace", "walk list of ace_t entries", 6772546Scarlsonj ace_walk_init, ace_walk_step, ace_walk_fini }, 6782546Scarlsonj { NULL } 6792546Scarlsonj }; 6802546Scarlsonj 6812546Scarlsonj static const mdb_qops_t arp_qops = { arp_qinfo, arp_rnext, arp_wnext }; 6822546Scarlsonj static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 6832546Scarlsonj 6842546Scarlsonj const mdb_modinfo_t * 6852546Scarlsonj _mdb_init(void) 6862546Scarlsonj { 6872546Scarlsonj GElf_Sym sym; 6882546Scarlsonj 6892546Scarlsonj if (mdb_lookup_by_obj("arp", "winit", &sym) == 0) 6902546Scarlsonj mdb_qops_install(&arp_qops, (uintptr_t)sym.st_value); 6912546Scarlsonj 6922546Scarlsonj return (&modinfo); 6932546Scarlsonj } 6942546Scarlsonj 6952546Scarlsonj void 6962546Scarlsonj _mdb_fini(void) 6972546Scarlsonj { 6982546Scarlsonj GElf_Sym sym; 6992546Scarlsonj 7002546Scarlsonj if (mdb_lookup_by_obj("arp", "winit", &sym) == 0) 7012546Scarlsonj mdb_qops_remove(&arp_qops, (uintptr_t)sym.st_value); 7022546Scarlsonj } 703