arp.c revision 69bb4bb45c98da60d21839c4dc3c01ea1be60585
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * CDDL HEADER START
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * The contents of this file are subject to the terms of the
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * Common Development and Distribution License (the "License").
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * You may not use this file except in compliance with the License.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * See the License for the specific language governing permissions
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * and limitations under the License.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * When distributing Covered Code, include this CDDL HEADER in each
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * If applicable, add the following below this CDDL HEADER, with the
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * fields enclosed by brackets "[]" replaced with your own identifying
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * information: Portions Copyright [yyyy] [name of copyright owner]
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * CDDL HEADER END
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * Use is subject to license terms.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj#pragma ident "%Z%%M% %I% %E% SMI"
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjtypedef struct {
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * Table of ARP commands and structure types used for messages between ARP and
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { AR_ENTRY_DELETE, "AR_ENTRY_DELETE", "arp`ared_t" },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { AR_ENTRY_QUERY, "AR_ENTRY_QUERY", "arp`areq_t" },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { AR_ENTRY_SQUERY, "AR_ENTRY_SQUERY", "arp`area_t" },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { AR_MAPPING_ADD, "AR_MAPPING_ADD", "arp`arma_t" },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { AR_CLIENT_NOTIFY, "AR_CLIENT_NOTIFY", "arp`arcn_t" },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { AR_INTERFACE_UP, "AR_INTERFACE_UP", "arp`arc_t" },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { AR_INTERFACE_DOWN, "AR_INTERFACE_DOWN", "arp`arc_t" },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { AR_INTERFACE_ON, "AR_INTERFACE_ON", "arp`arc_t" },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { AR_INTERFACE_OFF, "AR_INTERFACE_OFF", "arp`arc_t" },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * State information kept during walk over ACE hash table and unhashed mask
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjtypedef struct ace_walk_data {
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_readvar(&wsp->walk_addr, "arl_g_head") == -1) {
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj return ((*wsp->walk_callback)(addr, &arl, wsp->walk_cbdata));
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj aw = mdb_alloc(sizeof (ace_walk_data_t), UM_SLEEP);
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (mdb_readsym(aw->awd_hash_tbl, sizeof (aw->awd_hash_tbl),
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (mdb_readvar(&aw->awd_masks, "ar_ce_mask_entries") == -1) {
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj /* The step routine will start off by incrementing to index 0 */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * If we're at the end of the previous list, then find the start of the
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * next list to process.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj return (wsp->walk_callback(addr, &ace, wsp->walk_cbdata));
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_free(wsp->walk_data, sizeof (ace_walk_data_t));
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj/* Common routine to produce an 'ar' text description */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjar_describe(const ar_t *ar, char *buf, size_t nbytes, boolean_t addmac)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (mdb_vread(&wq, sizeof (wq), (uintptr_t)ar->ar_wq) == -1 ||
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_vread(&ipq, sizeof (ipq), (uintptr_t)wq.q_next) == -1)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj (uintptr_t)sym.st_value == (uintptr_t)ipq.q_qinfo);
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_vread(&ill, sizeof (ill), (uintptr_t)ipq.q_ptr) == -1 ||
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (mdb_vread(&arl, sizeof (arl), (uintptr_t)ar->ar_arl) == -1)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj retv = mdb_snprintf(buf, nbytes, "ARP %s ", arl.arl_name);
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (mdb_vread(macaddr, alen, (uintptr_t)arl.arl_hw_addr) == -1)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_mac_addr(macaddr, alen, buf + retv, nbytes - retv);
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj/* ARGSUSED2 */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjar_cb(uintptr_t addr, const void *arptr, void *dummy)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_printf("%?p %?p %?p %s\n", addr, ar->ar_wq, ar->ar_arl, ardesc);
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * Print out ARP client structures.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj/* ARGSUSED2 */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjar_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) {
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj/* ARGSUSED2 */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjarl_cb(uintptr_t addr, const void *arlptr, void *dummy)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj const char *primstr;
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj else if ((primstr = mdb_dlpi_prim(arl->arl_dlpi_pending)) != NULL)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj } else if (mdb_vread(macaddr, arl->arl_hw_addr_length,
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_mac_addr(macaddr, arl->arl_hw_addr_length, macstr,
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj /* Print both the link-layer state and the NOARP flag */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_mblk_count(arl->arl_dlpi_deferred), flags, arl->arl_name,
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * Print out ARP link-layer elements.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj/* ARGSUSED2 */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjarl_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) {
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj "HW ADDR");
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj/* ARGSUSED2 */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjace_cb(uintptr_t addr, const void *aceptr, void *dummy)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj /* The %b format isn't compact enough for long listings */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj const char *cp;
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj /* Walk the list of flags and produce a string */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj /* If it's not resolved, then it has no hardware address */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj } else if (mdb_vread(macaddr, ace->ace_hw_addr_length,
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_mac_addr(macaddr, ace->ace_hw_addr_length, macstr,
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * Nothing other than IP uses ARP these days, so we don't try very hard
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * here to switch out on ARP protocol type. (Note that ARP protocol
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * types are roughly Ethertypes, but are allocated separately at IANA.)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_vread(&mask, sizeof (mask), (uintptr_t)ace->ace_proto_mask) !=
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * If it's the standard host mask, then print it normally.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * Otherwise, use "/n" notation.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj (void) mdb_snprintf(addrstr, sizeof (addrstr), "%I",
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj (void) mdb_snprintf(addrstr, sizeof (addrstr), "%I/%d",
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_printf("%?p %-18s %-8s %s\n", addr, addrstr, flags, macstr);
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * Print out ARP cache entry (ace_t) elements.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj/* ARGSUSED2 */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjace_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) {
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * Print an ARP hardware and protocol address pair; used when printing an ARP
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjprint_arp(char field_id, const uchar_t *buf, const arh_t *arh, uint16_t ptype)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_mac_addr(buf, arh->arh_hlen, macstr, sizeof (macstr));
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_printf("%?s ar$%cha %s\n", "", field_id, macstr);
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_printf("%?s ar$%cpa (unknown)\n", "", field_id);
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj (void) memcpy(&inaddr, buf + arh->arh_hlen, sizeof (inaddr));
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_printf("%?s ar$%cpa %I\n", "", field_id, inaddr);
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_printf("%?s ar$%cpa (malformed IP)\n", "", field_id);
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * Decode an ARP message and display it.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj/* ARGSUSED2 */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjarphdr_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj const char *cp;
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_warn("address required to print ARP header\n");
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (mdb_vread(&arp.arh, sizeof (arp.arh), addr) == -1) {
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_nhconvert(&htype, arp.arh.arh_hardware, sizeof (htype));
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_nhconvert(&ptype, arp.arh.arh_proto, sizeof (ptype));
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_nhconvert(&op, arp.arh.arh_operation, sizeof (op));
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_printf("%?p: ar$hrd %x (%s)\n", addr, htype, cp);
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * Note that we go to some length to attempt to print out the fixed
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * header data before trying to decode the variable-length data. This
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * is done to maximize the amount of useful information shown when the
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * buffer is truncated or otherwise corrupt.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (mdb_vread(&arp.addrs, blen, addr + sizeof (arp.arh)) == -1) {
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj print_arp('t', arp.addrs + arp.arh.arh_hlen + arp.arh.arh_plen,
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * Print out an arp command formatted in a reasonable manner. This implements
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * the type switch used by ARP.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * It could also dump the data that follows the header (using offset and length
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * in the various structures), but it currently does not.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj/* ARGSUSED2 */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjarpcmd_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_warn("address required to print ARP command\n");
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_printf("%p %s (%s) = ", addr, tp->act_name, tp->act_type);
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (mdb_call_dcmd("print", addr, DCMD_ADDRSPEC, 1, &subargv) == -1)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * The code in common/inet/mi.c allocates an extra word to store the
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * size of the allocation. An mi_o_s is thus a size_t plus an mi_o_s.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr - sizeof (m)) != -1)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj return (m.mi_nbytes - sizeof (m));
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj return (0);
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * This is called when ::stream is used and an ARP module is seen on the
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * stream. Determine what sort of ARP usage is involved and show an
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj * appropriate message.
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjarp_qinfo(const queue_t *qp, char *buf, size_t nbytes)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (mdb_vread(&ar, sizeof (ar), (uintptr_t)qp->q_ptr) == -1)
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (size == sizeof (ar_t) && mdb_vread(&ar, sizeof (ar),
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj if (size == sizeof (ar_t) && mdb_vread(&ar, sizeof (ar),
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { "ar", "?", "display ARP client streams", ar_cmd, NULL },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { "arl", "?", "display ARP link layers", arl_cmd, NULL },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { "ace", "?", "display ARP cache entries", ace_cmd, NULL },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { "arphdr", ":", "display an ARP header", arphdr_cmd, NULL },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj { "arpcmd", ":", "display an ARP command", arpcmd_cmd, NULL },
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj/* Note: ar_t walker is in genunix.c and net.c; generic MI walker */
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjstatic const mdb_qops_t arp_qops = { arp_qinfo, arp_rnext, arp_wnext };
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonjstatic const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
69bb4bb45c98da60d21839c4dc3c01ea1be60585carlsonj mdb_qops_install(&arp_qops, (uintptr_t)sym.st_value);