blob: d1ef4afa8773441aa7e3f7b9eaf098cc02ec9b4f [file] [log] [blame]
Andrew Jeffery23140be2018-09-05 14:15:07 +09301// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2018 IBM Corp.
3#include "config.h"
4
Andrew Jefferya6ca7a92018-08-20 13:03:44 +09305#include <assert.h>
Andrew Jeffery23140be2018-09-05 14:15:07 +09306#include <errno.h>
Andrew Jefferya6ca7a92018-08-20 13:03:44 +09307#include <string.h>
Andrew Jeffery23140be2018-09-05 14:15:07 +09308#include <systemd/sd-bus.h>
9
10#include "common.h"
11#include "dbus.h"
12#include "mboxd.h"
13#include "protocol.h"
Andrew Jeffery23a48212018-08-10 14:41:48 +093014#include "transport.h"
15
Andrew Jeffery0453aa42018-08-21 08:25:46 +093016static int transport_dbus_property_update(struct mbox_context *context,
17 uint8_t events)
Andrew Jefferya6ca7a92018-08-20 13:03:44 +093018{
Andrew Jeffery0453aa42018-08-21 08:25:46 +093019 /* Two properties plus a terminating NULL */
Andrew Jefferya6ca7a92018-08-20 13:03:44 +093020 char *props[3] = { 0 };
21 int i = 0;
Andrew Jefferyf62601b2018-11-01 13:44:25 +103022 int rc;
Andrew Jefferya6ca7a92018-08-20 13:03:44 +093023
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
Andrew Jefferyf62601b2018-11-01 13:44:25 +103032 rc = sd_bus_emit_properties_changed_strv(context->bus,
Andrew Jefferya6ca7a92018-08-20 13:03:44 +093033 MBOX_DBUS_OBJECT,
34 /* FIXME: Hard-coding v2 */
35 MBOX_DBUS_PROTOCOL_IFACE_V2,
36 props);
Andrew Jefferyf62601b2018-11-01 13:44:25 +103037
38 return (rc < 0) ? rc : 0;
Andrew Jeffery0453aa42018-08-21 08:25:46 +093039}
40
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +103041static int transport_dbus_signal_update(struct mbox_context *context,
42 uint8_t events)
Andrew Jeffery0453aa42018-08-21 08:25:46 +093043{
44 int rc;
45
Andrew Jeffery0453aa42018-08-21 08:25:46 +093046 /*
47 * Handle signals - edge triggered, only necessary when they're
48 * asserted
49 */
Andrew Jefferya6ca7a92018-08-20 13:03:44 +093050 if (events & BMC_EVENT_WINDOW_RESET) {
51 sd_bus_message *m = NULL;
52
53 rc = sd_bus_message_new_signal(context->bus, &m,
54 MBOX_DBUS_OBJECT,
55 /* FIXME: Hard-coding v2 */
56 MBOX_DBUS_PROTOCOL_IFACE_V2,
57 "WindowReset");
58 if (rc < 0) {
59 return rc;
60 }
61
62 rc = sd_bus_send(context->bus, m, NULL);
63 if (rc < 0) {
64 return rc;
65 }
66 }
67
68 if (events & BMC_EVENT_REBOOT) {
69 sd_bus_message *m = NULL;
70
71 rc = sd_bus_message_new_signal(context->bus, &m,
72 MBOX_DBUS_OBJECT,
73 /* FIXME: Hard-coding v2 */
74 MBOX_DBUS_PROTOCOL_IFACE_V2,
75 "ProtocolReset");
76 if (rc < 0) {
77 return rc;
78 }
79
80 rc = sd_bus_send(context->bus, m, NULL);
81 if (rc < 0) {
82 return rc;
83 }
84 }
85
86 return 0;
87}
88
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +103089static int transport_dbus_put_events(struct mbox_context *context, uint8_t mask)
90{
91 int rc;
92
93 /* Always update all properties */
94 rc = transport_dbus_property_update(context, mask);
95 if (rc < 0) {
96 return rc;
97 }
98
99 /*
100 * Still test signals against the values set as sending them indicates
101 * the event has been asserted, so we must not send them if the bits
102 * are not set.
103 */
104 return transport_dbus_signal_update(context,
105 context->bmc_events & mask);
106}
107
108static int transport_dbus_set_events(struct mbox_context *context,
109 uint8_t events, uint8_t mask)
110{
111 int rc;
112
113 rc = transport_dbus_property_update(context, events & mask);
114 if (rc < 0) {
115 return rc;
116 }
117
118 return transport_dbus_signal_update(context, events & mask);
119}
120
Andrew Jeffery4414fb82018-08-20 12:13:09 +0930121static int transport_dbus_clear_events(struct mbox_context *context,
Andrew Jefferyf62601b2018-11-01 13:44:25 +1030122 uint8_t events, uint8_t mask)
Andrew Jeffery23a48212018-08-10 14:41:48 +0930123{
Andrew Jeffery0453aa42018-08-21 08:25:46 +0930124 /* No need to emit signals for ackable events on clear */
Andrew Jefferyf62601b2018-11-01 13:44:25 +1030125 return transport_dbus_property_update(context, events & mask);
Andrew Jeffery23a48212018-08-10 14:41:48 +0930126}
127
128static const struct transport_ops transport_dbus_ops = {
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030129 .put_events = transport_dbus_put_events,
Andrew Jeffery4414fb82018-08-20 12:13:09 +0930130 .set_events = transport_dbus_set_events,
131 .clear_events = transport_dbus_clear_events,
Andrew Jeffery23a48212018-08-10 14:41:48 +0930132};
Andrew Jeffery23140be2018-09-05 14:15:07 +0930133
Andrew Jeffery7255d262018-08-23 16:53:48 +0930134static int transport_dbus_reset(sd_bus_message *m, void *userdata,
135 sd_bus_error *ret_error)
136{
137 struct mbox_context *context = userdata;
138 sd_bus_message *n;
139 int rc;
140
141 if (!context) {
142 MSG_ERR("DBUS Internal Error\n");
143 return -EINVAL;
144 }
145
146 rc = context->protocol->reset(context);
147 if (rc < 0) {
148 return rc;
149 }
150
151 rc = sd_bus_message_new_method_return(m, &n);
152 if (rc < 0) {
153 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
154 return rc;
155 }
156
157 return sd_bus_send(NULL, n, NULL);
158}
159
Andrew Jeffery23140be2018-09-05 14:15:07 +0930160static int transport_dbus_get_info(sd_bus_message *m, void *userdata,
161 sd_bus_error *ret_error)
162{
163 struct mbox_context *context = userdata;
164 struct protocol_get_info io;
165 sd_bus_message *n;
166 int rc;
167
168 if (!context) {
169 MSG_ERR("DBUS Internal Error\n");
170 return -EINVAL;
171 }
172
173 rc = sd_bus_message_read_basic(m, 'y', &io.req.api_version);
174 if (rc < 0) {
175 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
176 return rc;
177 }
178
179 rc = context->protocol->get_info(context, &io);
180 if (rc < 0) {
181 return rc;
182 }
183
Andrew Jeffery23a48212018-08-10 14:41:48 +0930184 /* Switch transport to DBus. This is fine as DBus signals are async */
185 context->transport = &transport_dbus_ops;
Andrew Jeffery0453aa42018-08-21 08:25:46 +0930186 /* A bit messy, but we need the correct event mask */
187 protocol_events_set(context, context->bmc_events);
Andrew Jeffery23a48212018-08-10 14:41:48 +0930188
Andrew Jeffery23140be2018-09-05 14:15:07 +0930189 rc = sd_bus_message_new_method_return(m, &n);
190 if (rc < 0) {
191 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
192 return rc;
193 }
194
195 if (API_VERSION_2 != io.resp.api_version) {
196 MSG_ERR("Unsupported protocol version for DBus transport: %d\n",
197 io.resp.api_version);
198 return rc;
199 }
200
201 rc = sd_bus_message_append(n, "yyq",
202 io.resp.api_version,
203 io.resp.v2.block_size_shift,
204 io.resp.v2.timeout);
205 if (rc < 0) {
206 MSG_ERR("sd_bus_message_append failed!\n");
207 return rc;
208 }
209
210 return sd_bus_send(NULL, n, NULL);
211}
212
Andrew Jeffery9c627172018-08-23 20:59:54 +0930213static int transport_dbus_get_flash_info(sd_bus_message *m, void *userdata,
214 sd_bus_error *ret_error)
215{
216 struct mbox_context *context = userdata;
217 struct protocol_get_flash_info io;
218 sd_bus_message *n;
219 int rc;
220
221 if (!context) {
222 MSG_ERR("DBUS Internal Error\n");
223 return -EINVAL;
224 }
225
226 rc = context->protocol->get_flash_info(context, &io);
227 if (rc < 0) {
228 return rc;
229 }
230
231 rc = sd_bus_message_new_method_return(m, &n);
232 if (rc < 0) {
233 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
234 return rc;
235 }
236
237 rc = sd_bus_message_append(n, "qq",
238 io.resp.v2.flash_size,
239 io.resp.v2.erase_size);
240 if (rc < 0) {
241 MSG_ERR("sd_bus_message_append failed!\n");
242 return rc;
243 }
244
245 return sd_bus_send(NULL, n, NULL);
246}
247
Andrew Jeffery0e785f42018-08-23 21:43:44 +0930248static int transport_dbus_create_window(struct mbox_context *context,
249 bool ro,
250 sd_bus_message *m,
251 sd_bus_error *ret_error)
Andrew Jefferyb9d72d02018-08-23 21:36:49 +0930252{
Andrew Jefferyb9d72d02018-08-23 21:36:49 +0930253 struct protocol_create_window io;
254 sd_bus_message *n;
255 int rc;
256
257 if (!context) {
258 MSG_ERR("DBUS Internal Error\n");
259 return -EINVAL;
260 }
261
262 rc = sd_bus_message_read(m, "qq", &io.req.offset, &io.req.size);
263 if (rc < 0) {
264 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
265 return rc;
266 }
267
Andrew Jeffery0e785f42018-08-23 21:43:44 +0930268 io.req.ro = ro;
Andrew Jefferyb9d72d02018-08-23 21:36:49 +0930269 rc = context->protocol->create_window(context, &io);
270 if (rc < 0) {
271 return rc;
272 }
273
274 rc = sd_bus_message_new_method_return(m, &n);
275 if (rc < 0) {
276 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
277 return rc;
278 }
279
280 rc = sd_bus_message_append(n, "qqq",
281 io.resp.lpc_address,
282 io.resp.size,
283 io.resp.offset);
284 if (rc < 0) {
285 MSG_ERR("sd_bus_message_append failed!\n");
286 return rc;
287 }
288
289 return sd_bus_send(NULL, n, NULL);
290}
291
Andrew Jeffery0e785f42018-08-23 21:43:44 +0930292static int transport_dbus_create_read_window(sd_bus_message *m, void *userdata,
293 sd_bus_error *ret_error)
294{
295 struct mbox_context *context = userdata;
296
297 return transport_dbus_create_window(context, true, m, ret_error);
298}
299
300static int transport_dbus_create_write_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, false, m, ret_error);
306}
307
Andrew Jefferyc2cbb3d2018-08-23 22:55:33 +0930308static int transport_dbus_close_window(sd_bus_message *m, void *userdata,
309 sd_bus_error *ret_error)
310{
311 struct mbox_context *context = userdata;
312 struct protocol_close io;
313 sd_bus_message *n;
314 int rc;
315
316 if (!context) {
317 MSG_ERR("DBUS Internal Error\n");
318 return -EINVAL;
319 }
320
321 rc = sd_bus_message_read(m, "y", &io.req.flags);
322 if (rc < 0) {
323 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
324 return rc;
325 }
326
327 rc = context->protocol->close(context, &io);
328 if (rc < 0) {
329 return rc;
330 }
331
332 rc = sd_bus_message_new_method_return(m, &n);
333 if (rc < 0) {
334 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
335 return rc;
336 }
337
338 return sd_bus_send(NULL, n, NULL);
339
340}
341
Andrew Jeffery40ef67b2018-08-24 07:14:25 +0930342static int transport_dbus_mark_dirty(sd_bus_message *m, void *userdata,
343 sd_bus_error *ret_error)
344{
345 struct mbox_context *context = userdata;
346 struct protocol_mark_dirty io;
347 sd_bus_message *n;
348 int rc;
349
350 if (!context) {
351 MSG_ERR("DBUS Internal Error\n");
352 return -EINVAL;
353 }
354
355 rc = sd_bus_message_read(m, "qq", &io.req.v2.offset, &io.req.v2.size);
356 if (rc < 0) {
357 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
358 return rc;
359 }
360
361 rc = context->protocol->mark_dirty(context, &io);
362 if (rc < 0) {
363 return rc;
364 }
365
366 rc = sd_bus_message_new_method_return(m, &n);
367 if (rc < 0) {
368 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
369 return rc;
370 }
371
372 return sd_bus_send(NULL, n, NULL);
373}
374
Andrew Jefferyd66af2a2018-08-24 08:28:13 +0930375static int transport_dbus_write_flush(sd_bus_message *m, void *userdata,
376 sd_bus_error *ret_error)
377{
378 struct mbox_context *context = userdata;
379 sd_bus_message *n;
380 int rc;
381
382 if (!context) {
383 MSG_ERR("DBUS Internal Error\n");
384 return -EINVAL;
385 }
386
387 rc = context->protocol->flush(context, NULL /* No args in v2 */);
388 if (rc < 0) {
389 return rc;
390 }
391
392 rc = sd_bus_message_new_method_return(m, &n);
393 if (rc < 0) {
394 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
395 return rc;
396 }
397
398 return sd_bus_send(NULL, n, NULL);
399}
400
Andrew Jefferybcc33992018-08-23 17:19:25 +0930401static int transport_dbus_ack(sd_bus_message *m, void *userdata,
402 sd_bus_error *ret_error)
403{
404 struct mbox_context *context = userdata;
405 struct protocol_ack io;
406 sd_bus_message *n;
407 int rc;
408
409 if (!context) {
410 MSG_ERR("DBUS Internal Error\n");
411 return -EINVAL;
412 }
413
414 rc = sd_bus_message_read_basic(m, 'y', &io.req.flags);
415 if (rc < 0) {
416 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
417 return rc;
418 }
419
420 rc = context->protocol->ack(context, &io);
421 if (rc < 0) {
422 return rc;
423 }
424
425 rc = sd_bus_message_new_method_return(m, &n);
426 if (rc < 0) {
427 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
428 return rc;
429 }
430
431 return sd_bus_send(NULL, n, NULL);
432}
433
Andrew Jefferyea5400f2018-08-24 09:36:44 +0930434static int transport_dbus_erase(sd_bus_message *m, void *userdata,
435 sd_bus_error *ret_error)
436{
437 struct mbox_context *context = userdata;
438 struct protocol_erase io;
439 sd_bus_message *n;
440 int rc;
441
442 if (!context) {
443 MSG_ERR("DBUS Internal Error\n");
444 return -EINVAL;
445 }
446
447 rc = sd_bus_message_read(m, "qq", &io.req.offset, &io.req.size);
448 if (rc < 0) {
449 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
450 return rc;
451 }
452
453 rc = context->protocol->erase(context, &io);
454 if (rc < 0) {
455 return rc;
456 }
457
458 rc = sd_bus_message_new_method_return(m, &n);
459 if (rc < 0) {
460 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
461 return rc;
462 }
463
464 return sd_bus_send(NULL, n, NULL);
465}
466
Andrew Jefferya6ca7a92018-08-20 13:03:44 +0930467static int transport_dbus_get_property(sd_bus *bus,
468 const char *path,
469 const char *interface,
470 const char *property,
471 sd_bus_message *reply,
472 void *userdata,
473 sd_bus_error *ret_error)
474{
475 struct mbox_context *context = userdata;
476 bool value;
477
478 assert(!strcmp(MBOX_DBUS_OBJECT, path));
479 assert(!strcmp(MBOX_DBUS_PROTOCOL_IFACE_V2, interface));
480
481 if (!strcmp("FlashControlLost", property)) {
482 value = context->bmc_events & BMC_EVENT_FLASH_CTRL_LOST;
483 } else if (!strcmp("DaemonReady", property)) {
484 value = context->bmc_events & BMC_EVENT_DAEMON_READY;
485 } else {
486 MSG_ERR("Unknown DBus property: %s\n", property);
487 return -EINVAL;
488 }
489
490 return sd_bus_message_append(reply, "b", value);
491}
492
Andrew Jeffery23140be2018-09-05 14:15:07 +0930493static const sd_bus_vtable protocol_unversioned_vtable[] = {
494 SD_BUS_VTABLE_START(0),
Andrew Jeffery7255d262018-08-23 16:53:48 +0930495 SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset,
496 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery23140be2018-09-05 14:15:07 +0930497 SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info,
498 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferybcc33992018-08-23 17:19:25 +0930499 SD_BUS_METHOD("Ack", "y", NULL, &transport_dbus_ack,
500 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery23140be2018-09-05 14:15:07 +0930501 SD_BUS_VTABLE_END
502};
503
504static const sd_bus_vtable protocol_v2_vtable[] = {
505 SD_BUS_VTABLE_START(0),
Andrew Jeffery7255d262018-08-23 16:53:48 +0930506 SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset,
507 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery23140be2018-09-05 14:15:07 +0930508 SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info,
509 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery9c627172018-08-23 20:59:54 +0930510 SD_BUS_METHOD("GetFlashInfo", NULL, "qq",
511 &transport_dbus_get_flash_info,
512 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferyb9d72d02018-08-23 21:36:49 +0930513 SD_BUS_METHOD("CreateReadWindow", "qq", "qqq",
514 &transport_dbus_create_read_window,
515 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery0e785f42018-08-23 21:43:44 +0930516 SD_BUS_METHOD("CreateWriteWindow", "qq", "qqq",
517 &transport_dbus_create_write_window,
518 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferyc2cbb3d2018-08-23 22:55:33 +0930519 SD_BUS_METHOD("CloseWindow", "y", NULL, &transport_dbus_close_window,
520 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery40ef67b2018-08-24 07:14:25 +0930521 SD_BUS_METHOD("MarkDirty", "qq", NULL, &transport_dbus_mark_dirty,
522 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferyd66af2a2018-08-24 08:28:13 +0930523 SD_BUS_METHOD("Flush", NULL, NULL, &transport_dbus_write_flush,
524 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferybcc33992018-08-23 17:19:25 +0930525 SD_BUS_METHOD("Ack", "y", NULL, &transport_dbus_ack,
526 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferyea5400f2018-08-24 09:36:44 +0930527 SD_BUS_METHOD("Erase", "qq", NULL, &transport_dbus_erase,
528 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferya6ca7a92018-08-20 13:03:44 +0930529 SD_BUS_PROPERTY("FlashControlLost", "b", transport_dbus_get_property,
530 0, /* Just a pointer to struct mbox_context */
531 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
532 SD_BUS_PROPERTY("DaemonReady", "b", transport_dbus_get_property,
533 0, /* Just a pointer to struct mbox_context */
534 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
535 SD_BUS_SIGNAL("ProtocolReset", NULL, 0),
536 SD_BUS_SIGNAL("WindowReset", NULL, 0),
Andrew Jeffery23140be2018-09-05 14:15:07 +0930537 SD_BUS_VTABLE_END
538};
539
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030540int transport_dbus_init(struct mbox_context *context,
541 const struct transport_ops **ops)
Andrew Jeffery23140be2018-09-05 14:15:07 +0930542{
543 int rc;
544
545 rc = sd_bus_add_object_vtable(context->bus, NULL,
546 MBOX_DBUS_OBJECT,
547 MBOX_DBUS_PROTOCOL_IFACE,
548 protocol_unversioned_vtable,
549 context);
550 if (rc < 0) {
551 return rc;
552 }
553
554 rc = sd_bus_add_object_vtable(context->bus, NULL,
555 MBOX_DBUS_OBJECT,
Andrew Jefferya6ca7a92018-08-20 13:03:44 +0930556 MBOX_DBUS_PROTOCOL_IFACE_V2,
Andrew Jeffery23140be2018-09-05 14:15:07 +0930557 protocol_v2_vtable, context);
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030558 if (rc < 0) {
559 return rc;
560 }
Andrew Jeffery23140be2018-09-05 14:15:07 +0930561
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030562 if (ops) {
563 *ops = &transport_dbus_ops;
564 }
565
566 return 0;
Andrew Jeffery23140be2018-09-05 14:15:07 +0930567}
568
569#define __unused __attribute__((unused))
570void transport_dbus_free(struct mbox_context *context __unused)
571{
572 return;
573}