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