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