1 /* Copyright (c) 2013 Zdenek Styblik, All Rights Reserved 2 * 3 * Redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions 5 * are met: 6 * 7 * Redistribution of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 10 * Redistribution in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * Neither the name of Zdenek Styblik or the names of 15 * contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * This software is provided "AS IS," without a warranty of any kind. 19 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 20 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 21 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. 22 * Zdenek Styblik SHALL NOT BE LIABLE 23 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING 24 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL 25 * Zdenek Styblik BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, 26 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR 27 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 28 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 29 * EVEN IF Zdenek Styblik HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 30 */ 31 #include <errno.h> 32 #include <limits.h> 33 #include <stdio.h> 34 #include <sys/socket.h> 35 #include <sys/types.h> 36 #include <sys/un.h> 37 #include <unistd.h> 38 39 #include <ipmitool/ipmi.h> 40 #include <ipmitool/ipmi_intf.h> 41 #include <ipmitool/helper.h> 42 #include <ipmitool/log.h> 43 44 #include "dummy.h" 45 46 #if defined(HAVE_CONFIG_H) 47 # include <config.h> 48 #endif 49 50 extern int verbose; 51 52 /* data_read - read data from socket 53 * 54 * @data_ptr - pointer to memory where to store read data 55 * @data_len - how much to read from socket 56 * 57 * return 0 on success, otherwise (-1) 58 */ 59 int 60 data_read(int fd, void *data_ptr, int data_len) 61 { 62 int rc = 0; 63 int data_read = 0; 64 int data_total = 0; 65 int try = 1; 66 int errno_save = 0; 67 if (data_len < 0) { 68 return (-1); 69 } 70 while (data_total < data_len && try < 4) { 71 errno = 0; 72 /* TODO - add poll() */ 73 data_read = read(fd, data_ptr, data_len); 74 errno_save = errno; 75 if (data_read > 0) { 76 data_total+= data_read; 77 } 78 if (errno_save != 0) { 79 if (errno_save == EINTR || errno_save == EAGAIN) { 80 try++; 81 sleep(2); 82 continue; 83 } else { 84 errno = errno_save; 85 perror("dummy failed on read(): "); 86 rc = (-1); 87 break; 88 } 89 } 90 } 91 if (try > 3 && data_total != data_len) { 92 rc = (-1); 93 } 94 return rc; 95 } 96 97 /* data_write - write data to the socket 98 * 99 * @data_ptr - ptr to data to send 100 * @data_len - how long is the data to send 101 * 102 * returns 0 on success, otherwise (-1) 103 */ 104 int 105 data_write(int fd, void *data_ptr, int data_len) 106 { 107 int rc = 0; 108 int data_written = 0; 109 int data_total = 0; 110 int try = 1; 111 int errno_save = 0; 112 if (data_len < 0) { 113 return (-1); 114 } 115 while (data_total < data_len && try < 4) { 116 errno = 0; 117 /* TODO - add poll() */ 118 data_written = write(fd, data_ptr, data_len); 119 errno_save = errno; 120 if (data_read > 0) { 121 data_total+= data_written; 122 } 123 if (errno_save != 0) { 124 if (errno_save == EINTR || errno_save == EAGAIN) { 125 try++; 126 sleep(2); 127 continue; 128 } else { 129 errno = errno_save; 130 perror("dummy failed on read(): "); 131 rc = (-1); 132 break; 133 } 134 } 135 } 136 if (try > 3 && data_total != data_len) { 137 rc = (-1); 138 } 139 return rc; 140 } 141 142 /* ipmi_dummyipmi_close - send "BYE" and close socket 143 * 144 * @intf - ptr to initialize ipmi_intf struct 145 * 146 * returns void 147 */ 148 static void 149 ipmi_dummyipmi_close(struct ipmi_intf *intf) 150 { 151 struct dummy_rq req; 152 int data_total = 0; 153 int data_written = 0; 154 int try = 0; 155 if (intf->fd < 0) { 156 return; 157 } 158 memset(&req, 0, sizeof(req)); 159 req.msg.netfn = 0x3f; 160 req.msg.cmd = 0xff; 161 if (data_write(intf->fd, &req, sizeof(req)) != 0) { 162 lprintf(LOG_ERR, "dummy failed to send 'BYE'"); 163 } 164 close(intf->fd); 165 intf->fd = (-1); 166 intf->opened = 0; 167 } 168 169 /* ipmi_dummyipmi_open - open socket and prepare ipmi_intf struct 170 * 171 * @intf - ptr to ipmi_inf struct 172 * 173 * returns 0 on success, (-1) on error 174 */ 175 static int 176 ipmi_dummyipmi_open(struct ipmi_intf *intf) 177 { 178 struct sockaddr_un address; 179 int len; 180 int rc; 181 182 if (intf->opened == 1) { 183 return intf->fd; 184 } 185 intf->fd = socket(AF_UNIX, SOCK_STREAM, 0); 186 if (intf->fd == (-1)) { 187 lprintf(LOG_ERR, "dummy failed on socket()"); 188 return (-1); 189 } 190 address.sun_family = AF_UNIX; 191 strcpy(address.sun_path, DUMMY_SOCKET_PATH); 192 len = sizeof(address); 193 rc = connect(intf->fd, (struct sockaddr *)&address, len); 194 if (rc != 0) { 195 perror("dummy failed on connect(): "); 196 return (-1); 197 } 198 intf->opened = 1; 199 return intf->fd; 200 } 201 202 /* ipmi_dummyipmi_send_cmd - send IPMI payload and await reply 203 * 204 * @intf - ptr to initialized ipmi_intf struct 205 * @req - ptr to ipmi_rq struct to send 206 * 207 * return pointer to struct ipmi_rs OR NULL on error 208 */ 209 static struct ipmi_rs* 210 ipmi_dummyipmi_send_cmd(struct ipmi_intf *intf, struct ipmi_rq *req) 211 { 212 static struct ipmi_rs rsp; 213 struct dummy_rq req_dummy; 214 struct dummy_rs rsp_dummy; 215 if (intf == NULL || intf->fd < 0 || intf->opened != 1) { 216 lprintf(LOG_ERR, "dummy failed on intf check."); 217 return NULL; 218 } 219 220 memset(&req_dummy, 0, sizeof(req_dummy)); 221 req_dummy.msg.netfn = req->msg.netfn; 222 req_dummy.msg.lun = req->msg.lun; 223 req_dummy.msg.cmd = req->msg.cmd; 224 req_dummy.msg.target_cmd = req->msg.target_cmd; 225 req_dummy.msg.data_len = req->msg.data_len; 226 req_dummy.msg.data = req->msg.data; 227 if (verbose) { 228 lprintf(LOG_NOTICE, ">>> IPMI req"); 229 lprintf(LOG_NOTICE, "msg.data_len: %i", 230 req_dummy.msg.data_len); 231 lprintf(LOG_NOTICE, "msg.netfn: %x", req_dummy.msg.netfn); 232 lprintf(LOG_NOTICE, "msg.cmd: %x", req_dummy.msg.cmd); 233 lprintf(LOG_NOTICE, "msg.target_cmd: %x", 234 req_dummy.msg.target_cmd); 235 lprintf(LOG_NOTICE, "msg.lun: %x", req_dummy.msg.lun); 236 lprintf(LOG_NOTICE, ">>>"); 237 } 238 if (data_write(intf->fd, &req_dummy, 239 sizeof(struct dummy_rq)) != 0) { 240 return NULL; 241 } 242 if (req->msg.data_len > 0) { 243 if (data_write(intf->fd, (uint8_t *)(req->msg.data), 244 req_dummy.msg.data_len) != 0) { 245 return NULL; 246 } 247 } 248 249 memset(&rsp_dummy, 0, sizeof(rsp_dummy)); 250 if (data_read(intf->fd, &rsp_dummy, sizeof(struct dummy_rs)) != 0) { 251 return NULL; 252 } 253 if (rsp_dummy.data_len > 0) { 254 if (data_read(intf->fd, (uint8_t *)&rsp.data, 255 rsp_dummy.data_len) != 0) { 256 return NULL; 257 } 258 } 259 rsp.ccode = rsp_dummy.ccode; 260 rsp.data_len = rsp_dummy.data_len; 261 rsp.msg.netfn = rsp_dummy.msg.netfn; 262 rsp.msg.cmd = rsp_dummy.msg.cmd; 263 rsp.msg.seq = rsp_dummy.msg.seq; 264 rsp.msg.lun = rsp_dummy.msg.lun; 265 if (verbose) { 266 lprintf(LOG_NOTICE, "<<< IPMI rsp"); 267 lprintf(LOG_NOTICE, "ccode: %x", rsp.ccode); 268 lprintf(LOG_NOTICE, "data_len: %i", rsp.data_len); 269 lprintf(LOG_NOTICE, "msg.netfn: %x", rsp.msg.netfn); 270 lprintf(LOG_NOTICE, "msg.cmd: %x", rsp.msg.cmd); 271 lprintf(LOG_NOTICE, "msg.seq: %x", rsp.msg.seq); 272 lprintf(LOG_NOTICE, "msg.lun: %x", rsp.msg.lun); 273 lprintf(LOG_NOTICE, "<<<"); 274 } 275 return &rsp; 276 } 277 278 struct ipmi_intf ipmi_dummy_intf = { 279 .name = "dummy", 280 .desc = "Linux DummyIPMI Interface", 281 .open = ipmi_dummyipmi_open, 282 .close = ipmi_dummyipmi_close, 283 .sendrecv = ipmi_dummyipmi_send_cmd, 284 .my_addr = IPMI_BMC_SLAVE_ADDR, 285 .target_addr = IPMI_BMC_SLAVE_ADDR, 286 }; 287