summaryrefslogtreecommitdiffstats
path: root/mboxd_dbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'mboxd_dbus.c')
-rw-r--r--mboxd_dbus.c372
1 files changed, 372 insertions, 0 deletions
diff --git a/mboxd_dbus.c b/mboxd_dbus.c
new file mode 100644
index 0000000..3b09bb1
--- /dev/null
+++ b/mboxd_dbus.c
@@ -0,0 +1,372 @@
+/*
+ * Mailbox Daemon DBUS Helpers
+ *
+ * Copyright 2016 IBM
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/timerfd.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <systemd/sd-bus.h>
+
+#include "mbox.h"
+#include "common.h"
+#include "dbus.h"
+#include "mboxd_dbus.h"
+#include "mboxd_windows.h"
+#include "mboxd_msg.h"
+#include "mboxd_lpc.h"
+#include "mboxd_flash.h"
+
+typedef int (*mboxd_dbus_handler)(struct mbox_context *, struct mbox_dbus_msg *,
+ struct mbox_dbus_msg *);
+
+/* DBUS Functions */
+
+/*
+ * Command: DBUS Ping
+ * Ping the daemon
+ *
+ * Args: NONE
+ * Resp: NONE
+ */
+static int dbus_handle_ping(struct mbox_context *context,
+ struct mbox_dbus_msg *req,
+ struct mbox_dbus_msg *resp)
+{
+ return 0;
+}
+
+/*
+ * Command: DBUS Status
+ * Get the status of the daemon
+ *
+ * Args: NONE
+ * Resp[0]: Status Code
+ */
+static int dbus_handle_daemon_state(struct mbox_context *context,
+ struct mbox_dbus_msg *req,
+ struct mbox_dbus_msg *resp)
+{
+ resp->num_args = DAEMON_STATE_NUM_ARGS;
+ resp->args = calloc(resp->num_args, sizeof(*resp->args));
+ resp->args[0] = (context->state & STATE_SUSPENDED) ?
+ DAEMON_STATE_SUSPENDED : DAEMON_STATE_ACTIVE;
+
+ return 0;
+}
+
+/*
+ * Command: DBUS LPC State
+ * Get the state of the lpc bus mapping (whether it points to memory or flash
+ *
+ * Args: NONE
+ * Resp[0]: LPC Bus State Code
+ */
+static int dbus_handle_lpc_state(struct mbox_context *context,
+ struct mbox_dbus_msg *req,
+ struct mbox_dbus_msg *resp)
+{
+ resp->num_args = LPC_STATE_NUM_ARGS;
+ resp->args = calloc(resp->num_args, sizeof(*resp->args));
+ if ((context->state & MAPS_MEM) && !(context->state & MAPS_FLASH)) {
+ resp->args[0] = LPC_STATE_MEM;
+ } else if (!(context->state & MAPS_MEM) &&
+ (context->state & MAPS_FLASH)) {
+ resp->args[0] = LPC_STATE_FLASH;
+ } else {
+ resp->args[0] = LPC_STATE_INVALID;
+ }
+
+ return 0;
+}
+
+/*
+ * Command: DBUS Reset
+ * Reset the daemon state, final operation TBA.
+ * For now we just point the lpc mapping back at the flash.
+ *
+ * Args: NONE
+ * Resp: NONE
+ */
+static int dbus_handle_reset(struct mbox_context *context,
+ struct mbox_dbus_msg *req,
+ struct mbox_dbus_msg *resp)
+{
+ int rc;
+
+ /* We don't let the host access flash if the daemon is suspened */
+ if (context->state & STATE_SUSPENDED) {
+ return -E_DBUS_REJECTED;
+ }
+
+ /*
+ * This will close (and flush) the current window and point the lpc bus
+ * mapping back to flash. Better set the bmc event to notify the host
+ * of this.
+ */
+ reset_all_windows(context, SET_BMC_EVENT);
+ rc = point_to_flash(context);
+ if (rc < 0) {
+ return -E_DBUS_HARDWARE;
+ }
+
+ return 0;
+}
+
+/*
+ * Command: DBUS Kill
+ * Stop the daemon
+ *
+ * Args: NONE
+ * Resp: NONE
+ */
+static int dbus_handle_kill(struct mbox_context *context,
+ struct mbox_dbus_msg *req,
+ struct mbox_dbus_msg *resp)
+{
+ context->terminate = 1;
+
+ MSG_OUT("DBUS Kill - Exiting...\n");
+
+ return 0;
+}
+
+/*
+ * Command: DBUS Flash Modified
+ * Used to notify the daemon that the flash has been modified out from under
+ * it - We need to reset all out windows to ensure flash will be reloaded
+ * when a new window is opened.
+ * Note: We don't flush any previously opened windows
+ *
+ * Args: NONE
+ * Resp: NONE
+ */
+static int dbus_handle_modified(struct mbox_context *context,
+ struct mbox_dbus_msg *req,
+ struct mbox_dbus_msg *resp)
+{
+ /* Flash has been modified - can no longer trust our erased bytemap */
+ set_flash_bytemap(context, 0, context->flash_size, FLASH_DIRTY);
+
+ /* Force daemon to reload all windows -> Set BMC event to notify host */
+ reset_all_windows(context, SET_BMC_EVENT);
+
+ return 0;
+}
+
+/*
+ * Command: DBUS Suspend
+ * Suspend the daemon to inhibit it from performing flash accesses.
+ * This is used to synchronise access to the flash between the daemon and
+ * directly from the BMC.
+ *
+ * Args: NONE
+ * Resp: NONE
+ */
+static int dbus_handle_suspend(struct mbox_context *context,
+ struct mbox_dbus_msg *req,
+ struct mbox_dbus_msg *resp)
+{
+ int rc;
+
+ if (context->state & STATE_SUSPENDED) {
+ /* Already Suspended */
+ return DBUS_SUCCESS;
+ }
+
+ /* Nothing to check - Just set the bit to notify the host */
+ rc = set_bmc_events(context, BMC_EVENT_FLASH_CTRL_LOST, SET_BMC_EVENT);
+ if (rc < 0) {
+ return -E_DBUS_HARDWARE;
+ }
+
+ context->state |= STATE_SUSPENDED;
+
+ return rc;
+}
+
+/*
+ * Command: DBUS Resume
+ * Resume the daemon to let it perform flash accesses again.
+ *
+ * Args[0]: Flash Modified (0 - no | 1 - yes)
+ * Resp: NONE
+ */
+static int dbus_handle_resume(struct mbox_context *context,
+ struct mbox_dbus_msg *req,
+ struct mbox_dbus_msg *resp)
+{
+ int rc;
+
+ if (req->num_args != 1) {
+ return -E_DBUS_INVAL;
+ }
+
+ if (!(context->state & STATE_SUSPENDED)) {
+ /* We weren't suspended... */
+ return DBUS_SUCCESS;
+ }
+
+ if (req->args[0] == RESUME_FLASH_MODIFIED) {
+ /* Clear the bit and call the flash modified handler */
+ clr_bmc_events(context, BMC_EVENT_FLASH_CTRL_LOST,
+ NO_BMC_EVENT);
+ rc = dbus_handle_modified(context, req, resp);
+ } else {
+ /* Flash wasn't modified - just clear the bit with writeback */
+ rc = clr_bmc_events(context, BMC_EVENT_FLASH_CTRL_LOST,
+ SET_BMC_EVENT);
+ }
+
+ if (rc < 0) {
+ rc = -E_DBUS_HARDWARE;
+ }
+ context->state &= ~STATE_SUSPENDED;
+
+ return rc;
+}
+
+static const mboxd_dbus_handler dbus_handlers[NUM_DBUS_CMDS] = {
+ dbus_handle_ping,
+ dbus_handle_daemon_state,
+ dbus_handle_reset,
+ dbus_handle_suspend,
+ dbus_handle_resume,
+ dbus_handle_modified,
+ dbus_handle_kill,
+ dbus_handle_lpc_state
+};
+
+static int method_cmd(sd_bus_message *m, void *userdata,
+ sd_bus_error *ret_error)
+{
+ struct mbox_dbus_msg req = { 0 }, resp = { 0 };
+ struct mbox_context *context;
+ sd_bus_message *n;
+ int rc;
+
+ context = (struct mbox_context *) userdata;
+ if (!context) {
+ MSG_ERR("DBUS Internal Error\n");
+ rc = -E_DBUS_INTERNAL;
+ goto out;
+ }
+
+ /* Read the command */
+ rc = sd_bus_message_read(m, "y", &req.cmd);
+ if (rc < 0) {
+ MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
+ rc = -E_DBUS_INTERNAL;
+ goto out;
+ }
+
+ /* Read the args */
+ rc = sd_bus_message_read_array(m, 'y', (const void **) &req.args,
+ &req.num_args);
+ if (rc < 0) {
+ MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
+ rc = -E_DBUS_INTERNAL;
+ goto out;
+ }
+
+ /* Handle the command */
+ if (req.cmd >= NUM_DBUS_CMDS) {
+ rc = -E_DBUS_INVAL;
+ MSG_ERR("Received unknown dbus cmd: %d\n", req.cmd);
+ } else {
+ rc = dbus_handlers[req.cmd](context, &req, &resp);
+ }
+
+out:
+ if (rc < 0) {
+ resp.cmd = -rc;
+ }
+ sd_bus_message_new_method_return(m, &n); /* Generate response */
+ sd_bus_message_append(n, "y", resp.cmd); /* Set return code */
+ sd_bus_message_append_array(n, 'y', resp.args, resp.num_args);
+ sd_bus_send(sd_bus_message_get_bus(m), n, NULL); /* Send response */
+ free(resp.args);
+ return 0;
+}
+
+static const sd_bus_vtable mboxd_vtable[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD("cmd", "yay", "yay", &method_cmd,
+ SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_VTABLE_END
+};
+
+int init_mboxd_dbus(struct mbox_context *context)
+{
+ int rc;
+
+ rc = sd_bus_default_system(&context->bus);
+ if (rc < 0) {
+ MSG_ERR("Failed to connect to the system bus: %s\n",
+ strerror(-rc));
+ return rc;
+ }
+
+ rc = sd_bus_add_object_vtable(context->bus, NULL, DOBJ_NAME, DBUS_NAME,
+ mboxd_vtable, context);
+ if (rc < 0) {
+ MSG_ERR("Failed to register vtable: %s\n", strerror(-rc));
+ return rc;
+ }
+
+ rc = sd_bus_request_name(context->bus, DBUS_NAME,
+ SD_BUS_NAME_ALLOW_REPLACEMENT |
+ SD_BUS_NAME_REPLACE_EXISTING);
+ if (rc < 0) {
+ MSG_ERR("Failed to acquire service name: %s\n", strerror(-rc));
+ return rc;
+ }
+
+ rc = sd_bus_get_fd(context->bus);
+ if (rc < 0) {
+ MSG_ERR("Failed to get bus fd: %s\n", strerror(-rc));
+ return rc;
+ }
+
+ context->fds[DBUS_FD].fd = rc;
+
+ return 0;
+}
+
+void free_mboxd_dbus(struct mbox_context *context)
+{
+ sd_bus_unref(context->bus);
+}
OpenPOWER on IntegriCloud