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