blob: 42fb018b04e582f5bd6d1c0b88721917f0084620 [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 Jefferyfd4fa342018-11-23 08:33:37 +110020 char *props[5] = { 0 };
Andrew Jefferya6ca7a92018-08-20 13:03:44 +093021 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 Jefferyfd4fa342018-11-23 08:33:37 +110032 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
Andrew Jefferyf62601b2018-11-01 13:44:25 +103040 rc = sd_bus_emit_properties_changed_strv(context->bus,
Andrew Jefferya6ca7a92018-08-20 13:03:44 +093041 MBOX_DBUS_OBJECT,
42 /* FIXME: Hard-coding v2 */
43 MBOX_DBUS_PROTOCOL_IFACE_V2,
44 props);
Andrew Jefferyf62601b2018-11-01 13:44:25 +103045
46 return (rc < 0) ? rc : 0;
Andrew Jeffery0453aa42018-08-21 08:25:46 +093047}
48
Andrew Jefferya6ca7a92018-08-20 13:03:44 +093049
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +103050static int transport_dbus_put_events(struct mbox_context *context, uint8_t mask)
51{
Andrew Jeffery9ed627c2018-11-26 14:49:18 +110052 return transport_dbus_property_update(context, mask);
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +103053}
54
55static int transport_dbus_set_events(struct mbox_context *context,
56 uint8_t events, uint8_t mask)
57{
Andrew Jeffery9ed627c2018-11-26 14:49:18 +110058 return transport_dbus_property_update(context, events & mask);
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +103059}
60
Andrew Jeffery4414fb82018-08-20 12:13:09 +093061static int transport_dbus_clear_events(struct mbox_context *context,
Andrew Jefferyf62601b2018-11-01 13:44:25 +103062 uint8_t events, uint8_t mask)
Andrew Jeffery23a48212018-08-10 14:41:48 +093063{
Andrew Jefferyf62601b2018-11-01 13:44:25 +103064 return transport_dbus_property_update(context, events & mask);
Andrew Jeffery23a48212018-08-10 14:41:48 +093065}
66
67static const struct transport_ops transport_dbus_ops = {
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +103068 .put_events = transport_dbus_put_events,
Andrew Jeffery4414fb82018-08-20 12:13:09 +093069 .set_events = transport_dbus_set_events,
70 .clear_events = transport_dbus_clear_events,
Andrew Jeffery23a48212018-08-10 14:41:48 +093071};
Andrew Jeffery23140be2018-09-05 14:15:07 +093072
Andrew Jeffery7255d262018-08-23 16:53:48 +093073static int transport_dbus_reset(sd_bus_message *m, void *userdata,
74 sd_bus_error *ret_error)
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 return sd_bus_send(NULL, n, NULL);
97}
98
Andrew Jeffery23140be2018-09-05 14:15:07 +093099static int transport_dbus_get_info(sd_bus_message *m, void *userdata,
100 sd_bus_error *ret_error)
101{
102 struct mbox_context *context = userdata;
103 struct protocol_get_info io;
104 sd_bus_message *n;
105 int rc;
106
107 if (!context) {
108 MSG_ERR("DBUS Internal Error\n");
109 return -EINVAL;
110 }
111
112 rc = sd_bus_message_read_basic(m, 'y', &io.req.api_version);
113 if (rc < 0) {
114 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
115 return rc;
116 }
117
118 rc = context->protocol->get_info(context, &io);
119 if (rc < 0) {
120 return rc;
121 }
122
Andrew Jeffery23a48212018-08-10 14:41:48 +0930123 /* Switch transport to DBus. This is fine as DBus signals are async */
124 context->transport = &transport_dbus_ops;
Andrew Jeffery0453aa42018-08-21 08:25:46 +0930125 /* A bit messy, but we need the correct event mask */
126 protocol_events_set(context, context->bmc_events);
Andrew Jeffery23a48212018-08-10 14:41:48 +0930127
Andrew Jeffery23140be2018-09-05 14:15:07 +0930128 rc = sd_bus_message_new_method_return(m, &n);
129 if (rc < 0) {
130 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
131 return rc;
132 }
133
134 if (API_VERSION_2 != io.resp.api_version) {
135 MSG_ERR("Unsupported protocol version for DBus transport: %d\n",
136 io.resp.api_version);
137 return rc;
138 }
139
140 rc = sd_bus_message_append(n, "yyq",
141 io.resp.api_version,
142 io.resp.v2.block_size_shift,
143 io.resp.v2.timeout);
144 if (rc < 0) {
145 MSG_ERR("sd_bus_message_append failed!\n");
146 return rc;
147 }
148
149 return sd_bus_send(NULL, n, NULL);
150}
151
Andrew Jeffery9c627172018-08-23 20:59:54 +0930152static int transport_dbus_get_flash_info(sd_bus_message *m, void *userdata,
153 sd_bus_error *ret_error)
154{
155 struct mbox_context *context = userdata;
156 struct protocol_get_flash_info io;
157 sd_bus_message *n;
158 int rc;
159
160 if (!context) {
161 MSG_ERR("DBUS Internal Error\n");
162 return -EINVAL;
163 }
164
165 rc = context->protocol->get_flash_info(context, &io);
166 if (rc < 0) {
167 return rc;
168 }
169
170 rc = sd_bus_message_new_method_return(m, &n);
171 if (rc < 0) {
172 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
173 return rc;
174 }
175
176 rc = sd_bus_message_append(n, "qq",
177 io.resp.v2.flash_size,
178 io.resp.v2.erase_size);
179 if (rc < 0) {
180 MSG_ERR("sd_bus_message_append failed!\n");
181 return rc;
182 }
183
184 return sd_bus_send(NULL, n, NULL);
185}
186
Andrew Jeffery0e785f42018-08-23 21:43:44 +0930187static int transport_dbus_create_window(struct mbox_context *context,
188 bool ro,
189 sd_bus_message *m,
190 sd_bus_error *ret_error)
Andrew Jefferyb9d72d02018-08-23 21:36:49 +0930191{
Andrew Jefferyb9d72d02018-08-23 21:36:49 +0930192 struct protocol_create_window io;
193 sd_bus_message *n;
194 int rc;
195
196 if (!context) {
197 MSG_ERR("DBUS Internal Error\n");
198 return -EINVAL;
199 }
200
201 rc = sd_bus_message_read(m, "qq", &io.req.offset, &io.req.size);
202 if (rc < 0) {
203 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
204 return rc;
205 }
206
Andrew Jeffery0e785f42018-08-23 21:43:44 +0930207 io.req.ro = ro;
Andrew Jefferyb9d72d02018-08-23 21:36:49 +0930208 rc = context->protocol->create_window(context, &io);
209 if (rc < 0) {
210 return rc;
211 }
212
213 rc = sd_bus_message_new_method_return(m, &n);
214 if (rc < 0) {
215 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
216 return rc;
217 }
218
219 rc = sd_bus_message_append(n, "qqq",
220 io.resp.lpc_address,
221 io.resp.size,
222 io.resp.offset);
223 if (rc < 0) {
224 MSG_ERR("sd_bus_message_append failed!\n");
225 return rc;
226 }
227
228 return sd_bus_send(NULL, n, NULL);
229}
230
Andrew Jeffery0e785f42018-08-23 21:43:44 +0930231static int transport_dbus_create_read_window(sd_bus_message *m, void *userdata,
232 sd_bus_error *ret_error)
233{
234 struct mbox_context *context = userdata;
235
236 return transport_dbus_create_window(context, true, m, ret_error);
237}
238
239static int transport_dbus_create_write_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, false, m, ret_error);
245}
246
Andrew Jefferyc2cbb3d2018-08-23 22:55:33 +0930247static int transport_dbus_close_window(sd_bus_message *m, void *userdata,
248 sd_bus_error *ret_error)
249{
250 struct mbox_context *context = userdata;
251 struct protocol_close io;
252 sd_bus_message *n;
253 int rc;
254
255 if (!context) {
256 MSG_ERR("DBUS Internal Error\n");
257 return -EINVAL;
258 }
259
260 rc = sd_bus_message_read(m, "y", &io.req.flags);
261 if (rc < 0) {
262 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
263 return rc;
264 }
265
266 rc = context->protocol->close(context, &io);
267 if (rc < 0) {
268 return rc;
269 }
270
271 rc = sd_bus_message_new_method_return(m, &n);
272 if (rc < 0) {
273 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
274 return rc;
275 }
276
277 return sd_bus_send(NULL, n, NULL);
278
279}
280
Andrew Jeffery40ef67b2018-08-24 07:14:25 +0930281static int transport_dbus_mark_dirty(sd_bus_message *m, void *userdata,
282 sd_bus_error *ret_error)
283{
284 struct mbox_context *context = userdata;
285 struct protocol_mark_dirty io;
286 sd_bus_message *n;
287 int rc;
288
289 if (!context) {
290 MSG_ERR("DBUS Internal Error\n");
291 return -EINVAL;
292 }
293
294 rc = sd_bus_message_read(m, "qq", &io.req.v2.offset, &io.req.v2.size);
295 if (rc < 0) {
296 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
297 return rc;
298 }
299
300 rc = context->protocol->mark_dirty(context, &io);
301 if (rc < 0) {
302 return rc;
303 }
304
305 rc = sd_bus_message_new_method_return(m, &n);
306 if (rc < 0) {
307 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
308 return rc;
309 }
310
311 return sd_bus_send(NULL, n, NULL);
312}
313
Andrew Jefferyd66af2a2018-08-24 08:28:13 +0930314static int transport_dbus_write_flush(sd_bus_message *m, void *userdata,
315 sd_bus_error *ret_error)
316{
317 struct mbox_context *context = userdata;
318 sd_bus_message *n;
319 int rc;
320
321 if (!context) {
322 MSG_ERR("DBUS Internal Error\n");
323 return -EINVAL;
324 }
325
326 rc = context->protocol->flush(context, NULL /* No args in v2 */);
327 if (rc < 0) {
328 return rc;
329 }
330
331 rc = sd_bus_message_new_method_return(m, &n);
332 if (rc < 0) {
333 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
334 return rc;
335 }
336
337 return sd_bus_send(NULL, n, NULL);
338}
339
Andrew Jefferybcc33992018-08-23 17:19:25 +0930340static int transport_dbus_ack(sd_bus_message *m, void *userdata,
341 sd_bus_error *ret_error)
342{
343 struct mbox_context *context = userdata;
344 struct protocol_ack io;
345 sd_bus_message *n;
346 int rc;
347
348 if (!context) {
349 MSG_ERR("DBUS Internal Error\n");
350 return -EINVAL;
351 }
352
353 rc = sd_bus_message_read_basic(m, 'y', &io.req.flags);
354 if (rc < 0) {
355 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
356 return rc;
357 }
358
359 rc = context->protocol->ack(context, &io);
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 Jefferyea5400f2018-08-24 09:36:44 +0930373static int transport_dbus_erase(sd_bus_message *m, void *userdata,
374 sd_bus_error *ret_error)
375{
376 struct mbox_context *context = userdata;
377 struct protocol_erase 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(m, "qq", &io.req.offset, &io.req.size);
387 if (rc < 0) {
388 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
389 return rc;
390 }
391
392 rc = context->protocol->erase(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 Jefferya6ca7a92018-08-20 13:03:44 +0930406static int transport_dbus_get_property(sd_bus *bus,
407 const char *path,
408 const char *interface,
409 const char *property,
410 sd_bus_message *reply,
411 void *userdata,
412 sd_bus_error *ret_error)
413{
414 struct mbox_context *context = userdata;
415 bool value;
416
417 assert(!strcmp(MBOX_DBUS_OBJECT, path));
418 assert(!strcmp(MBOX_DBUS_PROTOCOL_IFACE_V2, interface));
419
420 if (!strcmp("FlashControlLost", property)) {
421 value = context->bmc_events & BMC_EVENT_FLASH_CTRL_LOST;
422 } else if (!strcmp("DaemonReady", property)) {
423 value = context->bmc_events & BMC_EVENT_DAEMON_READY;
Andrew Jefferyfd4fa342018-11-23 08:33:37 +1100424 } else if (!strcmp("WindowReset", property)) {
425 value = context->bmc_events & BMC_EVENT_WINDOW_RESET;
426 } else if (!strcmp("ProtocolReset", property)) {
427 value = context->bmc_events & BMC_EVENT_PROTOCOL_RESET;
Andrew Jefferya6ca7a92018-08-20 13:03:44 +0930428 } else {
429 MSG_ERR("Unknown DBus property: %s\n", property);
430 return -EINVAL;
431 }
432
433 return sd_bus_message_append(reply, "b", value);
434}
435
Andrew Jeffery23140be2018-09-05 14:15:07 +0930436static const sd_bus_vtable protocol_unversioned_vtable[] = {
437 SD_BUS_VTABLE_START(0),
Andrew Jeffery7255d262018-08-23 16:53:48 +0930438 SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset,
439 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery23140be2018-09-05 14:15:07 +0930440 SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info,
441 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferybcc33992018-08-23 17:19:25 +0930442 SD_BUS_METHOD("Ack", "y", NULL, &transport_dbus_ack,
443 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery23140be2018-09-05 14:15:07 +0930444 SD_BUS_VTABLE_END
445};
446
447static const sd_bus_vtable protocol_v2_vtable[] = {
448 SD_BUS_VTABLE_START(0),
Andrew Jeffery7255d262018-08-23 16:53:48 +0930449 SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset,
450 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery23140be2018-09-05 14:15:07 +0930451 SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info,
452 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery9c627172018-08-23 20:59:54 +0930453 SD_BUS_METHOD("GetFlashInfo", NULL, "qq",
454 &transport_dbus_get_flash_info,
455 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferyb9d72d02018-08-23 21:36:49 +0930456 SD_BUS_METHOD("CreateReadWindow", "qq", "qqq",
457 &transport_dbus_create_read_window,
458 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery0e785f42018-08-23 21:43:44 +0930459 SD_BUS_METHOD("CreateWriteWindow", "qq", "qqq",
460 &transport_dbus_create_write_window,
461 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferyc2cbb3d2018-08-23 22:55:33 +0930462 SD_BUS_METHOD("CloseWindow", "y", NULL, &transport_dbus_close_window,
463 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jeffery40ef67b2018-08-24 07:14:25 +0930464 SD_BUS_METHOD("MarkDirty", "qq", NULL, &transport_dbus_mark_dirty,
465 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferyd66af2a2018-08-24 08:28:13 +0930466 SD_BUS_METHOD("Flush", NULL, NULL, &transport_dbus_write_flush,
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 Jefferyea5400f2018-08-24 09:36:44 +0930470 SD_BUS_METHOD("Erase", "qq", NULL, &transport_dbus_erase,
471 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferya6ca7a92018-08-20 13:03:44 +0930472 SD_BUS_PROPERTY("FlashControlLost", "b", transport_dbus_get_property,
473 0, /* Just a pointer to struct mbox_context */
474 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
475 SD_BUS_PROPERTY("DaemonReady", "b", transport_dbus_get_property,
476 0, /* Just a pointer to struct mbox_context */
477 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
Andrew Jefferyfd4fa342018-11-23 08:33:37 +1100478 SD_BUS_PROPERTY("ProtocolReset", "b",
479 transport_dbus_get_property,
480 0, /* Just a pointer to struct mbox_context */
481 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
482 SD_BUS_PROPERTY("WindowReset", "b",
483 transport_dbus_get_property,
484 0, /* Just a pointer to struct mbox_context */
485 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
Andrew Jeffery23140be2018-09-05 14:15:07 +0930486 SD_BUS_VTABLE_END
487};
488
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030489int transport_dbus_init(struct mbox_context *context,
490 const struct transport_ops **ops)
Andrew Jeffery23140be2018-09-05 14:15:07 +0930491{
492 int rc;
493
494 rc = sd_bus_add_object_vtable(context->bus, NULL,
495 MBOX_DBUS_OBJECT,
496 MBOX_DBUS_PROTOCOL_IFACE,
497 protocol_unversioned_vtable,
498 context);
499 if (rc < 0) {
500 return rc;
501 }
502
503 rc = sd_bus_add_object_vtable(context->bus, NULL,
504 MBOX_DBUS_OBJECT,
Andrew Jefferya6ca7a92018-08-20 13:03:44 +0930505 MBOX_DBUS_PROTOCOL_IFACE_V2,
Andrew Jeffery23140be2018-09-05 14:15:07 +0930506 protocol_v2_vtable, context);
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030507 if (rc < 0) {
508 return rc;
509 }
Andrew Jeffery23140be2018-09-05 14:15:07 +0930510
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030511 if (ops) {
512 *ops = &transport_dbus_ops;
513 }
514
515 return 0;
Andrew Jeffery23140be2018-09-05 14:15:07 +0930516}
517
518#define __unused __attribute__((unused))
519void transport_dbus_free(struct mbox_context *context __unused)
520{
521 return;
522}