blob: 6673ca64e067585deeb45c89db5fb7eb6313f410 [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) {
244 /* Clear the bit and call the flash modified handler */
245 clr_bmc_events(context, BMC_EVENT_FLASH_CTRL_LOST,
246 NO_BMC_EVENT);
247 rc = dbus_handle_modified(context, req, resp);
248 } else {
249 /* Flash wasn't modified - just clear the bit with writeback */
250 rc = clr_bmc_events(context, BMC_EVENT_FLASH_CTRL_LOST,
251 SET_BMC_EVENT);
252 }
253
254 if (rc < 0) {
255 rc = -E_DBUS_HARDWARE;
256 }
257 context->state &= ~STATE_SUSPENDED;
258
259 return rc;
260}
261
262static const mboxd_dbus_handler dbus_handlers[NUM_DBUS_CMDS] = {
263 dbus_handle_ping,
264 dbus_handle_daemon_state,
265 dbus_handle_reset,
266 dbus_handle_suspend,
267 dbus_handle_resume,
268 dbus_handle_modified,
269 dbus_handle_kill,
270 dbus_handle_lpc_state
271};
272
273static int method_cmd(sd_bus_message *m, void *userdata,
274 sd_bus_error *ret_error)
275{
276 struct mbox_dbus_msg req = { 0 }, resp = { 0 };
277 struct mbox_context *context;
278 sd_bus_message *n;
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000279 int rc, i;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100280
281 context = (struct mbox_context *) userdata;
282 if (!context) {
283 MSG_ERR("DBUS Internal Error\n");
284 rc = -E_DBUS_INTERNAL;
285 goto out;
286 }
287
288 /* Read the command */
289 rc = sd_bus_message_read(m, "y", &req.cmd);
290 if (rc < 0) {
291 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
292 rc = -E_DBUS_INTERNAL;
293 goto out;
294 }
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000295 MSG_DBG("DBUS request: %u\n", req.cmd);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100296
297 /* Read the args */
298 rc = sd_bus_message_read_array(m, 'y', (const void **) &req.args,
299 &req.num_args);
300 if (rc < 0) {
301 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
302 rc = -E_DBUS_INTERNAL;
303 goto out;
304 }
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000305 MSG_DBG("DBUS num_args: %u\n", (unsigned) req.num_args);
306 for (i = 0; i < req.num_args; i++) {
307 MSG_DBG("DBUS arg[%d]: %u\n", i, req.args[i]);
308 }
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100309
310 /* Handle the command */
311 if (req.cmd >= NUM_DBUS_CMDS) {
312 rc = -E_DBUS_INVAL;
313 MSG_ERR("Received unknown dbus cmd: %d\n", req.cmd);
314 } else {
315 rc = dbus_handlers[req.cmd](context, &req, &resp);
316 }
317
318out:
319 if (rc < 0) {
320 resp.cmd = -rc;
321 }
Andrew Jefferyded91bc2017-04-19 13:44:15 +0930322 rc = sd_bus_message_new_method_return(m, &n); /* Generate response */
323 if (rc < 0) {
324 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
325 goto cleanup;
326 }
327
328 rc = sd_bus_message_append(n, "y", resp.cmd); /* Set return code */
329 if (rc < 0) {
330 MSG_ERR("sd_bus_message_append failed: %d\n", rc);
331 goto cleanup;
332 }
333
334 rc = sd_bus_message_append_array(n, 'y', resp.args, resp.num_args);
335 if (rc < 0) {
336 MSG_ERR("sd_bus_message_append_array failed: %d\n", rc);
337 goto cleanup;
338 }
339
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000340 MSG_DBG("DBUS response: %u\n", resp.cmd);
341 MSG_DBG("DBUS num_args: %u\n", (unsigned) resp.num_args);
342 for (i = 0; i < resp.num_args; i++) {
343 MSG_DBG("DBUS arg[%d]: %u\n", i, resp.args[i]);
344 }
345
Andrew Jefferyded91bc2017-04-19 13:44:15 +0930346 rc = sd_bus_send(NULL, n, NULL); /* Send response */
347 if (rc < 0)
348 MSG_ERR("sd_bus_send failed: %d\n", rc);
349
350cleanup:
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100351 free(resp.args);
Andrew Jefferyded91bc2017-04-19 13:44:15 +0930352 return rc;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100353}
354
355static const sd_bus_vtable mboxd_vtable[] = {
356 SD_BUS_VTABLE_START(0),
357 SD_BUS_METHOD("cmd", "yay", "yay", &method_cmd,
358 SD_BUS_VTABLE_UNPRIVILEGED),
359 SD_BUS_VTABLE_END
360};
361
362int init_mboxd_dbus(struct mbox_context *context)
363{
364 int rc;
365
366 rc = sd_bus_default_system(&context->bus);
367 if (rc < 0) {
368 MSG_ERR("Failed to connect to the system bus: %s\n",
369 strerror(-rc));
370 return rc;
371 }
372
373 rc = sd_bus_add_object_vtable(context->bus, NULL, DOBJ_NAME, DBUS_NAME,
374 mboxd_vtable, context);
375 if (rc < 0) {
376 MSG_ERR("Failed to register vtable: %s\n", strerror(-rc));
377 return rc;
378 }
379
380 rc = sd_bus_request_name(context->bus, DBUS_NAME,
381 SD_BUS_NAME_ALLOW_REPLACEMENT |
382 SD_BUS_NAME_REPLACE_EXISTING);
383 if (rc < 0) {
384 MSG_ERR("Failed to acquire service name: %s\n", strerror(-rc));
385 return rc;
386 }
387
388 rc = sd_bus_get_fd(context->bus);
389 if (rc < 0) {
390 MSG_ERR("Failed to get bus fd: %s\n", strerror(-rc));
391 return rc;
392 }
393
394 context->fds[DBUS_FD].fd = rc;
395
396 return 0;
397}
398
399void free_mboxd_dbus(struct mbox_context *context)
400{
401 sd_bus_unref(context->bus);
402}