xref: /openbmc/ipmitool/src/plugins/free/free.c (revision 89e9e634)
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 
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 
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 
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