blob: c1b78e3596183a1d9e19563742e01cc0da3538d4 [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
103static int transport_dbus_get_info(sd_bus_message *m, void *userdata,
104 sd_bus_error *ret_error)
105{
106 struct mbox_context *context = userdata;
107 struct protocol_get_info io;
108 sd_bus_message *n;
109 int rc;
110
111 if (!context) {
112 MSG_ERR("DBUS Internal Error\n");
113 return -EINVAL;
114 }
115
116 rc = sd_bus_message_read_basic(m, 'y', &io.req.api_version);
117 if (rc < 0) {
118 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
119 return rc;
120 }
121
122 rc = context->protocol->get_info(context, &io);
123 if (rc < 0) {
124 return rc;
125 }
126
Andrew Jeffery23a48212018-08-10 14:41:48 +0930127 /* Switch transport to DBus. This is fine as DBus signals are async */
128 context->transport = &transport_dbus_ops;
Andrew Jeffery0453aa42018-08-21 08:25:46 +0930129 /* A bit messy, but we need the correct event mask */
130 protocol_events_set(context, context->bmc_events);
Andrew Jeffery23a48212018-08-10 14:41:48 +0930131
Andrew Jeffery23140be2018-09-05 14:15:07 +0930132 rc = sd_bus_message_new_method_return(m, &n);
133 if (rc < 0) {
134 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
135 return rc;
136 }
137
138 if (API_VERSION_2 != io.resp.api_version) {
139 MSG_ERR("Unsupported protocol version for DBus transport: %d\n",
140 io.resp.api_version);
141 return rc;
142 }
143
144 rc = sd_bus_message_append(n, "yyq",
145 io.resp.api_version,
146 io.resp.v2.block_size_shift,
147 io.resp.v2.timeout);
148 if (rc < 0) {
149 MSG_ERR("sd_bus_message_append failed!\n");
150 return rc;
151 }
152
153 return sd_bus_send(NULL, n, NULL);
154}
155
Andrew Jefferya6ca7a92018-08-20 13:03:44 +0930156static int transport_dbus_get_property(sd_bus *bus,
157 const char *path,
158 const char *interface,
159 const char *property,
160 sd_bus_message *reply,
161 void *userdata,
162 sd_bus_error *ret_error)
163{
164 struct mbox_context *context = userdata;
165 bool value;
166
167 assert(!strcmp(MBOX_DBUS_OBJECT, path));
168 assert(!strcmp(MBOX_DBUS_PROTOCOL_IFACE_V2, interface));
169
170 if (!strcmp("FlashControlLost", property)) {
171 value = context->bmc_events & BMC_EVENT_FLASH_CTRL_LOST;
172 } else if (!strcmp("DaemonReady", property)) {
173 value = context->bmc_events & BMC_EVENT_DAEMON_READY;
174 } else {
175 MSG_ERR("Unknown DBus property: %s\n", property);
176 return -EINVAL;
177 }
178
179 return sd_bus_message_append(reply, "b", value);
180}
181
Andrew Jeffery23140be2018-09-05 14:15:07 +0930182static const sd_bus_vtable protocol_unversioned_vtable[] = {
183 SD_BUS_VTABLE_START(0),
184 SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info,
185 SD_BUS_VTABLE_UNPRIVILEGED),
186 SD_BUS_VTABLE_END
187};
188
189static const sd_bus_vtable protocol_v2_vtable[] = {
190 SD_BUS_VTABLE_START(0),
191 SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info,
192 SD_BUS_VTABLE_UNPRIVILEGED),
Andrew Jefferya6ca7a92018-08-20 13:03:44 +0930193 SD_BUS_PROPERTY("FlashControlLost", "b", transport_dbus_get_property,
194 0, /* Just a pointer to struct mbox_context */
195 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
196 SD_BUS_PROPERTY("DaemonReady", "b", transport_dbus_get_property,
197 0, /* Just a pointer to struct mbox_context */
198 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
199 SD_BUS_SIGNAL("ProtocolReset", NULL, 0),
200 SD_BUS_SIGNAL("WindowReset", NULL, 0),
Andrew Jeffery23140be2018-09-05 14:15:07 +0930201 SD_BUS_VTABLE_END
202};
203
204int transport_dbus_init(struct mbox_context *context)
205{
206 int rc;
207
208 rc = sd_bus_add_object_vtable(context->bus, NULL,
209 MBOX_DBUS_OBJECT,
210 MBOX_DBUS_PROTOCOL_IFACE,
211 protocol_unversioned_vtable,
212 context);
213 if (rc < 0) {
214 return rc;
215 }
216
217 rc = sd_bus_add_object_vtable(context->bus, NULL,
218 MBOX_DBUS_OBJECT,
Andrew Jefferya6ca7a92018-08-20 13:03:44 +0930219 MBOX_DBUS_PROTOCOL_IFACE_V2,
Andrew Jeffery23140be2018-09-05 14:15:07 +0930220 protocol_v2_vtable, context);
221
222 return rc;
223}
224
225#define __unused __attribute__((unused))
226void transport_dbus_free(struct mbox_context *context __unused)
227{
228 return;
229}