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