xref: /openbmc/hiomapd/transport_dbus.c (revision f1e547c7)
1 // SPDX-License-Identifier: Apache-2.0
2 // Copyright (C) 2018 IBM Corp.
3 #include "config.h"
4 
5 #include <assert.h>
6 #include <errno.h>
7 #include <string.h>
8 #include <systemd/sd-bus.h>
9 
10 #include "common.h"
11 #include "dbus.h"
12 #include "mboxd.h"
13 #include "protocol.h"
14 #include "transport.h"
15 
16 static int transport_dbus_property_update(struct mbox_context *context,
17 					  uint8_t events)
18 {
19 	/* Two properties plus a terminating NULL */
20 	char *props[5] = { 0 };
21 	int i = 0;
22 	int rc;
23 
24 	if (events & BMC_EVENT_FLASH_CTRL_LOST) {
25 		props[i++] = "FlashControlLost";
26 	}
27 
28 	if (events & BMC_EVENT_DAEMON_READY) {
29 		props[i++] = "DaemonReady";
30 	}
31 
32 	if (events & BMC_EVENT_WINDOW_RESET) {
33 		props[i++] = "WindowReset";
34 	}
35 
36 	if (events & BMC_EVENT_PROTOCOL_RESET) {
37 		props[i++] = "ProtocolReset";
38 	}
39 
40 	rc = sd_bus_emit_properties_changed_strv(context->bus,
41 						 MBOX_DBUS_OBJECT,
42 						 /* FIXME: Hard-coding v2 */
43 						 MBOX_DBUS_PROTOCOL_IFACE_V2,
44 						 props);
45 
46 	return (rc < 0) ? rc : 0;
47 }
48 
49 
50 static int transport_dbus_put_events(struct mbox_context *context, uint8_t mask)
51 {
52 	return transport_dbus_property_update(context, mask);
53 }
54 
55 static int transport_dbus_set_events(struct mbox_context *context,
56 				     uint8_t events, uint8_t mask)
57 {
58 	return transport_dbus_property_update(context, events & mask);
59 }
60 
61 static int transport_dbus_clear_events(struct mbox_context *context,
62 				       uint8_t events, uint8_t mask)
63 {
64 	return transport_dbus_property_update(context, events & mask);
65 }
66 
67 static const struct transport_ops transport_dbus_ops = {
68 	.put_events = transport_dbus_put_events,
69 	.set_events = transport_dbus_set_events,
70 	.clear_events = transport_dbus_clear_events,
71 };
72 
73 static int transport_dbus_reset(sd_bus_message *m, void *userdata,
74 				     sd_bus_error *ret_error)
75 {
76 	struct mbox_context *context = userdata;
77 	sd_bus_message *n;
78 	int rc;
79 
80 	if (!context) {
81 		MSG_ERR("DBUS Internal Error\n");
82 		return -EINVAL;
83 	}
84 
85 	rc = context->protocol->reset(context);
86 	if (rc < 0) {
87 		return rc;
88 	}
89 
90 	rc = sd_bus_message_new_method_return(m, &n);
91 	if (rc < 0) {
92 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
93 		return rc;
94 	}
95 
96 	return sd_bus_send(NULL, n, NULL);
97 }
98 
99 static int transport_dbus_get_info(sd_bus_message *m, void *userdata,
100 					sd_bus_error *ret_error)
101 {
102 	struct mbox_context *context = userdata;
103 	struct protocol_get_info io;
104 	sd_bus_message *n;
105 	int rc;
106 
107 	if (!context) {
108 		MSG_ERR("DBUS Internal Error\n");
109 		return -EINVAL;
110 	}
111 
112 	rc = sd_bus_message_read_basic(m, 'y', &io.req.api_version);
113 	if (rc < 0) {
114 		MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
115 		return rc;
116 	}
117 
118 	rc = context->protocol->get_info(context, &io);
119 	if (rc < 0) {
120 		return rc;
121 	}
122 
123 	/* Switch transport to DBus. This is fine as DBus signals are async */
124 	context->transport = &transport_dbus_ops;
125 	/* A bit messy, but we need the correct event mask */
126 	protocol_events_set(context, context->bmc_events);
127 
128 	rc = sd_bus_message_new_method_return(m, &n);
129 	if (rc < 0) {
130 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
131 		return rc;
132 	}
133 
134 	if (API_VERSION_2 != io.resp.api_version) {
135 		MSG_ERR("Unsupported protocol version for DBus transport: %d\n",
136 			io.resp.api_version);
137 		return rc;
138 	}
139 
140 	rc = sd_bus_message_append(n, "yyq",
141 				   io.resp.api_version,
142 				   io.resp.v2.block_size_shift,
143 				   io.resp.v2.timeout);
144 	if (rc < 0) {
145 		MSG_ERR("sd_bus_message_append failed!\n");
146 		return rc;
147 	}
148 
149 	return sd_bus_send(NULL, n, NULL);
150 }
151 
152 static int transport_dbus_get_flash_info(sd_bus_message *m, void *userdata,
153 					 sd_bus_error *ret_error)
154 {
155 	struct mbox_context *context = userdata;
156 	struct protocol_get_flash_info io;
157 	sd_bus_message *n;
158 	int rc;
159 
160 	if (!context) {
161 		MSG_ERR("DBUS Internal Error\n");
162 		return -EINVAL;
163 	}
164 
165 	rc = context->protocol->get_flash_info(context, &io);
166 	if (rc < 0) {
167 		return rc;
168 	}
169 
170 	rc = sd_bus_message_new_method_return(m, &n);
171 	if (rc < 0) {
172 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
173 		return rc;
174 	}
175 
176 	rc = sd_bus_message_append(n, "qq",
177 				   io.resp.v2.flash_size,
178 				   io.resp.v2.erase_size);
179 	if (rc < 0) {
180 		MSG_ERR("sd_bus_message_append failed!\n");
181 		return rc;
182 	}
183 
184 	return sd_bus_send(NULL, n, NULL);
185 }
186 
187 static int transport_dbus_create_window(struct mbox_context *context,
188 					bool ro,
189 					sd_bus_message *m,
190 					sd_bus_error *ret_error)
191 {
192 	struct protocol_create_window io;
193 	sd_bus_message *n;
194 	int rc;
195 
196 	if (!context) {
197 		MSG_ERR("DBUS Internal Error\n");
198 		return -EINVAL;
199 	}
200 
201 	rc = sd_bus_message_read(m, "qq", &io.req.offset, &io.req.size);
202 	if (rc < 0) {
203 		MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
204 		return rc;
205 	}
206 
207 	io.req.ro = ro;
208 	rc = context->protocol->create_window(context, &io);
209 	if (rc < 0) {
210 		return rc;
211 	}
212 
213 	rc = sd_bus_message_new_method_return(m, &n);
214 	if (rc < 0) {
215 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
216 		return rc;
217 	}
218 
219 	rc = sd_bus_message_append(n, "qqq",
220 				   io.resp.lpc_address,
221 				   io.resp.size,
222 				   io.resp.offset);
223 	if (rc < 0) {
224 		MSG_ERR("sd_bus_message_append failed!\n");
225 		return rc;
226 	}
227 
228 	return sd_bus_send(NULL, n, NULL);
229 }
230 
231 static int transport_dbus_create_read_window(sd_bus_message *m, void *userdata,
232 					     sd_bus_error *ret_error)
233 {
234 	struct mbox_context *context = userdata;
235 
236 	return transport_dbus_create_window(context, true, m, ret_error);
237 }
238 
239 static int transport_dbus_create_write_window(sd_bus_message *m, void *userdata,
240 					      sd_bus_error *ret_error)
241 {
242 	struct mbox_context *context = userdata;
243 
244 	return transport_dbus_create_window(context, false, m, ret_error);
245 }
246 
247 static int transport_dbus_close_window(sd_bus_message *m, void *userdata,
248 				sd_bus_error *ret_error)
249 {
250 	struct mbox_context *context = userdata;
251 	struct protocol_close io;
252 	sd_bus_message *n;
253 	int rc;
254 
255 	if (!context) {
256 		MSG_ERR("DBUS Internal Error\n");
257 		return -EINVAL;
258 	}
259 
260 	rc = sd_bus_message_read(m, "y", &io.req.flags);
261 	if (rc < 0) {
262 		MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
263 		return rc;
264 	}
265 
266 	rc = context->protocol->close(context, &io);
267 	if (rc < 0) {
268 		return rc;
269 	}
270 
271 	rc = sd_bus_message_new_method_return(m, &n);
272 	if (rc < 0) {
273 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
274 		return rc;
275 	}
276 
277 	return sd_bus_send(NULL, n, NULL);
278 
279 }
280 
281 static int transport_dbus_mark_dirty(sd_bus_message *m, void *userdata,
282 				     sd_bus_error *ret_error)
283 {
284 	struct mbox_context *context = userdata;
285 	struct protocol_mark_dirty io;
286 	sd_bus_message *n;
287 	int rc;
288 
289 	if (!context) {
290 		MSG_ERR("DBUS Internal Error\n");
291 		return -EINVAL;
292 	}
293 
294 	rc = sd_bus_message_read(m, "qq", &io.req.v2.offset, &io.req.v2.size);
295 	if (rc < 0) {
296 		MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
297 		return rc;
298 	}
299 
300 	rc = context->protocol->mark_dirty(context, &io);
301 	if (rc < 0) {
302 		return rc;
303 	}
304 
305 	rc = sd_bus_message_new_method_return(m, &n);
306 	if (rc < 0) {
307 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
308 		return rc;
309 	}
310 
311 	return sd_bus_send(NULL, n, NULL);
312 }
313 
314 static int transport_dbus_write_flush(sd_bus_message *m, void *userdata,
315 				      sd_bus_error *ret_error)
316 {
317 	struct mbox_context *context = userdata;
318 	sd_bus_message *n;
319 	int rc;
320 
321 	if (!context) {
322 		MSG_ERR("DBUS Internal Error\n");
323 		return -EINVAL;
324 	}
325 
326 	rc = context->protocol->flush(context, NULL /* No args in v2 */);
327 	if (rc < 0) {
328 		return rc;
329 	}
330 
331 	rc = sd_bus_message_new_method_return(m, &n);
332 	if (rc < 0) {
333 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
334 		return rc;
335 	}
336 
337 	return sd_bus_send(NULL, n, NULL);
338 }
339 
340 static int transport_dbus_ack(sd_bus_message *m, void *userdata,
341 			      sd_bus_error *ret_error)
342 {
343 	struct mbox_context *context = userdata;
344 	struct protocol_ack io;
345 	sd_bus_message *n;
346 	int rc;
347 
348 	if (!context) {
349 		MSG_ERR("DBUS Internal Error\n");
350 		return -EINVAL;
351 	}
352 
353 	rc = sd_bus_message_read_basic(m, 'y', &io.req.flags);
354 	if (rc < 0) {
355 		MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
356 		return rc;
357 	}
358 
359 	rc = context->protocol->ack(context, &io);
360 	if (rc < 0) {
361 		return rc;
362 	}
363 
364 	rc = sd_bus_message_new_method_return(m, &n);
365 	if (rc < 0) {
366 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
367 		return rc;
368 	}
369 
370 	return sd_bus_send(NULL, n, NULL);
371 }
372 
373 static int transport_dbus_erase(sd_bus_message *m, void *userdata,
374 				sd_bus_error *ret_error)
375 {
376 	struct mbox_context *context = userdata;
377 	struct protocol_erase io;
378 	sd_bus_message *n;
379 	int rc;
380 
381 	if (!context) {
382 		MSG_ERR("DBUS Internal Error\n");
383 		return -EINVAL;
384 	}
385 
386 	rc = sd_bus_message_read(m, "qq", &io.req.offset, &io.req.size);
387 	if (rc < 0) {
388 		MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
389 		return rc;
390 	}
391 
392 	rc = context->protocol->erase(context, &io);
393 	if (rc < 0) {
394 		return rc;
395 	}
396 
397 	rc = sd_bus_message_new_method_return(m, &n);
398 	if (rc < 0) {
399 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
400 		return rc;
401 	}
402 
403 	return sd_bus_send(NULL, n, NULL);
404 }
405 
406 static int transport_dbus_get_property(sd_bus *bus,
407 				       const char *path,
408 				       const char *interface,
409 				       const char *property,
410 				       sd_bus_message *reply,
411 				       void *userdata,
412 				       sd_bus_error *ret_error)
413 {
414 	struct mbox_context *context = userdata;
415 	bool value;
416 
417 	assert(!strcmp(MBOX_DBUS_OBJECT, path));
418 	assert(!strcmp(MBOX_DBUS_PROTOCOL_IFACE_V2, interface));
419 
420 	if (!strcmp("FlashControlLost", property)) {
421 		value = context->bmc_events & BMC_EVENT_FLASH_CTRL_LOST;
422 	} else if (!strcmp("DaemonReady", property)) {
423 		value = context->bmc_events & BMC_EVENT_DAEMON_READY;
424 	} else if (!strcmp("WindowReset", property)) {
425 		value = context->bmc_events & BMC_EVENT_WINDOW_RESET;
426 	} else if (!strcmp("ProtocolReset", property)) {
427 		value = context->bmc_events & BMC_EVENT_PROTOCOL_RESET;
428 	} else {
429 		MSG_ERR("Unknown DBus property: %s\n", property);
430 		return -EINVAL;
431 	}
432 
433 	return sd_bus_message_append(reply, "b", value);
434 }
435 
436 static const sd_bus_vtable protocol_unversioned_vtable[] = {
437 	SD_BUS_VTABLE_START(0),
438 	SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset,
439 		      SD_BUS_VTABLE_UNPRIVILEGED),
440 	SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info,
441 		      SD_BUS_VTABLE_UNPRIVILEGED),
442 	SD_BUS_METHOD("Ack", "y", NULL, &transport_dbus_ack,
443 		      SD_BUS_VTABLE_UNPRIVILEGED),
444 	SD_BUS_VTABLE_END
445 };
446 
447 static const sd_bus_vtable protocol_v2_vtable[] = {
448 	SD_BUS_VTABLE_START(0),
449 	SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset,
450 		      SD_BUS_VTABLE_UNPRIVILEGED),
451 	SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info,
452 		      SD_BUS_VTABLE_UNPRIVILEGED),
453 	SD_BUS_METHOD("GetFlashInfo", NULL, "qq",
454 		      &transport_dbus_get_flash_info,
455 		      SD_BUS_VTABLE_UNPRIVILEGED),
456 	SD_BUS_METHOD("CreateReadWindow", "qq", "qqq",
457 		      &transport_dbus_create_read_window,
458 		      SD_BUS_VTABLE_UNPRIVILEGED),
459 	SD_BUS_METHOD("CreateWriteWindow", "qq", "qqq",
460 		      &transport_dbus_create_write_window,
461 		      SD_BUS_VTABLE_UNPRIVILEGED),
462 	SD_BUS_METHOD("CloseWindow", "y", NULL, &transport_dbus_close_window,
463 		      SD_BUS_VTABLE_UNPRIVILEGED),
464 	SD_BUS_METHOD("MarkDirty", "qq", NULL, &transport_dbus_mark_dirty,
465 		      SD_BUS_VTABLE_UNPRIVILEGED),
466 	SD_BUS_METHOD("Flush", NULL, NULL, &transport_dbus_write_flush,
467 		      SD_BUS_VTABLE_UNPRIVILEGED),
468 	SD_BUS_METHOD("Ack", "y", NULL, &transport_dbus_ack,
469 		      SD_BUS_VTABLE_UNPRIVILEGED),
470 	SD_BUS_METHOD("Erase", "qq", NULL, &transport_dbus_erase,
471 		      SD_BUS_VTABLE_UNPRIVILEGED),
472 	SD_BUS_PROPERTY("FlashControlLost", "b", transport_dbus_get_property,
473 			0, /* Just a pointer to struct mbox_context */
474 			SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
475 	SD_BUS_PROPERTY("DaemonReady", "b", transport_dbus_get_property,
476 			0, /* Just a pointer to struct mbox_context */
477 			SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
478 	SD_BUS_PROPERTY("ProtocolReset",  "b",
479 			transport_dbus_get_property,
480 			0, /* Just a pointer to struct mbox_context */
481 			SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
482 	SD_BUS_PROPERTY("WindowReset", "b",
483 			transport_dbus_get_property,
484 			0, /* Just a pointer to struct mbox_context */
485 			SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
486 	SD_BUS_VTABLE_END
487 };
488 
489 int transport_dbus_init(struct mbox_context *context,
490 			const struct transport_ops **ops)
491 {
492 	int rc;
493 
494 	rc = sd_bus_add_object_vtable(context->bus, NULL,
495 					MBOX_DBUS_OBJECT,
496 					MBOX_DBUS_PROTOCOL_IFACE,
497 					protocol_unversioned_vtable,
498 					context);
499 	if (rc < 0) {
500 		return rc;
501 	}
502 
503 	rc = sd_bus_add_object_vtable(context->bus, NULL,
504 					MBOX_DBUS_OBJECT,
505 					MBOX_DBUS_PROTOCOL_IFACE_V2,
506 					protocol_v2_vtable, context);
507 	if (rc < 0) {
508 		return rc;
509 	}
510 
511 	if (ops) {
512 		*ops = &transport_dbus_ops;
513 	}
514 
515 	return 0;
516 }
517 
518 #define __unused __attribute__((unused))
519 void transport_dbus_free(struct mbox_context *context __unused)
520 {
521 	return;
522 }
523