blob: 3ad0dad7141e9ed4afa78de9a3e0c544129f7325 [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 Jefferya6ca7a92018-08-20 13:03:44 +093022
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
Andrew Jeffery0453aa42018-08-21 08:25:46 +093031 return sd_bus_emit_properties_changed_strv(context->bus,
Andrew Jefferya6ca7a92018-08-20 13:03:44 +093032 MBOX_DBUS_OBJECT,
33 /* FIXME: Hard-coding v2 */
34 MBOX_DBUS_PROTOCOL_IFACE_V2,
35 props);
Andrew Jeffery0453aa42018-08-21 08:25:46 +093036}
37
38static 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);
Andrew Jefferya6ca7a92018-08-20 13:03:44 +093044 if (rc < 0) {
45 return rc;
46 }
47
Andrew Jeffery0453aa42018-08-21 08:25:46 +093048 /*
49 * Handle signals - edge triggered, only necessary when they're
50 * asserted
51 */
Andrew Jefferya6ca7a92018-08-20 13:03:44 +093052 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
Andrew Jeffery4414fb82018-08-20 12:13:09 +093091static int transport_dbus_clear_events(struct mbox_context *context,
92 uint8_t events)
Andrew Jeffery23a48212018-08-10 14:41:48 +093093{
Andrew Jeffery0453aa42018-08-21 08:25:46 +093094 /* No need to emit signals for ackable events on clear */
95 return transport_dbus_property_update(context, events);
Andrew Jeffery23a48212018-08-10 14:41:48 +093096}
97
98static const struct transport_ops transport_dbus_ops = {
Andrew Jeffery4414fb82018-08-20 12:13:09 +093099 .set_events = transport_dbus_set_events,
100 .clear_events = transport_dbus_clear_events,
Andrew Jeffery23a48212018-08-10 14:41:48 +0930101};
Andrew Jeffery23140be2018-09-05 14:15:07 +0930102
Andrew Jeffery7255d262018-08-23 16:53:48 +0930103static 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
Andrew Jeffery23140be2018-09-05 14:15:07 +0930129static 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
Andrew Jeffery23a48212018-08-10 14:41:48 +0930153 /* Switch transport to DBus. This is fine as DBus signals are async */
154 context->transport = &transport_dbus_ops;
Andrew Jeffery0453aa42018-08-21 08:25:46 +0930155 /* A bit messy, but we need the correct event mask */
156 protocol_events_set(context, context->bmc_events);
Andrew Jeffery23a48212018-08-10 14:41:48 +0930157
Andrew Jeffery23140be2018-09-05 14:15:07 +0930158 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
Andrew Jeffery9c627172018-08-23 20:59:54 +0930182static 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
Andrew Jeffery0e785f42018-08-23 21:43:44 +0930217static int transport_dbus_create_window(struct mbox_context *context,
218 bool ro,
219 sd_bus_message *m,
220 sd_bus_error *ret_error)
Andrew Jefferyb9d72d02018-08-23 21:36:49 +0930221{
Andrew Jefferyb9d72d02018-08-23 21:36:49 +0930222 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
Andrew Jeffery0e785f42018-08-23 21:43:44 +0930237 io.req.ro = ro;
Andrew Jefferyb9d72d02018-08-23 21:36:49 +0930238 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
Andrew Jeffery0e785f42018-08-23 21:43:44 +0930261static 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
269static 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
Andrew Jefferyc2cbb3d2018-08-23 22:55:33 +0930277static 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
Andrew Jeffery40ef67b2018-08-24 07:14:25 +0930311static 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
Andrew Jefferyd66af2a2018-08-24 08:28:13 +0930344static 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
Andrew Jefferybcc33992018-08-23 17:19:25 +0930370static 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
Andrew Jefferyea5400f2018-08-24 09:36:44 +0930403static 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
Andrew Jefferya6ca7a92018-08-20 13:03:44 +0930436static 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
Andrew Jeffery23140be2018-09-05 14:15:07 +0930462static const sd_bus_vtable protocol_unversioned_vtable[] = {
463 SD_BUS_VTABLE_START(0),
Andrew Jeffery7255d262018-08-23 16:53:48 +0930464 SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset,
465 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery23140be2018-09-05 14:15:07 +0930466 SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info,
467 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferybcc33992018-08-23 17:19:25 +0930468 SD_BUS_METHOD("Ack", "y", NULL, &transport_dbus_ack,
469 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery23140be2018-09-05 14:15:07 +0930470 SD_BUS_VTABLE_END
471};
472
473static const sd_bus_vtable protocol_v2_vtable[] = {
474 SD_BUS_VTABLE_START(0),
Andrew Jeffery7255d262018-08-23 16:53:48 +0930475 SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset,
476 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery23140be2018-09-05 14:15:07 +0930477 SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info,
478 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery9c627172018-08-23 20:59:54 +0930479 SD_BUS_METHOD("GetFlashInfo", NULL, "qq",
480 &transport_dbus_get_flash_info,
481 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferyb9d72d02018-08-23 21:36:49 +0930482 SD_BUS_METHOD("CreateReadWindow", "qq", "qqq",
483 &transport_dbus_create_read_window,
484 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery0e785f42018-08-23 21:43:44 +0930485 SD_BUS_METHOD("CreateWriteWindow", "qq", "qqq",
486 &transport_dbus_create_write_window,
487 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferyc2cbb3d2018-08-23 22:55:33 +0930488 SD_BUS_METHOD("CloseWindow", "y", NULL, &transport_dbus_close_window,
489 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery40ef67b2018-08-24 07:14:25 +0930490 SD_BUS_METHOD("MarkDirty", "qq", NULL, &transport_dbus_mark_dirty,
491 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferyd66af2a2018-08-24 08:28:13 +0930492 SD_BUS_METHOD("Flush", NULL, NULL, &transport_dbus_write_flush,
493 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferybcc33992018-08-23 17:19:25 +0930494 SD_BUS_METHOD("Ack", "y", NULL, &transport_dbus_ack,
495 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferyea5400f2018-08-24 09:36:44 +0930496 SD_BUS_METHOD("Erase", "qq", NULL, &transport_dbus_erase,
497 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferya6ca7a92018-08-20 13:03:44 +0930498 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),
Andrew Jeffery23140be2018-09-05 14:15:07 +0930506 SD_BUS_VTABLE_END
507};
508
509int 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,
Andrew Jefferya6ca7a92018-08-20 13:03:44 +0930524 MBOX_DBUS_PROTOCOL_IFACE_V2,
Andrew Jeffery23140be2018-09-05 14:15:07 +0930525 protocol_v2_vtable, context);
526
527 return rc;
528}
529
530#define __unused __attribute__((unused))
531void transport_dbus_free(struct mbox_context *context __unused)
532{
533 return;
534}