xref: /openbmc/ipmitool/src/plugins/dummy/dummy.c (revision 13a2a291)
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
data_read(int fd,void * data_ptr,int data_len)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
data_write(int fd,void * data_ptr,int data_len)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
ipmi_dummyipmi_close(struct ipmi_intf * intf)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
ipmi_dummyipmi_open(struct ipmi_intf * intf)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*
ipmi_dummyipmi_send_cmd(struct ipmi_intf * intf,struct ipmi_rq * req)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