Blame src/plugins/dummy/dummy.c

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