blob: 6493ccf3928947d9320a1277ef3a257b45b3bb6b [file] [log] [blame]
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +11001/*
2 * Mailbox Daemon DBUS Helpers
3 *
4 * Copyright 2016 IBM
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20#define _GNU_SOURCE
21#include <assert.h>
22#include <errno.h>
23#include <fcntl.h>
24#include <getopt.h>
25#include <limits.h>
26#include <poll.h>
27#include <stdbool.h>
28#include <stdint.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <syslog.h>
33#include <signal.h>
34#include <sys/ioctl.h>
35#include <sys/mman.h>
36#include <sys/stat.h>
37#include <sys/timerfd.h>
38#include <sys/types.h>
39#include <time.h>
40#include <unistd.h>
41#include <inttypes.h>
42#include <systemd/sd-bus.h>
43
44#include "mbox.h"
45#include "common.h"
46#include "dbus.h"
47#include "mboxd_dbus.h"
48#include "mboxd_windows.h"
49#include "mboxd_msg.h"
50#include "mboxd_lpc.h"
51#include "mboxd_flash.h"
52
53typedef int (*mboxd_dbus_handler)(struct mbox_context *, struct mbox_dbus_msg *,
54 struct mbox_dbus_msg *);
55
56/* DBUS Functions */
57
58/*
59 * Command: DBUS Ping
60 * Ping the daemon
61 *
62 * Args: NONE
63 * Resp: NONE
64 */
65static int dbus_handle_ping(struct mbox_context *context,
66 struct mbox_dbus_msg *req,
67 struct mbox_dbus_msg *resp)
68{
69 return 0;
70}
71
72/*
73 * Command: DBUS Status
74 * Get the status of the daemon
75 *
76 * Args: NONE
77 * Resp[0]: Status Code
78 */
79static int dbus_handle_daemon_state(struct mbox_context *context,
80 struct mbox_dbus_msg *req,
81 struct mbox_dbus_msg *resp)
82{
83 resp->num_args = DAEMON_STATE_NUM_ARGS;
84 resp->args = calloc(resp->num_args, sizeof(*resp->args));
85 resp->args[0] = (context->state & STATE_SUSPENDED) ?
86 DAEMON_STATE_SUSPENDED : DAEMON_STATE_ACTIVE;
87
88 return 0;
89}
90
91/*
92 * Command: DBUS LPC State
93 * Get the state of the lpc bus mapping (whether it points to memory or flash
94 *
95 * Args: NONE
96 * Resp[0]: LPC Bus State Code
97 */
98static int dbus_handle_lpc_state(struct mbox_context *context,
99 struct mbox_dbus_msg *req,
100 struct mbox_dbus_msg *resp)
101{
102 resp->num_args = LPC_STATE_NUM_ARGS;
103 resp->args = calloc(resp->num_args, sizeof(*resp->args));
104 if ((context->state & MAPS_MEM) && !(context->state & MAPS_FLASH)) {
105 resp->args[0] = LPC_STATE_MEM;
106 } else if (!(context->state & MAPS_MEM) &&
107 (context->state & MAPS_FLASH)) {
108 resp->args[0] = LPC_STATE_FLASH;
109 } else {
110 resp->args[0] = LPC_STATE_INVALID;
111 }
112
113 return 0;
114}
115
116/*
117 * Command: DBUS Reset
118 * Reset the daemon state, final operation TBA.
119 * For now we just point the lpc mapping back at the flash.
120 *
121 * Args: NONE
122 * Resp: NONE
123 */
124static int dbus_handle_reset(struct mbox_context *context,
125 struct mbox_dbus_msg *req,
126 struct mbox_dbus_msg *resp)
127{
128 int rc;
129
130 /* We don't let the host access flash if the daemon is suspened */
131 if (context->state & STATE_SUSPENDED) {
132 return -E_DBUS_REJECTED;
133 }
134
135 /*
136 * This will close (and flush) the current window and point the lpc bus
137 * mapping back to flash. Better set the bmc event to notify the host
138 * of this.
139 */
140 reset_all_windows(context, SET_BMC_EVENT);
141 rc = point_to_flash(context);
142 if (rc < 0) {
143 return -E_DBUS_HARDWARE;
144 }
145
146 return 0;
147}
148
149/*
150 * Command: DBUS Kill
151 * Stop the daemon
152 *
153 * Args: NONE
154 * Resp: NONE
155 */
156static int dbus_handle_kill(struct mbox_context *context,
157 struct mbox_dbus_msg *req,
158 struct mbox_dbus_msg *resp)
159{
160 context->terminate = 1;
161
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000162 MSG_INFO("DBUS Kill - Exiting...\n");
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100163
164 return 0;
165}
166
167/*
168 * Command: DBUS Flash Modified
169 * Used to notify the daemon that the flash has been modified out from under
170 * it - We need to reset all out windows to ensure flash will be reloaded
171 * when a new window is opened.
172 * Note: We don't flush any previously opened windows
173 *
174 * Args: NONE
175 * Resp: NONE
176 */
177static int dbus_handle_modified(struct mbox_context *context,
178 struct mbox_dbus_msg *req,
179 struct mbox_dbus_msg *resp)
180{
181 /* Flash has been modified - can no longer trust our erased bytemap */
182 set_flash_bytemap(context, 0, context->flash_size, FLASH_DIRTY);
183
184 /* Force daemon to reload all windows -> Set BMC event to notify host */
185 reset_all_windows(context, SET_BMC_EVENT);
186
187 return 0;
188}
189
190/*
191 * Command: DBUS Suspend
192 * Suspend the daemon to inhibit it from performing flash accesses.
193 * This is used to synchronise access to the flash between the daemon and
194 * directly from the BMC.
195 *
196 * Args: NONE
197 * Resp: NONE
198 */
199static int dbus_handle_suspend(struct mbox_context *context,
200 struct mbox_dbus_msg *req,
201 struct mbox_dbus_msg *resp)
202{
203 int rc;
204
205 if (context->state & STATE_SUSPENDED) {
206 /* Already Suspended */
207 return DBUS_SUCCESS;
208 }
209
210 /* Nothing to check - Just set the bit to notify the host */
211 rc = set_bmc_events(context, BMC_EVENT_FLASH_CTRL_LOST, SET_BMC_EVENT);
212 if (rc < 0) {
213 return -E_DBUS_HARDWARE;
214 }
215
216 context->state |= STATE_SUSPENDED;
217
218 return rc;
219}
220
221/*
222 * Command: DBUS Resume
223 * Resume the daemon to let it perform flash accesses again.
224 *
225 * Args[0]: Flash Modified (0 - no | 1 - yes)
226 * Resp: NONE
227 */
228static int dbus_handle_resume(struct mbox_context *context,
229 struct mbox_dbus_msg *req,
230 struct mbox_dbus_msg *resp)
231{
232 int rc;
233
234 if (req->num_args != 1) {
235 return -E_DBUS_INVAL;
236 }
237
238 if (!(context->state & STATE_SUSPENDED)) {
239 /* We weren't suspended... */
240 return DBUS_SUCCESS;
241 }
242
243 if (req->args[0] == RESUME_FLASH_MODIFIED) {
Suraj Jitindar Singh7760fd82017-09-20 18:03:35 +1000244 /* Call the flash modified handler */
245 dbus_handle_modified(context, req, resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100246 }
247
Suraj Jitindar Singh7760fd82017-09-20 18:03:35 +1000248 /* Clear the bit and send the BMC Event to the host */
249 rc = clr_bmc_events(context, BMC_EVENT_FLASH_CTRL_LOST, SET_BMC_EVENT);
250
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100251 if (rc < 0) {
252 rc = -E_DBUS_HARDWARE;
253 }
254 context->state &= ~STATE_SUSPENDED;
255
256 return rc;
257}
258
259static const mboxd_dbus_handler dbus_handlers[NUM_DBUS_CMDS] = {
260 dbus_handle_ping,
261 dbus_handle_daemon_state,
262 dbus_handle_reset,
263 dbus_handle_suspend,
264 dbus_handle_resume,
265 dbus_handle_modified,
266 dbus_handle_kill,
267 dbus_handle_lpc_state
268};
269
270static int method_cmd(sd_bus_message *m, void *userdata,
271 sd_bus_error *ret_error)
272{
273 struct mbox_dbus_msg req = { 0 }, resp = { 0 };
274 struct mbox_context *context;
275 sd_bus_message *n;
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000276 int rc, i;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100277
278 context = (struct mbox_context *) userdata;
279 if (!context) {
280 MSG_ERR("DBUS Internal Error\n");
281 rc = -E_DBUS_INTERNAL;
282 goto out;
283 }
284
285 /* Read the command */
286 rc = sd_bus_message_read(m, "y", &req.cmd);
287 if (rc < 0) {
288 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
289 rc = -E_DBUS_INTERNAL;
290 goto out;
291 }
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000292 MSG_DBG("DBUS request: %u\n", req.cmd);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100293
294 /* Read the args */
295 rc = sd_bus_message_read_array(m, 'y', (const void **) &req.args,
296 &req.num_args);
297 if (rc < 0) {
298 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
299 rc = -E_DBUS_INTERNAL;
300 goto out;
301 }
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000302 MSG_DBG("DBUS num_args: %u\n", (unsigned) req.num_args);
303 for (i = 0; i < req.num_args; i++) {
304 MSG_DBG("DBUS arg[%d]: %u\n", i, req.args[i]);
305 }
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100306
307 /* Handle the command */
308 if (req.cmd >= NUM_DBUS_CMDS) {
309 rc = -E_DBUS_INVAL;
310 MSG_ERR("Received unknown dbus cmd: %d\n", req.cmd);
311 } else {
312 rc = dbus_handlers[req.cmd](context, &req, &resp);
313 }
314
315out:
316 if (rc < 0) {
317 resp.cmd = -rc;
318 }
Andrew Jefferyded91bc2017-04-19 13:44:15 +0930319 rc = sd_bus_message_new_method_return(m, &n); /* Generate response */
320 if (rc < 0) {
321 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
322 goto cleanup;
323 }
324
325 rc = sd_bus_message_append(n, "y", resp.cmd); /* Set return code */
326 if (rc < 0) {
327 MSG_ERR("sd_bus_message_append failed: %d\n", rc);
328 goto cleanup;
329 }
330
331 rc = sd_bus_message_append_array(n, 'y', resp.args, resp.num_args);
332 if (rc < 0) {
333 MSG_ERR("sd_bus_message_append_array failed: %d\n", rc);
334 goto cleanup;
335 }
336
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000337 MSG_DBG("DBUS response: %u\n", resp.cmd);
338 MSG_DBG("DBUS num_args: %u\n", (unsigned) resp.num_args);
339 for (i = 0; i < resp.num_args; i++) {
340 MSG_DBG("DBUS arg[%d]: %u\n", i, resp.args[i]);
341 }
342
Andrew Jefferyded91bc2017-04-19 13:44:15 +0930343 rc = sd_bus_send(NULL, n, NULL); /* Send response */
344 if (rc < 0)
345 MSG_ERR("sd_bus_send failed: %d\n", rc);
346
347cleanup:
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100348 free(resp.args);
Andrew Jefferyded91bc2017-04-19 13:44:15 +0930349 return rc;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100350}
351
352static const sd_bus_vtable mboxd_vtable[] = {
353 SD_BUS_VTABLE_START(0),
354 SD_BUS_METHOD("cmd", "yay", "yay", &method_cmd,
355 SD_BUS_VTABLE_UNPRIVILEGED),
356 SD_BUS_VTABLE_END
357};
358
359int init_mboxd_dbus(struct mbox_context *context)
360{
361 int rc;
362
363 rc = sd_bus_default_system(&context->bus);
364 if (rc < 0) {
365 MSG_ERR("Failed to connect to the system bus: %s\n",
366 strerror(-rc));
367 return rc;
368 }
369
370 rc = sd_bus_add_object_vtable(context->bus, NULL, DOBJ_NAME, DBUS_NAME,
371 mboxd_vtable, context);
372 if (rc < 0) {
373 MSG_ERR("Failed to register vtable: %s\n", strerror(-rc));
374 return rc;
375 }
376
377 rc = sd_bus_request_name(context->bus, DBUS_NAME,
378 SD_BUS_NAME_ALLOW_REPLACEMENT |
379 SD_BUS_NAME_REPLACE_EXISTING);
380 if (rc < 0) {
381 MSG_ERR("Failed to acquire service name: %s\n", strerror(-rc));
382 return rc;
383 }
384
385 rc = sd_bus_get_fd(context->bus);
386 if (rc < 0) {
387 MSG_ERR("Failed to get bus fd: %s\n", strerror(-rc));
388 return rc;
389 }
390
391 context->fds[DBUS_FD].fd = rc;
392
393 return 0;
394}
395
396void free_mboxd_dbus(struct mbox_context *context)
397{
398 sd_bus_unref(context->bus);
399}