xref: /openbmc/hiomapd/transport_dbus.c (revision 899857542e729e57049d1dd88406127626b3902d)
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 static int transport_dbus_signal_update(struct mbox_context *context,
50 					uint8_t events)
51 {
52 	int rc;
53 
54 	/*
55 	 * Handle signals - edge triggered, only necessary when they're
56 	 * asserted
57 	 */
58 	if (events & BMC_EVENT_WINDOW_RESET) {
59 		sd_bus_message *m = NULL;
60 
61 		rc = sd_bus_message_new_signal(context->bus, &m,
62 					       MBOX_DBUS_OBJECT,
63 					       /* FIXME: Hard-coding v2 */
64 					       MBOX_DBUS_PROTOCOL_IFACE_V2,
65 					       "WindowReset");
66 		if (rc < 0) {
67 			return rc;
68 		}
69 
70 		rc = sd_bus_send(context->bus, m, NULL);
71 		if (rc < 0) {
72 			return rc;
73 		}
74 	}
75 
76 	if (events & BMC_EVENT_PROTOCOL_RESET) {
77 		sd_bus_message *m = NULL;
78 
79 		rc = sd_bus_message_new_signal(context->bus, &m,
80 					       MBOX_DBUS_OBJECT,
81 					       /* FIXME: Hard-coding v2 */
82 					       MBOX_DBUS_PROTOCOL_IFACE_V2,
83 					       "ProtocolReset");
84 		if (rc < 0) {
85 			return rc;
86 		}
87 
88 		rc = sd_bus_send(context->bus, m, NULL);
89 		if (rc < 0) {
90 			return rc;
91 		}
92 	}
93 
94 	return 0;
95 }
96 
97 static int transport_dbus_put_events(struct mbox_context *context, uint8_t mask)
98 {
99 	int rc;
100 
101 	/* Always update all properties */
102 	rc = transport_dbus_property_update(context, mask);
103 	if (rc < 0) {
104 		return rc;
105 	}
106 
107 	/*
108 	 * Still test signals against the values set as sending them indicates
109 	 * the event has been asserted, so we must not send them if the bits
110 	 * are not set.
111 	 */
112 	return transport_dbus_signal_update(context,
113 					    context->bmc_events & mask);
114 }
115 
116 static int transport_dbus_set_events(struct mbox_context *context,
117 				     uint8_t events, uint8_t mask)
118 {
119 	int rc;
120 
121 	rc = transport_dbus_property_update(context, events & mask);
122 	if (rc < 0) {
123 		return rc;
124 	}
125 
126 	return transport_dbus_signal_update(context, events & mask);
127 }
128 
129 static int transport_dbus_clear_events(struct mbox_context *context,
130 				       uint8_t events, uint8_t mask)
131 {
132 	/* No need to emit signals for ackable events on clear */
133 	return transport_dbus_property_update(context, events & mask);
134 }
135 
136 static const struct transport_ops transport_dbus_ops = {
137 	.put_events = transport_dbus_put_events,
138 	.set_events = transport_dbus_set_events,
139 	.clear_events = transport_dbus_clear_events,
140 };
141 
142 static int transport_dbus_reset(sd_bus_message *m, void *userdata,
143 				     sd_bus_error *ret_error)
144 {
145 	struct mbox_context *context = userdata;
146 	sd_bus_message *n;
147 	int rc;
148 
149 	if (!context) {
150 		MSG_ERR("DBUS Internal Error\n");
151 		return -EINVAL;
152 	}
153 
154 	rc = context->protocol->reset(context);
155 	if (rc < 0) {
156 		return rc;
157 	}
158 
159 	rc = sd_bus_message_new_method_return(m, &n);
160 	if (rc < 0) {
161 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
162 		return rc;
163 	}
164 
165 	return sd_bus_send(NULL, n, NULL);
166 }
167 
168 static int transport_dbus_get_info(sd_bus_message *m, void *userdata,
169 					sd_bus_error *ret_error)
170 {
171 	struct mbox_context *context = userdata;
172 	struct protocol_get_info io;
173 	sd_bus_message *n;
174 	int rc;
175 
176 	if (!context) {
177 		MSG_ERR("DBUS Internal Error\n");
178 		return -EINVAL;
179 	}
180 
181 	rc = sd_bus_message_read_basic(m, 'y', &io.req.api_version);
182 	if (rc < 0) {
183 		MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
184 		return rc;
185 	}
186 
187 	rc = context->protocol->get_info(context, &io);
188 	if (rc < 0) {
189 		return rc;
190 	}
191 
192 	/* Switch transport to DBus. This is fine as DBus signals are async */
193 	context->transport = &transport_dbus_ops;
194 	/* A bit messy, but we need the correct event mask */
195 	protocol_events_set(context, context->bmc_events);
196 
197 	rc = sd_bus_message_new_method_return(m, &n);
198 	if (rc < 0) {
199 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
200 		return rc;
201 	}
202 
203 	if (API_VERSION_2 != io.resp.api_version) {
204 		MSG_ERR("Unsupported protocol version for DBus transport: %d\n",
205 			io.resp.api_version);
206 		return rc;
207 	}
208 
209 	rc = sd_bus_message_append(n, "yyq",
210 				   io.resp.api_version,
211 				   io.resp.v2.block_size_shift,
212 				   io.resp.v2.timeout);
213 	if (rc < 0) {
214 		MSG_ERR("sd_bus_message_append failed!\n");
215 		return rc;
216 	}
217 
218 	return sd_bus_send(NULL, n, NULL);
219 }
220 
221 static int transport_dbus_get_flash_info(sd_bus_message *m, void *userdata,
222 					 sd_bus_error *ret_error)
223 {
224 	struct mbox_context *context = userdata;
225 	struct protocol_get_flash_info io;
226 	sd_bus_message *n;
227 	int rc;
228 
229 	if (!context) {
230 		MSG_ERR("DBUS Internal Error\n");
231 		return -EINVAL;
232 	}
233 
234 	rc = context->protocol->get_flash_info(context, &io);
235 	if (rc < 0) {
236 		return rc;
237 	}
238 
239 	rc = sd_bus_message_new_method_return(m, &n);
240 	if (rc < 0) {
241 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
242 		return rc;
243 	}
244 
245 	rc = sd_bus_message_append(n, "qq",
246 				   io.resp.v2.flash_size,
247 				   io.resp.v2.erase_size);
248 	if (rc < 0) {
249 		MSG_ERR("sd_bus_message_append failed!\n");
250 		return rc;
251 	}
252 
253 	return sd_bus_send(NULL, n, NULL);
254 }
255 
256 static int transport_dbus_create_window(struct mbox_context *context,
257 					bool ro,
258 					sd_bus_message *m,
259 					sd_bus_error *ret_error)
260 {
261 	struct protocol_create_window io;
262 	sd_bus_message *n;
263 	int rc;
264 
265 	if (!context) {
266 		MSG_ERR("DBUS Internal Error\n");
267 		return -EINVAL;
268 	}
269 
270 	rc = sd_bus_message_read(m, "qq", &io.req.offset, &io.req.size);
271 	if (rc < 0) {
272 		MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
273 		return rc;
274 	}
275 
276 	io.req.ro = ro;
277 	rc = context->protocol->create_window(context, &io);
278 	if (rc < 0) {
279 		return rc;
280 	}
281 
282 	rc = sd_bus_message_new_method_return(m, &n);
283 	if (rc < 0) {
284 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
285 		return rc;
286 	}
287 
288 	rc = sd_bus_message_append(n, "qqq",
289 				   io.resp.lpc_address,
290 				   io.resp.size,
291 				   io.resp.offset);
292 	if (rc < 0) {
293 		MSG_ERR("sd_bus_message_append failed!\n");
294 		return rc;
295 	}
296 
297 	return sd_bus_send(NULL, n, NULL);
298 }
299 
300 static int transport_dbus_create_read_window(sd_bus_message *m, void *userdata,
301 					     sd_bus_error *ret_error)
302 {
303 	struct mbox_context *context = userdata;
304 
305 	return transport_dbus_create_window(context, true, m, ret_error);
306 }
307 
308 static int transport_dbus_create_write_window(sd_bus_message *m, void *userdata,
309 					      sd_bus_error *ret_error)
310 {
311 	struct mbox_context *context = userdata;
312 
313 	return transport_dbus_create_window(context, false, m, ret_error);
314 }
315 
316 static int transport_dbus_close_window(sd_bus_message *m, void *userdata,
317 				sd_bus_error *ret_error)
318 {
319 	struct mbox_context *context = userdata;
320 	struct protocol_close io;
321 	sd_bus_message *n;
322 	int rc;
323 
324 	if (!context) {
325 		MSG_ERR("DBUS Internal Error\n");
326 		return -EINVAL;
327 	}
328 
329 	rc = sd_bus_message_read(m, "y", &io.req.flags);
330 	if (rc < 0) {
331 		MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
332 		return rc;
333 	}
334 
335 	rc = context->protocol->close(context, &io);
336 	if (rc < 0) {
337 		return rc;
338 	}
339 
340 	rc = sd_bus_message_new_method_return(m, &n);
341 	if (rc < 0) {
342 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
343 		return rc;
344 	}
345 
346 	return sd_bus_send(NULL, n, NULL);
347 
348 }
349 
350 static int transport_dbus_mark_dirty(sd_bus_message *m, void *userdata,
351 				     sd_bus_error *ret_error)
352 {
353 	struct mbox_context *context = userdata;
354 	struct protocol_mark_dirty io;
355 	sd_bus_message *n;
356 	int rc;
357 
358 	if (!context) {
359 		MSG_ERR("DBUS Internal Error\n");
360 		return -EINVAL;
361 	}
362 
363 	rc = sd_bus_message_read(m, "qq", &io.req.v2.offset, &io.req.v2.size);
364 	if (rc < 0) {
365 		MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
366 		return rc;
367 	}
368 
369 	rc = context->protocol->mark_dirty(context, &io);
370 	if (rc < 0) {
371 		return rc;
372 	}
373 
374 	rc = sd_bus_message_new_method_return(m, &n);
375 	if (rc < 0) {
376 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
377 		return rc;
378 	}
379 
380 	return sd_bus_send(NULL, n, NULL);
381 }
382 
383 static int transport_dbus_write_flush(sd_bus_message *m, void *userdata,
384 				      sd_bus_error *ret_error)
385 {
386 	struct mbox_context *context = userdata;
387 	sd_bus_message *n;
388 	int rc;
389 
390 	if (!context) {
391 		MSG_ERR("DBUS Internal Error\n");
392 		return -EINVAL;
393 	}
394 
395 	rc = context->protocol->flush(context, NULL /* No args in v2 */);
396 	if (rc < 0) {
397 		return rc;
398 	}
399 
400 	rc = sd_bus_message_new_method_return(m, &n);
401 	if (rc < 0) {
402 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
403 		return rc;
404 	}
405 
406 	return sd_bus_send(NULL, n, NULL);
407 }
408 
409 static int transport_dbus_ack(sd_bus_message *m, void *userdata,
410 			      sd_bus_error *ret_error)
411 {
412 	struct mbox_context *context = userdata;
413 	struct protocol_ack io;
414 	sd_bus_message *n;
415 	int rc;
416 
417 	if (!context) {
418 		MSG_ERR("DBUS Internal Error\n");
419 		return -EINVAL;
420 	}
421 
422 	rc = sd_bus_message_read_basic(m, 'y', &io.req.flags);
423 	if (rc < 0) {
424 		MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
425 		return rc;
426 	}
427 
428 	rc = context->protocol->ack(context, &io);
429 	if (rc < 0) {
430 		return rc;
431 	}
432 
433 	rc = sd_bus_message_new_method_return(m, &n);
434 	if (rc < 0) {
435 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
436 		return rc;
437 	}
438 
439 	return sd_bus_send(NULL, n, NULL);
440 }
441 
442 static int transport_dbus_erase(sd_bus_message *m, void *userdata,
443 				sd_bus_error *ret_error)
444 {
445 	struct mbox_context *context = userdata;
446 	struct protocol_erase io;
447 	sd_bus_message *n;
448 	int rc;
449 
450 	if (!context) {
451 		MSG_ERR("DBUS Internal Error\n");
452 		return -EINVAL;
453 	}
454 
455 	rc = sd_bus_message_read(m, "qq", &io.req.offset, &io.req.size);
456 	if (rc < 0) {
457 		MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
458 		return rc;
459 	}
460 
461 	rc = context->protocol->erase(context, &io);
462 	if (rc < 0) {
463 		return rc;
464 	}
465 
466 	rc = sd_bus_message_new_method_return(m, &n);
467 	if (rc < 0) {
468 		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
469 		return rc;
470 	}
471 
472 	return sd_bus_send(NULL, n, NULL);
473 }
474 
475 static int transport_dbus_get_property(sd_bus *bus,
476 				       const char *path,
477 				       const char *interface,
478 				       const char *property,
479 				       sd_bus_message *reply,
480 				       void *userdata,
481 				       sd_bus_error *ret_error)
482 {
483 	struct mbox_context *context = userdata;
484 	bool value;
485 
486 	assert(!strcmp(MBOX_DBUS_OBJECT, path));
487 	assert(!strcmp(MBOX_DBUS_PROTOCOL_IFACE_V2, interface));
488 
489 	if (!strcmp("FlashControlLost", property)) {
490 		value = context->bmc_events & BMC_EVENT_FLASH_CTRL_LOST;
491 	} else if (!strcmp("DaemonReady", property)) {
492 		value = context->bmc_events & BMC_EVENT_DAEMON_READY;
493 	} else if (!strcmp("WindowReset", property)) {
494 		value = context->bmc_events & BMC_EVENT_WINDOW_RESET;
495 	} else if (!strcmp("ProtocolReset", property)) {
496 		value = context->bmc_events & BMC_EVENT_PROTOCOL_RESET;
497 	} else {
498 		MSG_ERR("Unknown DBus property: %s\n", property);
499 		return -EINVAL;
500 	}
501 
502 	return sd_bus_message_append(reply, "b", value);
503 }
504 
505 static const sd_bus_vtable protocol_unversioned_vtable[] = {
506 	SD_BUS_VTABLE_START(0),
507 	SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset,
508 		      SD_BUS_VTABLE_UNPRIVILEGED),
509 	SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info,
510 		      SD_BUS_VTABLE_UNPRIVILEGED),
511 	SD_BUS_METHOD("Ack", "y", NULL, &transport_dbus_ack,
512 		      SD_BUS_VTABLE_UNPRIVILEGED),
513 	SD_BUS_VTABLE_END
514 };
515 
516 static const sd_bus_vtable protocol_v2_vtable[] = {
517 	SD_BUS_VTABLE_START(0),
518 	SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset,
519 		      SD_BUS_VTABLE_UNPRIVILEGED),
520 	SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info,
521 		      SD_BUS_VTABLE_UNPRIVILEGED),
522 	SD_BUS_METHOD("GetFlashInfo", NULL, "qq",
523 		      &transport_dbus_get_flash_info,
524 		      SD_BUS_VTABLE_UNPRIVILEGED),
525 	SD_BUS_METHOD("CreateReadWindow", "qq", "qqq",
526 		      &transport_dbus_create_read_window,
527 		      SD_BUS_VTABLE_UNPRIVILEGED),
528 	SD_BUS_METHOD("CreateWriteWindow", "qq", "qqq",
529 		      &transport_dbus_create_write_window,
530 		      SD_BUS_VTABLE_UNPRIVILEGED),
531 	SD_BUS_METHOD("CloseWindow", "y", NULL, &transport_dbus_close_window,
532 		      SD_BUS_VTABLE_UNPRIVILEGED),
533 	SD_BUS_METHOD("MarkDirty", "qq", NULL, &transport_dbus_mark_dirty,
534 		      SD_BUS_VTABLE_UNPRIVILEGED),
535 	SD_BUS_METHOD("Flush", NULL, NULL, &transport_dbus_write_flush,
536 		      SD_BUS_VTABLE_UNPRIVILEGED),
537 	SD_BUS_METHOD("Ack", "y", NULL, &transport_dbus_ack,
538 		      SD_BUS_VTABLE_UNPRIVILEGED),
539 	SD_BUS_METHOD("Erase", "qq", NULL, &transport_dbus_erase,
540 		      SD_BUS_VTABLE_UNPRIVILEGED),
541 	SD_BUS_PROPERTY("FlashControlLost", "b", transport_dbus_get_property,
542 			0, /* Just a pointer to struct mbox_context */
543 			SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
544 	SD_BUS_PROPERTY("DaemonReady", "b", transport_dbus_get_property,
545 			0, /* Just a pointer to struct mbox_context */
546 			SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
547 	SD_BUS_SIGNAL("ProtocolReset", NULL, 0),
548 	SD_BUS_SIGNAL("WindowReset", NULL, 0),
549 	SD_BUS_PROPERTY("ProtocolReset",  "b",
550 			transport_dbus_get_property,
551 			0, /* Just a pointer to struct mbox_context */
552 			SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
553 	SD_BUS_PROPERTY("WindowReset", "b",
554 			transport_dbus_get_property,
555 			0, /* Just a pointer to struct mbox_context */
556 			SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
557 	SD_BUS_VTABLE_END
558 };
559 
560 int transport_dbus_init(struct mbox_context *context,
561 			const struct transport_ops **ops)
562 {
563 	int rc;
564 
565 	rc = sd_bus_add_object_vtable(context->bus, NULL,
566 					MBOX_DBUS_OBJECT,
567 					MBOX_DBUS_PROTOCOL_IFACE,
568 					protocol_unversioned_vtable,
569 					context);
570 	if (rc < 0) {
571 		return rc;
572 	}
573 
574 	rc = sd_bus_add_object_vtable(context->bus, NULL,
575 					MBOX_DBUS_OBJECT,
576 					MBOX_DBUS_PROTOCOL_IFACE_V2,
577 					protocol_v2_vtable, context);
578 	if (rc < 0) {
579 		return rc;
580 	}
581 
582 	if (ops) {
583 		*ops = &transport_dbus_ops;
584 	}
585 
586 	return 0;
587 }
588 
589 #define __unused __attribute__((unused))
590 void transport_dbus_free(struct mbox_context *context __unused)
591 {
592 	return;
593 }
594