1 // SPDX-License-Identifier: Apache-2.0
2 // Copyright (C) 2018 IBM Corp.
3 #include <errno.h>
4 #include <stdlib.h>
5
6 #include "common.h"
7 #include "dbus.h"
8 #include "control_dbus.h"
9 #include "mboxd.h"
10
11 /* Command IDs (Legacy interface) */
12 #define DBUS_C_PING 0x00
13 #define DBUS_C_DAEMON_STATE 0x01
14 #define DBUS_C_RESET 0x02
15 #define DBUS_C_SUSPEND 0x03
16 #define DBUS_C_RESUME 0x04
17 #define DBUS_C_MODIFIED 0x05
18 #define DBUS_C_KILL 0x06
19 #define DBUS_C_LPC_STATE 0x07
20 #define NUM_DBUS_CMDS (DBUS_C_LPC_STATE + 1)
21
22 /* Return Values (Legacy interface) */
23 #define DBUS_SUCCESS 0x00 /* Command Succeded */
24 #define E_DBUS_INTERNAL 0x01 /* Internal DBUS Error */
25 #define E_DBUS_INVAL 0x02 /* Invalid Command */
26 #define E_DBUS_REJECTED 0x03 /* Daemon Rejected Request */
27 #define E_DBUS_HARDWARE 0x04 /* BMC Hardware Error */
28 #define E_DBUS_NO_MEM 0x05 /* Failed Memory Allocation */
29
30 struct mbox_dbus_msg {
31 uint8_t cmd;
32 size_t num_args;
33 uint8_t *args;
34 };
35
36 /*
37 * Command: DBUS Ping
38 * Ping the daemon
39 *
40 * Args: NONE
41 * Resp: NONE
42 */
control_legacy_ping(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)43 static int control_legacy_ping(struct mbox_context *context,
44 struct mbox_dbus_msg *req __attribute__((unused)),
45 struct mbox_dbus_msg *resp __attribute__((unused)))
46 {
47 return control_ping(context);
48 }
49
50 /*
51 * Command: DBUS Status
52 * Get the status of the daemon
53 *
54 * Args: NONE
55 * Resp[0]: Status Code
56 */
control_legacy_daemon_state(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)57 static int control_legacy_daemon_state(struct mbox_context *context,
58 struct mbox_dbus_msg *req __attribute__((unused)),
59 struct mbox_dbus_msg *resp)
60 {
61 resp->num_args = DAEMON_STATE_NUM_ARGS;
62 resp->args = calloc(resp->num_args, sizeof(*resp->args));
63 resp->args[0] = control_daemon_state(context);
64
65 return 0;
66 }
67
68 /*
69 * Command: DBUS LPC State
70 * Get the state of the lpc bus mapping (whether it points to memory or flash
71 *
72 * Args: NONE
73 * Resp[0]: LPC Bus State Code
74 */
control_legacy_lpc_state(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)75 static int control_legacy_lpc_state(struct mbox_context *context,
76 struct mbox_dbus_msg *req __attribute__((unused)),
77 struct mbox_dbus_msg *resp)
78 {
79
80 resp->num_args = LPC_STATE_NUM_ARGS;
81 resp->args = calloc(resp->num_args, sizeof(*resp->args));
82 resp->args[0] = control_lpc_state(context);
83
84 return 0;
85 }
86
87 /*
88 * Command: DBUS Reset
89 * Reset the daemon state, final operation TBA.
90 * For now we just point the lpc mapping back at the flash.
91 *
92 * Args: NONE
93 * Resp: NONE
94 */
control_legacy_reset(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)95 static int control_legacy_reset(struct mbox_context *context,
96 struct mbox_dbus_msg *req __attribute__((unused)),
97 struct mbox_dbus_msg *resp __attribute__((unused)))
98 {
99 int rc;
100
101 rc = control_reset(context);
102
103 /* Map return codes for compatibility */
104 if (rc == -EBUSY) {
105 return -E_DBUS_REJECTED;
106 } else if (rc < 0) {
107 return -E_DBUS_HARDWARE;
108 }
109
110 return rc;
111 }
112
113 /*
114 * Command: DBUS Kill
115 * Stop the daemon
116 *
117 * Args: NONE
118 * Resp: NONE
119 */
control_legacy_kill(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)120 static int control_legacy_kill(struct mbox_context *context,
121 struct mbox_dbus_msg *req __attribute__((unused)),
122 struct mbox_dbus_msg *resp __attribute__((unused)))
123 {
124 return control_kill(context);
125 }
126
127 /*
128 * Command: DBUS Flash Modified
129 * Used to notify the daemon that the flash has been modified out from under
130 * it - We need to reset all out windows to ensure flash will be reloaded
131 * when a new window is opened.
132 * Note: We don't flush any previously opened windows
133 *
134 * Args: NONE
135 * Resp: NONE
136 */
control_legacy_modified(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)137 static int control_legacy_modified(struct mbox_context *context,
138 struct mbox_dbus_msg *req __attribute__((unused)),
139 struct mbox_dbus_msg *resp __attribute__((unused)))
140 {
141 return control_modified(context);
142 }
143
144 /*
145 * Command: DBUS Suspend
146 * Suspend the daemon to inhibit it from performing flash accesses.
147 * This is used to synchronise access to the flash between the daemon and
148 * directly from the BMC.
149 *
150 * Args: NONE
151 * Resp: NONE
152 */
control_legacy_suspend(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)153 static int control_legacy_suspend(struct mbox_context *context,
154 struct mbox_dbus_msg *req __attribute__((unused)),
155 struct mbox_dbus_msg *resp __attribute__((unused)))
156 {
157 int rc;
158
159 rc = control_suspend(context);
160 if (rc < 0) {
161 /* Map return codes for compatibility */
162 return -E_DBUS_HARDWARE;
163 }
164
165 return rc;
166 }
167
168 /*
169 * Command: DBUS Resume
170 * Resume the daemon to let it perform flash accesses again.
171 *
172 * Args[0]: Flash Modified (0 - no | 1 - yes)
173 * Resp: NONE
174 */
control_legacy_resume(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)175 static int control_legacy_resume(struct mbox_context *context,
176 struct mbox_dbus_msg *req,
177 struct mbox_dbus_msg *resp __attribute__((unused)))
178 {
179 int rc;
180
181 if (req->num_args != 1) {
182 return -E_DBUS_INVAL;
183 }
184
185 rc = control_resume(context, req->args[0] == RESUME_FLASH_MODIFIED);
186 if (rc < 0) {
187 /* Map return codes for compatibility */
188 rc = -E_DBUS_HARDWARE;
189 }
190
191 return rc;
192 }
193
194 typedef int (*control_action)(struct mbox_context *context,
195 struct mbox_dbus_msg *req,
196 struct mbox_dbus_msg *resp);
197 static const control_action dbus_handlers[NUM_DBUS_CMDS] = {
198 control_legacy_ping,
199 control_legacy_daemon_state,
200 control_legacy_reset,
201 control_legacy_suspend,
202 control_legacy_resume,
203 control_legacy_modified,
204 control_legacy_kill,
205 control_legacy_lpc_state
206 };
207
method_cmd(sd_bus_message * m,void * userdata,sd_bus_error * ret_error)208 static int method_cmd(sd_bus_message *m, void *userdata,
209 sd_bus_error *ret_error __attribute__((unused)))
210 {
211 struct mbox_dbus_msg req = { 0 }, resp = { 0 };
212 struct mbox_context *context;
213 sd_bus_message *n;
214 int rc;
215 size_t i;
216
217 context = (struct mbox_context *) userdata;
218 if (!context) {
219 MSG_ERR("DBUS Internal Error\n");
220 rc = -E_DBUS_INTERNAL;
221 goto out;
222 }
223
224 /* Read the command */
225 rc = sd_bus_message_read(m, "y", &req.cmd);
226 if (rc < 0) {
227 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
228 rc = -E_DBUS_INTERNAL;
229 goto out;
230 }
231 MSG_DBG("DBUS request: %u\n", req.cmd);
232
233 /* Read the args */
234 rc = sd_bus_message_read_array(m, 'y', (const void **) &req.args,
235 &req.num_args);
236 if (rc < 0) {
237 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
238 rc = -E_DBUS_INTERNAL;
239 goto out;
240 }
241 MSG_DBG("DBUS num_args: %u\n", (unsigned) req.num_args);
242 for (i = 0; i < req.num_args; i++) {
243 MSG_DBG("DBUS arg[%zd]: %u\n", i, req.args[i]);
244 }
245
246 /* Handle the command */
247 if (req.cmd >= NUM_DBUS_CMDS) {
248 rc = -E_DBUS_INVAL;
249 MSG_ERR("Received unknown dbus cmd: %d\n", req.cmd);
250 } else {
251 rc = dbus_handlers[req.cmd](context, &req, &resp);
252 }
253
254 out:
255 if (rc < 0) {
256 resp.cmd = -rc;
257 }
258 rc = sd_bus_message_new_method_return(m, &n); /* Generate response */
259 if (rc < 0) {
260 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
261 goto cleanup;
262 }
263
264 rc = sd_bus_message_append(n, "y", resp.cmd); /* Set return code */
265 if (rc < 0) {
266 MSG_ERR("sd_bus_message_append failed: %d\n", rc);
267 goto cleanup;
268 }
269
270 rc = sd_bus_message_append_array(n, 'y', resp.args, resp.num_args);
271 if (rc < 0) {
272 MSG_ERR("sd_bus_message_append_array failed: %d\n", rc);
273 goto cleanup;
274 }
275
276 MSG_DBG("DBUS response: %u\n", resp.cmd);
277 MSG_DBG("DBUS num_args: %u\n", (unsigned) resp.num_args);
278 for (i = 0; i < resp.num_args; i++) {
279 MSG_DBG("DBUS arg[%zd]: %u\n", i, resp.args[i]);
280 }
281
282 rc = sd_bus_send(NULL, n, NULL); /* Send response */
283 sd_bus_message_unref(n);
284 if (rc < 0)
285 MSG_ERR("sd_bus_send failed: %d\n", rc);
286
287 cleanup:
288 free(resp.args);
289 return rc;
290 }
291
292 static const sd_bus_vtable control_legacy_vtable[] = {
293 SD_BUS_VTABLE_START(0),
294 SD_BUS_METHOD("cmd", "yay", "yay", &method_cmd,
295 SD_BUS_VTABLE_UNPRIVILEGED),
296 SD_BUS_VTABLE_END
297 };
298
control_legacy_init(struct mbox_context * context)299 int control_legacy_init(struct mbox_context *context)
300 {
301 int rc;
302
303 rc = sd_bus_add_object_vtable(context->bus, NULL,
304 MBOX_DBUS_LEGACY_OBJECT,
305 MBOX_DBUS_LEGACY_NAME,
306 control_legacy_vtable, context);
307 if (rc < 0) {
308 MSG_ERR("Failed to register vtable: %s\n", strerror(-rc));
309 return rc;
310 }
311
312 return sd_bus_request_name(context->bus, MBOX_DBUS_LEGACY_NAME,
313 SD_BUS_NAME_ALLOW_REPLACEMENT |
314 SD_BUS_NAME_REPLACE_EXISTING);
315 }
316
control_legacy_free(struct mbox_context * context)317 void control_legacy_free(struct mbox_context *context __attribute__((unused)))
318 {
319 return;
320 }
321