xref: /openbmc/hiomapd/transport_dbus.c (revision cc650618464218891b1781c86a1bc2a57553f752)
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