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