1 /*
2 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * Redistribution of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * Redistribution in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * Neither the name of Sun Microsystems, Inc. or the names of
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * This software is provided "AS IS," without a warranty of any kind.
20 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
26 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31 *
32 * You acknowledge that this software is not designed or intended for use
33 * in the design, construction, operation or maintenance of any nuclear
34 * facility.
35 */
36
37 #if defined(HAVE_CONFIG_H)
38 # include <config.h>
39 #endif
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/types.h>
45
46 #include <ipmitool/ipmi.h>
47 #include <ipmitool/ipmi_intf.h>
48
49 #include <freeipmi/freeipmi.h>
50 #if IPMI_INTF_FREE_0_3_0 || IPMI_INTF_FREE_0_4_0 || IPMI_INTF_FREE_0_5_0
51 #include <freeipmi/udm/ipmi-udm.h>
52 #endif
53
54 #if IPMI_INTF_FREE_0_6_0
55 ipmi_ctx_t dev = NULL;
56 #else /* !IPMI_INTF_FREE_0_6_0 */
57 ipmi_device_t dev = NULL;
58 #endif /* !IPMI_INTF_FREE_0_6_0 */
59
60 extern int verbose;
61
ipmi_free_open(struct ipmi_intf * intf)62 static int ipmi_free_open(struct ipmi_intf * intf)
63 {
64 int kcs_ret = -1, ssif_ret = -1;
65
66 if (getuid() != 0) {
67 fprintf(stderr, "Permission denied, must be root\n");
68 return -1;
69 }
70
71 #if IPMI_INTF_FREE_0_3_0
72 if (!(dev = ipmi_open_inband (IPMI_DEVICE_KCS,
73 0,
74 0,
75 0,
76 NULL,
77 IPMI_FLAGS_DEFAULT))) {
78 if (!(dev = ipmi_open_inband (IPMI_DEVICE_SSIF,
79 0,
80 0,
81 0,
82 NULL,
83 IPMI_FLAGS_DEFAULT))) {
84 perror("ipmi_open_inband()");
85 goto cleanup;
86 }
87 }
88 #elif IPMI_INTF_FREE_0_4_0
89 if (!(dev = ipmi_device_create())) {
90 perror("ipmi_device_create");
91 goto cleanup;
92 }
93 if (ipmi_open_inband (dev,
94 IPMI_DEVICE_KCS,
95 0,
96 0,
97 0,
98 NULL,
99 IPMI_FLAGS_DEFAULT) < 0) {
100 if (ipmi_open_inband (dev,
101 IPMI_DEVICE_SSIF,
102 0,
103 0,
104 0,
105 NULL,
106 IPMI_FLAGS_DEFAULT) < 0) {
107 fprintf(stderr,
108 "ipmi_open_inband(): %s\n",
109 ipmi_device_strerror(ipmi_device_errnum(dev)));
110 goto cleanup;
111 }
112 }
113 #elif IPMI_INTF_FREE_0_5_0
114 if (!(dev = ipmi_device_create())) {
115 perror("ipmi_device_create");
116 goto cleanup;
117 }
118 if (ipmi_open_inband (dev,
119 IPMI_DEVICE_KCS,
120 0,
121 0,
122 0,
123 NULL,
124 0,
125 IPMI_FLAGS_DEFAULT) < 0) {
126 if (ipmi_open_inband (dev,
127 IPMI_DEVICE_SSIF,
128 0,
129 0,
130 0,
131 NULL,
132 0,
133 IPMI_FLAGS_DEFAULT) < 0) {
134 fprintf(stderr,
135 "ipmi_open_inband(): %s\n",
136 ipmi_device_strerror(ipmi_device_errnum(dev)));
137 goto cleanup;
138 }
139 }
140 #elif IPMI_INTF_FREE_0_6_0
141 if (!(dev = ipmi_ctx_create())) {
142 perror("ipmi_ctx_create");
143 goto cleanup;
144 }
145 if (ipmi_ctx_open_inband (dev,
146 IPMI_DEVICE_KCS,
147 0,
148 0,
149 0,
150 NULL,
151 0,
152 IPMI_FLAGS_DEFAULT) < 0) {
153 if (ipmi_ctx_open_inband (dev,
154 IPMI_DEVICE_SSIF,
155 0,
156 0,
157 0,
158 NULL,
159 0,
160 IPMI_FLAGS_DEFAULT) < 0) {
161 fprintf(stderr,
162 "ipmi_open_inband(): %s\n",
163 ipmi_ctx_strerror(ipmi_ctx_errnum(dev)));
164 goto cleanup;
165 }
166 }
167 #endif
168
169 intf->opened = 1;
170 intf->manufacturer_id = ipmi_get_oem(intf);
171 return 0;
172 cleanup:
173 if (dev) {
174 #if IPMI_INTF_FREE_0_3_0
175 ipmi_close_device(dev);
176 #elif IPMI_INTF_FREE_0_4_0 || IPMI_INTF_FREE_0_5_0
177 ipmi_close_device(dev);
178 ipmi_device_destroy(dev);
179 #elif IPMI_INTF_FREE_0_6_0
180 ipmi_ctx_close(dev);
181 ipmi_ctx_destroy(dev);
182 #endif
183 }
184 return -1;
185 }
186
ipmi_free_close(struct ipmi_intf * intf)187 static void ipmi_free_close(struct ipmi_intf * intf)
188 {
189 if (dev) {
190 #if IPMI_INTF_FREE_0_3_0
191 ipmi_close_device(dev);
192 #elif IPMI_INTF_FREE_0_4_0 || IPMI_INTF_FREE_0_5_0
193 ipmi_close_device(dev);
194 ipmi_device_destroy(dev);
195 #elif IPMI_INTF_FREE_0_6_0
196 ipmi_ctx_close(dev);
197 ipmi_ctx_destroy(dev);
198 #endif
199 }
200 intf->opened = 0;
201 intf->manufacturer_id = IPMI_OEM_UNKNOWN;
202 }
203
ipmi_free_send_cmd(struct ipmi_intf * intf,struct ipmi_rq * req)204 static struct ipmi_rs * ipmi_free_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req)
205 {
206 uint8_t lun = req->msg.lun;
207 uint8_t cmd = req->msg.cmd;
208 uint8_t netfn = req->msg.netfn;
209 uint8_t rq_buf[IPMI_BUF_SIZE];
210 uint8_t rs_buf[IPMI_BUF_SIZE];
211 uint32_t rs_buf_len = IPMI_BUF_SIZE;
212 int32_t rs_len;
213
214 static struct ipmi_rs rsp;
215
216 /* achu: FreeIPMI requests have the cmd as the first byte of
217 * the data. Responses have cmd as the first byte and
218 * completion code as the second byte. This differs from some
219 * other APIs, so it must be compensated for within the ipmitool
220 * interface.
221 */
222
223 if (!intf || !req)
224 return NULL;
225
226 if (!intf->opened && intf->open && intf->open(intf) < 0)
227 return NULL;
228
229 if (req->msg.data_len > IPMI_BUF_SIZE)
230 return NULL;
231
232 memset(rq_buf, '\0', IPMI_BUF_SIZE);
233 memset(rs_buf, '\0', IPMI_BUF_SIZE);
234 memcpy(rq_buf, &cmd, 1);
235
236 if (req->msg.data)
237 memcpy(rq_buf + 1, req->msg.data, req->msg.data_len);
238
239 if (intf->target_addr != 0
240 && intf->target_addr != IPMI_BMC_SLAVE_ADDR) {
241 #if IPMI_INTF_FREE_BRIDGING
242 if ((rs_len = ipmi_cmd_raw_ipmb(dev,
243 intf->target_channel,
244 intf->target_addr,
245 lun,
246 netfn,
247 rq_buf,
248 req->msg.data_len + 1,
249 rs_buf,
250 rs_buf_len)) < 0) {
251 if (verbose > 3)
252 fprintf(stderr,
253 "ipmi_cmd_raw_ipmb: %s\n",
254 ipmi_ctx_strerror(ipmi_ctx_errnum(dev)));
255 /* Compared to FreeIPMI, user is expected to input
256 * the target channel on the command line, it is not automatically
257 * discovered. So that is the likely cause of an error.
258 *
259 * Instead of returning an error, return a bad response so output
260 * of ipmitool commands looks like other interfaces
261 */
262 rs_len = 2;
263 rs_buf[0] = 0;
264 rs_buf[1] = 0xC1; /* invalid command */
265 }
266 #else /* !IPMI_INTF_FREE_BRIDGING */
267 if (verbose > 3)
268 fprintf(stderr, "sensor bridging not supported in this driver version");
269 /* instead of returning an error, return a bad response so output
270 * of ipmitool commands looks like other interfaces
271 */
272 rs_len = 2;
273 rs_buf[0] = 0;
274 rs_buf[1] = 0xC1; /* invalid command */
275 #endif /* !IPMI_INTF_FREE_BRIDGING */
276 }
277 else {
278 if ((rs_len = ipmi_cmd_raw(dev,
279 lun,
280 netfn,
281 rq_buf,
282 req->msg.data_len + 1,
283 rs_buf,
284 rs_buf_len)) < 0) {
285 #if IPMI_INTF_FREE_0_3_0
286 perror("ipmi_cmd_raw");
287 #elif IPMI_INTF_FREE_0_4_0 || IPMI_INTF_FREE_0_5_0
288 fprintf(stderr,
289 "ipmi_cmd_raw: %s\n",
290 ipmi_device_strerror(ipmi_device_errnum(dev)));
291 #elif IPMI_INTF_FREE_0_6_0
292 fprintf(stderr,
293 "ipmi_cmd_raw: %s\n",
294 ipmi_ctx_strerror(ipmi_ctx_errnum(dev)));
295 #endif
296 return NULL;
297 }
298 }
299
300 memset(&rsp, 0, sizeof(struct ipmi_rs));
301 rsp.ccode = (unsigned char)rs_buf[1];
302 rsp.data_len = (int)rs_len - 2;
303
304 if (!rsp.ccode && rsp.data_len)
305 memcpy(rsp.data, rs_buf + 2, rsp.data_len);
306
307 return &rsp;
308 }
309
310 struct ipmi_intf ipmi_free_intf = {
311 name: "free",
312 desc: "FreeIPMI IPMI Interface",
313 open: ipmi_free_open,
314 close: ipmi_free_close,
315 sendrecv: ipmi_free_send_cmd,
316 target_addr: IPMI_BMC_SLAVE_ADDR,
317 };
318
319