summaryrefslogtreecommitdiff
path: root/src/plugins/dummy/dummy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/dummy/dummy.c')
-rw-r--r--src/plugins/dummy/dummy.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/src/plugins/dummy/dummy.c b/src/plugins/dummy/dummy.c
new file mode 100644
index 0000000..eb2d086
--- /dev/null
+++ b/src/plugins/dummy/dummy.c
@@ -0,0 +1,286 @@
+/* Copyright (c) 2013 Zdenek Styblik, All Rights Reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Zdenek Styblik or the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * Zdenek Styblik SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * Zdenek Styblik BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF Zdenek Styblik HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/helper.h>
+#include <ipmitool/log.h>
+
+#include "dummy.h"
+
+#if defined(HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+extern int verbose;
+
+/* data_read - read data from socket
+ *
+ * @data_ptr - pointer to memory where to store read data
+ * @data_len - how much to read from socket
+ *
+ * return 0 on success, otherwise (-1)
+ */
+int
+data_read(int fd, void *data_ptr, int data_len)
+{
+ int rc = 0;
+ int data_read = 0;
+ int data_total = 0;
+ int try = 1;
+ int errno_save = 0;
+ if (data_len < 0) {
+ return (-1);
+ }
+ while (data_total < data_len && try < 4) {
+ errno = 0;
+ /* TODO - add poll() */
+ data_read = read(fd, data_ptr, data_len);
+ errno_save = errno;
+ if (data_read > 0) {
+ data_total+= data_read;
+ }
+ if (errno_save != 0) {
+ if (errno_save == EINTR || errno_save == EAGAIN) {
+ try++;
+ sleep(2);
+ continue;
+ } else {
+ errno = errno_save;
+ perror("dummy failed on read(): ");
+ rc = (-1);
+ break;
+ }
+ }
+ }
+ if (try > 3 && data_total != data_len) {
+ rc = (-1);
+ }
+ return rc;
+}
+
+/* data_write - write data to the socket
+ *
+ * @data_ptr - ptr to data to send
+ * @data_len - how long is the data to send
+ *
+ * returns 0 on success, otherwise (-1)
+ */
+int
+data_write(int fd, void *data_ptr, int data_len)
+{
+ int rc = 0;
+ int data_written = 0;
+ int data_total = 0;
+ int try = 1;
+ int errno_save = 0;
+ if (data_len < 0) {
+ return (-1);
+ }
+ while (data_total < data_len && try < 4) {
+ errno = 0;
+ /* TODO - add poll() */
+ data_written = write(fd, data_ptr, data_len);
+ errno_save = errno;
+ if (data_read > 0) {
+ data_total+= data_written;
+ }
+ if (errno_save != 0) {
+ if (errno_save == EINTR || errno_save == EAGAIN) {
+ try++;
+ sleep(2);
+ continue;
+ } else {
+ errno = errno_save;
+ perror("dummy failed on read(): ");
+ rc = (-1);
+ break;
+ }
+ }
+ }
+ if (try > 3 && data_total != data_len) {
+ rc = (-1);
+ }
+ return rc;
+}
+
+/* ipmi_dummyipmi_close - send "BYE" and close socket
+ *
+ * @intf - ptr to initialize ipmi_intf struct
+ *
+ * returns void
+ */
+static void
+ipmi_dummyipmi_close(struct ipmi_intf *intf)
+{
+ struct dummy_rq req;
+ int data_total = 0;
+ int data_written = 0;
+ int try = 0;
+ if (intf->fd < 0) {
+ return;
+ }
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = 0x3f;
+ req.msg.cmd = 0xff;
+ if (data_write(intf->fd, &req, sizeof(req)) != 0) {
+ lprintf(LOG_ERR, "dummy failed to send 'BYE'");
+ }
+ close(intf->fd);
+ intf->fd = (-1);
+ intf->opened = 0;
+}
+
+/* ipmi_dummyipmi_open - open socket and prepare ipmi_intf struct
+ *
+ * @intf - ptr to ipmi_inf struct
+ *
+ * returns 0 on success, (-1) on error
+ */
+static int
+ipmi_dummyipmi_open(struct ipmi_intf *intf)
+{
+ struct sockaddr_un address;
+ int len;
+ int rc;
+
+ if (intf->opened == 1) {
+ return intf->fd;
+ }
+ intf->fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (intf->fd == (-1)) {
+ lprintf(LOG_ERR, "dummy failed on socket()");
+ return (-1);
+ }
+ address.sun_family = AF_UNIX;
+ strcpy(address.sun_path, DUMMY_SOCKET_PATH);
+ len = sizeof(address);
+ rc = connect(intf->fd, (struct sockaddr *)&address, len);
+ if (rc != 0) {
+ perror("dummy failed on connect(): ");
+ return (-1);
+ }
+ intf->opened = 1;
+ return intf->fd;
+}
+
+/* ipmi_dummyipmi_send_cmd - send IPMI payload and await reply
+ *
+ * @intf - ptr to initialized ipmi_intf struct
+ * @req - ptr to ipmi_rq struct to send
+ *
+ * return pointer to struct ipmi_rs OR NULL on error
+ */
+static struct ipmi_rs*
+ipmi_dummyipmi_send_cmd(struct ipmi_intf *intf, struct ipmi_rq *req)
+{
+ static struct ipmi_rs rsp;
+ struct dummy_rq req_dummy;
+ struct dummy_rs rsp_dummy;
+ if (intf == NULL || intf->fd < 0 || intf->opened != 1) {
+ lprintf(LOG_ERR, "dummy failed on intf check.");
+ return NULL;
+ }
+
+ memset(&req_dummy, 0, sizeof(req_dummy));
+ req_dummy.msg.netfn = req->msg.netfn;
+ req_dummy.msg.lun = req->msg.lun;
+ req_dummy.msg.cmd = req->msg.cmd;
+ req_dummy.msg.target_cmd = req->msg.target_cmd;
+ req_dummy.msg.data_len = req->msg.data_len;
+ req_dummy.msg.data = req->msg.data;
+ if (verbose) {
+ lprintf(LOG_NOTICE, ">>> IPMI req");
+ lprintf(LOG_NOTICE, "msg.data_len: %i",
+ req_dummy.msg.data_len);
+ lprintf(LOG_NOTICE, "msg.netfn: %x", req_dummy.msg.netfn);
+ lprintf(LOG_NOTICE, "msg.cmd: %x", req_dummy.msg.cmd);
+ lprintf(LOG_NOTICE, "msg.target_cmd: %x",
+ req_dummy.msg.target_cmd);
+ lprintf(LOG_NOTICE, "msg.lun: %x", req_dummy.msg.lun);
+ lprintf(LOG_NOTICE, ">>>");
+ }
+ if (data_write(intf->fd, &req_dummy,
+ sizeof(struct dummy_rq)) != 0) {
+ return NULL;
+ }
+ if (req->msg.data_len > 0) {
+ if (data_write(intf->fd, (uint8_t *)(req->msg.data),
+ req_dummy.msg.data_len) != 0) {
+ return NULL;
+ }
+ }
+
+ memset(&rsp_dummy, 0, sizeof(rsp_dummy));
+ if (data_read(intf->fd, &rsp_dummy, sizeof(struct dummy_rs)) != 0) {
+ return NULL;
+ }
+ if (rsp_dummy.data_len > 0) {
+ if (data_read(intf->fd, (uint8_t *)&rsp.data,
+ rsp_dummy.data_len) != 0) {
+ return NULL;
+ }
+ }
+ rsp.ccode = rsp_dummy.ccode;
+ rsp.data_len = rsp_dummy.data_len;
+ rsp.msg.netfn = rsp_dummy.msg.netfn;
+ rsp.msg.cmd = rsp_dummy.msg.cmd;
+ rsp.msg.seq = rsp_dummy.msg.seq;
+ rsp.msg.lun = rsp_dummy.msg.lun;
+ if (verbose) {
+ lprintf(LOG_NOTICE, "<<< IPMI rsp");
+ lprintf(LOG_NOTICE, "ccode: %x", rsp.ccode);
+ lprintf(LOG_NOTICE, "data_len: %i", rsp.data_len);
+ lprintf(LOG_NOTICE, "msg.netfn: %x", rsp.msg.netfn);
+ lprintf(LOG_NOTICE, "msg.cmd: %x", rsp.msg.cmd);
+ lprintf(LOG_NOTICE, "msg.seq: %x", rsp.msg.seq);
+ lprintf(LOG_NOTICE, "msg.lun: %x", rsp.msg.lun);
+ lprintf(LOG_NOTICE, "<<<");
+ }
+ return &rsp;
+}
+
+struct ipmi_intf ipmi_dummy_intf = {
+ name: "dummy",
+ desc: "Linux DummyIPMI Interface",
+ open: ipmi_dummyipmi_open,
+ close: ipmi_dummyipmi_close,
+ sendrecv: ipmi_dummyipmi_send_cmd,
+ my_addr: IPMI_BMC_SLAVE_ADDR,
+ target_addr: IPMI_BMC_SLAVE_ADDR,
+};