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