1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <sys/stropts.h>
29 #include <sys/stream.h>
30 #include <sys/dlpi.h>
31 #include <sys/hook.h>
32 #include <sys/hook_event.h>
33 #include <inet/led.h>
34 #include <inet/common.h>
35 #include <inet/mi.h>
36 #include <inet/arp.h>
37 #include <inet/ip.h>
38 #include <netinet/arp.h>
39
40 #include <mdb/mdb_modapi.h>
41 #include <mdb/mdb_ks.h>
42
43 typedef struct {
44 uint32_t act_cmd;
45 char *act_name;
46 char *act_type;
47 } arp_cmd_tbl;
48
49 /*
50 * removed all the ace/arl related stuff. The only thing that remains
51 * is code for dealing with ioctls and printing out arp header that
52 * should probably be moved into the ip/mdb module.
53 */
54
55 /*
56 * Print an ARP hardware and protocol address pair; used when printing an ARP
57 * message.
58 */
59 static void
print_arp(char field_id,const uchar_t * buf,const arh_t * arh,uint16_t ptype)60 print_arp(char field_id, const uchar_t *buf, const arh_t *arh, uint16_t ptype)
61 {
62 char macstr[ARP_MAX_ADDR_LEN*3];
63 in_addr_t inaddr;
64
65 if (arh->arh_hlen == 0)
66 (void) strcpy(macstr, "(none)");
67 else
68 mdb_mac_addr(buf, arh->arh_hlen, macstr, sizeof (macstr));
69 mdb_printf("%?s ar$%cha %s\n", "", field_id, macstr);
70 if (arh->arh_plen == 0) {
71 mdb_printf("%?s ar$%cpa (none)\n", "", field_id);
72 } else if (ptype == IP_ARP_PROTO_TYPE) {
73 mdb_printf("%?s ar$%cpa (unknown)\n", "", field_id);
74 } else if (arh->arh_plen == sizeof (in_addr_t)) {
75 (void) memcpy(&inaddr, buf + arh->arh_hlen, sizeof (inaddr));
76 mdb_printf("%?s ar$%cpa %I\n", "", field_id, inaddr);
77 } else {
78 mdb_printf("%?s ar$%cpa (malformed IP)\n", "", field_id);
79 }
80 }
81
82 /*
83 * Decode an ARP message and display it.
84 */
85 /* ARGSUSED2 */
86 static int
arphdr_cmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)87 arphdr_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
88 {
89 struct {
90 arh_t arh;
91 uchar_t addrs[4 * ARP_MAX_ADDR_LEN];
92 } arp;
93 size_t blen;
94 uint16_t htype, ptype, op;
95 const char *cp;
96
97 if (!(flags & DCMD_ADDRSPEC)) {
98 mdb_warn("address required to print ARP header\n");
99 return (DCMD_ERR);
100 }
101
102 if (mdb_vread(&arp.arh, sizeof (arp.arh), addr) == -1) {
103 mdb_warn("unable to read ARP header at %p", addr);
104 return (DCMD_ERR);
105 }
106 mdb_nhconvert(&htype, arp.arh.arh_hardware, sizeof (htype));
107 mdb_nhconvert(&ptype, arp.arh.arh_proto, sizeof (ptype));
108 mdb_nhconvert(&op, arp.arh.arh_operation, sizeof (op));
109
110 switch (htype) {
111 case ARPHRD_ETHER:
112 cp = "Ether";
113 break;
114 case ARPHRD_IEEE802:
115 cp = "IEEE802";
116 break;
117 case ARPHRD_IB:
118 cp = "InfiniBand";
119 break;
120 default:
121 cp = "Unknown";
122 break;
123 }
124 mdb_printf("%?p: ar$hrd %x (%s)\n", addr, htype, cp);
125 mdb_printf("%?s ar$pro %x (%s)\n", "", ptype,
126 ptype == IP_ARP_PROTO_TYPE ? "IP" : "Unknown");
127
128 switch (op) {
129 case ARPOP_REQUEST:
130 cp = "ares_op$REQUEST";
131 break;
132 case ARPOP_REPLY:
133 cp = "ares_op$REPLY";
134 break;
135 case REVARP_REQUEST:
136 cp = "arev_op$REQUEST";
137 break;
138 case REVARP_REPLY:
139 cp = "arev_op$REPLY";
140 break;
141 default:
142 cp = "Unknown";
143 break;
144 }
145 mdb_printf("%?s ar$op %d (%s)\n", "", op, cp);
146
147 /*
148 * Note that we go to some length to attempt to print out the fixed
149 * header data before trying to decode the variable-length data. This
150 * is done to maximize the amount of useful information shown when the
151 * buffer is truncated or otherwise corrupt.
152 */
153 blen = 2 * (arp.arh.arh_hlen + arp.arh.arh_plen);
154 if (mdb_vread(&arp.addrs, blen, addr + sizeof (arp.arh)) == -1) {
155 mdb_warn("unable to read ARP body at %p", addr);
156 return (DCMD_ERR);
157 }
158
159 print_arp('s', arp.addrs, &arp.arh, ptype);
160 print_arp('t', arp.addrs + arp.arh.arh_hlen + arp.arh.arh_plen,
161 &arp.arh, ptype);
162 return (DCMD_OK);
163 }
164
165 static const mdb_dcmd_t dcmds[] = {
166 { "arphdr", ":", "display an ARP header", arphdr_cmd, NULL },
167 { NULL }
168 };
169
170 /* Note: ar_t walker is in genunix.c and net.c; generic MI walker */
171 static const mdb_walker_t walkers[] = {
172 { NULL }
173 };
174
175 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
176
177 const mdb_modinfo_t *
_mdb_init(void)178 _mdb_init(void)
179 {
180 return (&modinfo);
181 }
182
183 void
_mdb_fini(void)184 _mdb_fini(void)
185 {
186 }
187