xref: /openbmc/ipmitool/src/plugins/dummy/dummy.c (revision 531569ec)
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_written > 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 	if (intf->fd < 0) {
153 		return;
154 	}
155 	memset(&req, 0, sizeof(req));
156 	req.msg.netfn = 0x3f;
157 	req.msg.cmd = 0xff;
158 	if (data_write(intf->fd, &req, sizeof(req)) != 0) {
159 		lprintf(LOG_ERR, "dummy failed to send 'BYE'");
160 	}
161 	close(intf->fd);
162 	intf->fd = (-1);
163 	intf->opened = 0;
164 }
165 
166 /* ipmi_dummyipmi_open - open socket and prepare ipmi_intf struct
167  *
168  * @intf - ptr to ipmi_inf struct
169  *
170  * returns 0 on success, (-1) on error
171  */
172 static int
173 ipmi_dummyipmi_open(struct ipmi_intf *intf)
174 {
175 	struct sockaddr_un address;
176 	int len;
177 	int rc;
178 
179 	if (intf->opened == 1) {
180 		return intf->fd;
181 	}
182 	intf->fd = socket(AF_UNIX, SOCK_STREAM, 0);
183 	if (intf->fd == (-1)) {
184 		lprintf(LOG_ERR, "dummy failed on socket()");
185 		return (-1);
186 	}
187 	address.sun_family = AF_UNIX;
188 	strcpy(address.sun_path, DUMMY_SOCKET_PATH);
189 	len = sizeof(address);
190 	rc = connect(intf->fd, (struct sockaddr *)&address, len);
191 	if (rc != 0) {
192 		perror("dummy failed on connect(): ");
193 		return (-1);
194 	}
195 	intf->opened = 1;
196 	return intf->fd;
197 }
198 
199 /* ipmi_dummyipmi_send_cmd - send IPMI payload and await reply
200  *
201  * @intf - ptr to initialized ipmi_intf struct
202  * @req - ptr to ipmi_rq struct to send
203  *
204  * return pointer to struct ipmi_rs OR NULL on error
205  */
206 static struct ipmi_rs*
207 ipmi_dummyipmi_send_cmd(struct ipmi_intf *intf, struct ipmi_rq *req)
208 {
209 	static struct ipmi_rs rsp;
210 	struct dummy_rq req_dummy;
211 	struct dummy_rs rsp_dummy;
212 	if (intf == NULL || intf->fd < 0 || intf->opened != 1) {
213 		lprintf(LOG_ERR, "dummy failed on intf check.");
214 		return NULL;
215 	}
216 
217 	memset(&req_dummy, 0, sizeof(req_dummy));
218 	req_dummy.msg.netfn = req->msg.netfn;
219 	req_dummy.msg.lun = req->msg.lun;
220 	req_dummy.msg.cmd = req->msg.cmd;
221 	req_dummy.msg.target_cmd = req->msg.target_cmd;
222 	req_dummy.msg.data_len = req->msg.data_len;
223 	req_dummy.msg.data = req->msg.data;
224 	if (verbose) {
225 		lprintf(LOG_NOTICE, ">>> IPMI req");
226 		lprintf(LOG_NOTICE, "msg.data_len: %i",
227 				req_dummy.msg.data_len);
228 		lprintf(LOG_NOTICE, "msg.netfn: %x", req_dummy.msg.netfn);
229 		lprintf(LOG_NOTICE, "msg.cmd: %x", req_dummy.msg.cmd);
230 		lprintf(LOG_NOTICE, "msg.target_cmd: %x",
231 				req_dummy.msg.target_cmd);
232 		lprintf(LOG_NOTICE, "msg.lun: %x", req_dummy.msg.lun);
233 		lprintf(LOG_NOTICE, ">>>");
234 	}
235 	if (data_write(intf->fd, &req_dummy,
236 				sizeof(struct dummy_rq)) != 0) {
237 		return NULL;
238 	}
239 	if (req->msg.data_len > 0) {
240 		if (data_write(intf->fd, (uint8_t *)(req->msg.data),
241 					req_dummy.msg.data_len) != 0) {
242 			return NULL;
243 		}
244 	}
245 
246 	memset(&rsp_dummy, 0, sizeof(rsp_dummy));
247 	if (data_read(intf->fd, &rsp_dummy, sizeof(struct dummy_rs)) != 0) {
248 		return NULL;
249 	}
250 	if (rsp_dummy.data_len > 0) {
251 		if (data_read(intf->fd, (uint8_t *)&rsp.data,
252 					rsp_dummy.data_len) != 0) {
253 			return NULL;
254 		}
255 	}
256 	rsp.ccode = rsp_dummy.ccode;
257 	rsp.data_len = rsp_dummy.data_len;
258 	rsp.msg.netfn = rsp_dummy.msg.netfn;
259 	rsp.msg.cmd = rsp_dummy.msg.cmd;
260 	rsp.msg.seq = rsp_dummy.msg.seq;
261 	rsp.msg.lun = rsp_dummy.msg.lun;
262 	if (verbose) {
263 		lprintf(LOG_NOTICE, "<<< IPMI rsp");
264 		lprintf(LOG_NOTICE, "ccode: %x", rsp.ccode);
265 		lprintf(LOG_NOTICE, "data_len: %i", rsp.data_len);
266 		lprintf(LOG_NOTICE, "msg.netfn: %x", rsp.msg.netfn);
267 		lprintf(LOG_NOTICE, "msg.cmd: %x", rsp.msg.cmd);
268 		lprintf(LOG_NOTICE, "msg.seq: %x", rsp.msg.seq);
269 		lprintf(LOG_NOTICE, "msg.lun: %x", rsp.msg.lun);
270 		lprintf(LOG_NOTICE, "<<<");
271 	}
272 	return &rsp;
273 }
274 
275 struct ipmi_intf ipmi_dummy_intf = {
276 	.name = "dummy",
277 	.desc = "Linux DummyIPMI Interface",
278 	.open = ipmi_dummyipmi_open,
279 	.close = ipmi_dummyipmi_close,
280 	.sendrecv = ipmi_dummyipmi_send_cmd,
281 	.my_addr = IPMI_BMC_SLAVE_ADDR,
282 	.target_addr = IPMI_BMC_SLAVE_ADDR,
283 };
284