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