dbus: Mark current command set as legacy

Change-Id: I1b5d1c9262ea6ae0a9ff77c902b6941943085cd1
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
diff --git a/Makefile.am b/Makefile.am
index a36fb27..fb5997a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,6 +4,8 @@
 mboxd_SOURCES = \
 	mboxd.c \
 	common.c \
+	control.c \
+	control_legacy.c \
 	mboxd_dbus.c \
 	mboxd_lpc.c \
 	mboxd_msg.c \
diff --git a/control.c b/control.c
new file mode 100644
index 0000000..8c122ac
--- /dev/null
+++ b/control.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+#include <errno.h>
+#include <stdlib.h>
+
+#include "dbus.h"
+#include "mbox.h"
+#include "mboxd_flash.h"
+#include "mboxd_lpc.h"
+#include "mboxd_msg.h"
+#include "mboxd_windows.h"
+
+int control_ping(struct mbox_context *context)
+{
+	return 0;
+}
+
+int control_daemon_state(struct mbox_context *context)
+{
+	return (context->state & STATE_SUSPENDED) ?
+		DAEMON_STATE_SUSPENDED : DAEMON_STATE_ACTIVE;
+}
+
+int control_lpc_state(struct mbox_context *context)
+{
+	if ((context->state & MAPS_MEM) && !(context->state & MAPS_FLASH)) {
+		return LPC_STATE_MEM;
+	} else if (!(context->state & MAPS_MEM) &&
+		   (context->state & MAPS_FLASH)) {
+		return LPC_STATE_FLASH;
+	}
+
+	return LPC_STATE_INVALID;
+}
+
+int control_reset(struct mbox_context *context)
+{
+	int rc;
+
+	/* We don't let the host access flash if the daemon is suspened */
+	if (context->state & STATE_SUSPENDED) {
+		return -EBUSY;
+	}
+
+	/*
+	 * This will close (and flush) the current window and reset the lpc bus
+	 * mapping back to flash, or memory in case we're using a virtual pnor.
+	 * Better set the bmc event to notify the host of this.
+	 */
+	reset_all_windows(context, SET_BMC_EVENT);
+	rc = reset_lpc(context);
+	if (rc < 0) {
+		return rc;
+	}
+
+	return 0;
+}
+
+int control_kill(struct mbox_context *context)
+{
+	context->terminate = 1;
+
+	MSG_INFO("DBUS Kill - Exiting...\n");
+
+	return 0;
+}
+
+int control_modified(struct mbox_context *context)
+{
+	/* 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;
+}
+
+int control_suspend(struct mbox_context *context)
+{
+	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 rc;
+	}
+
+	context->state |= STATE_SUSPENDED;
+
+	return rc;
+}
+
+int control_resume(struct mbox_context *context, bool modified)
+{
+	int rc;
+
+	if (!(context->state & STATE_SUSPENDED)) {
+		/* We weren't suspended... */
+		return DBUS_SUCCESS;
+	}
+
+	if (modified) {
+		/* Call the flash modified handler */
+		control_modified(context);
+	}
+
+	/* Clear the bit and send the BMC Event to the host */
+	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;
+}
diff --git a/control_legacy.c b/control_legacy.c
new file mode 100644
index 0000000..d0e1e1f
--- /dev/null
+++ b/control_legacy.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+#include <errno.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "dbus.h"
+#include "mboxd_dbus.h"
+#include "mbox.h"
+
+/*
+ * Command: DBUS Ping
+ * Ping the daemon
+ *
+ * Args: NONE
+ * Resp: NONE
+ */
+static int control_legacy_ping(struct mbox_context *context,
+			   struct mbox_dbus_msg *req,
+			   struct mbox_dbus_msg *resp)
+{
+	return control_ping(context);
+}
+
+/*
+ * Command: DBUS Status
+ * Get the status of the daemon
+ *
+ * Args: NONE
+ * Resp[0]: Status Code
+ */
+static int control_legacy_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] = control_daemon_state(context);
+
+	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 control_legacy_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));
+	resp->args[0] = control_lpc_state(context);
+
+	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 control_legacy_reset(struct mbox_context *context,
+				   struct mbox_dbus_msg *req,
+				   struct mbox_dbus_msg *resp)
+{
+	int rc;
+
+	rc = control_reset(context);
+
+	/* Map return codes for compatibility */
+	if (rc == -EBUSY) {
+		return -E_DBUS_REJECTED;
+	} else if (rc < 0) {
+		return -E_DBUS_HARDWARE;
+	}
+
+	return rc;
+}
+
+/*
+ * Command: DBUS Kill
+ * Stop the daemon
+ *
+ * Args: NONE
+ * Resp: NONE
+ */
+static int control_legacy_kill(struct mbox_context *context,
+				  struct mbox_dbus_msg *req,
+				  struct mbox_dbus_msg *resp)
+{
+	return control_kill(context);
+}
+
+/*
+ * 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 control_legacy_modified(struct mbox_context *context,
+				      struct mbox_dbus_msg *req,
+				      struct mbox_dbus_msg *resp)
+{
+	return control_modified(context);
+}
+
+/*
+ * 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 control_legacy_suspend(struct mbox_context *context,
+				     struct mbox_dbus_msg *req,
+				     struct mbox_dbus_msg *resp)
+{
+	int rc;
+
+	rc = control_suspend(context);
+	if (rc < 0) {
+		/* Map return codes for compatibility */
+		return -E_DBUS_HARDWARE;
+	}
+
+	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 control_legacy_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;
+	}
+
+	rc = control_resume(context, req->args[0] == RESUME_FLASH_MODIFIED);
+	if (rc < 0) {
+		/* Map return codes for compatibility */
+		rc = -E_DBUS_HARDWARE;
+	}
+
+	return rc;
+}
+
+typedef int (*control_action)(struct mbox_context *context,
+				 struct mbox_dbus_msg *req,
+				 struct mbox_dbus_msg *resp);
+static const control_action dbus_handlers[NUM_DBUS_CMDS] = {
+	control_legacy_ping,
+	control_legacy_daemon_state,
+	control_legacy_reset,
+	control_legacy_suspend,
+	control_legacy_resume,
+	control_legacy_modified,
+	control_legacy_kill,
+	control_legacy_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, i;
+
+	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;
+	}
+	MSG_DBG("DBUS request: %u\n", req.cmd);
+
+	/* 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;
+	}
+	MSG_DBG("DBUS num_args: %u\n", (unsigned) req.num_args);
+	for (i = 0; i < req.num_args; i++) {
+		MSG_DBG("DBUS arg[%d]: %u\n", i, req.args[i]);
+	}
+
+	/* 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;
+	}
+	rc = sd_bus_message_new_method_return(m, &n); /* Generate response */
+	if (rc < 0) {
+		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
+		goto cleanup;
+	}
+
+	rc = sd_bus_message_append(n, "y", resp.cmd); /* Set return code */
+	if (rc < 0) {
+		MSG_ERR("sd_bus_message_append failed: %d\n", rc);
+		goto cleanup;
+	}
+
+	rc = sd_bus_message_append_array(n, 'y', resp.args, resp.num_args);
+	if (rc < 0) {
+		MSG_ERR("sd_bus_message_append_array failed: %d\n", rc);
+		goto cleanup;
+	}
+
+	MSG_DBG("DBUS response: %u\n", resp.cmd);
+	MSG_DBG("DBUS num_args: %u\n", (unsigned) resp.num_args);
+	for (i = 0; i < resp.num_args; i++) {
+		MSG_DBG("DBUS arg[%d]: %u\n", i, resp.args[i]);
+	}
+
+	rc = sd_bus_send(NULL, n, NULL); /* Send response */
+	if (rc < 0)
+		MSG_ERR("sd_bus_send failed: %d\n", rc);
+
+cleanup:
+	free(resp.args);
+	return rc;
+}
+
+static const sd_bus_vtable control_legacy_vtable[] = {
+	SD_BUS_VTABLE_START(0),
+	SD_BUS_METHOD("cmd", "yay", "yay", &method_cmd,
+		      SD_BUS_VTABLE_UNPRIVILEGED),
+	SD_BUS_VTABLE_END
+};
+
+int control_legacy_init(struct mbox_context *context)
+{
+	int rc;
+
+	rc = sd_bus_add_object_vtable(context->bus, NULL,
+				      MBOX_DBUS_LEGACY_OBJECT,
+				      MBOX_DBUS_LEGACY_NAME,
+				      control_legacy_vtable, context);
+	if (rc < 0) {
+		MSG_ERR("Failed to register vtable: %s\n", strerror(-rc));
+		return rc;
+	}
+
+	return sd_bus_request_name(context->bus, MBOX_DBUS_LEGACY_NAME,
+				 SD_BUS_NAME_ALLOW_REPLACEMENT |
+				 SD_BUS_NAME_REPLACE_EXISTING);
+}
+
+void control_legacy_free(struct mbox_context *context __attribute__((unused)))
+{
+	return;
+}
diff --git a/dbus.h b/dbus.h
index 0be0240..df31ca3 100644
--- a/dbus.h
+++ b/dbus.h
@@ -4,10 +4,27 @@
 #ifndef MBOX_DBUS_H
 #define MBOX_DBUS_H
 
-#define DBUS_NAME		"org.openbmc.mboxd"
-#define DOBJ_NAME		"/org/openbmc/mboxd"
+#include <stdint.h>
+#include <stddef.h>
 
-/* Commands */
+/*
+ * "mbox" will become an inappropriate name for the protocol/daemon, so claim a
+ * different name on the public interface.
+ *
+ * "hiomapd" expands to "Host I/O Map Daemon"
+ *
+ * TODO: The Great Rename
+ */
+#define MBOX_DBUS_NAME			"xyz.openbmc_project.Hiomapd"
+#define MBOX_DBUS_OBJECT		"/xyz/openbmc_project/Hiomapd"
+#define MBOX_DBUS_CONTROL_IFACE		"xyz.openbmc_project.Hiomapd.Control"
+#define MBOX_DBUS_PROTOCOL_IFACE	"xyz.openbmc_project.Hiomapd.Protocol"
+
+/* Legacy interface */
+#define MBOX_DBUS_LEGACY_NAME		"org.openbmc.mboxd"
+#define MBOX_DBUS_LEGACY_OBJECT		"/org/openbmc/mboxd"
+
+/* Command IDs (Legacy interface) */
 #define DBUS_C_PING		0x00
 #define	DBUS_C_DAEMON_STATE	0x01
 #define DBUS_C_RESET		0x02
@@ -24,7 +41,7 @@
 #define RESUME_NOT_MODIFIED	0x00
 #define RESUME_FLASH_MODIFIED	0x01
 
-/* Return Values */
+/* Return Values (Legacy interface) */
 #define DBUS_SUCCESS		0x00 /* Command Succeded */
 #define E_DBUS_INTERNAL		0x01 /* Internal DBUS Error */
 #define E_DBUS_INVAL		0x02 /* Invalid Command */
diff --git a/mboxctl.c b/mboxctl.c
index fff8c0e..7455bc8 100644
--- a/mboxctl.c
+++ b/mboxctl.c
@@ -68,7 +68,7 @@
 	return rc;
 }
 
-static int send_dbus_msg(struct mboxctl_context *context,
+static int send_dbus_msg_legacy(struct mboxctl_context *context,
 			 struct mbox_dbus_msg *msg,
 			 struct mbox_dbus_msg *resp)
 {
@@ -79,8 +79,10 @@
 	int rc;
 
 	/* Generate the bus message */
-	rc = sd_bus_message_new_method_call(context->bus, &m, DBUS_NAME,
-					    DOBJ_NAME, DBUS_NAME, "cmd");
+	rc = sd_bus_message_new_method_call(context->bus, &m,
+					    MBOX_DBUS_LEGACY_NAME,
+					    MBOX_DBUS_LEGACY_OBJECT,
+					    MBOX_DBUS_LEGACY_NAME, "cmd");
 	if (rc < 0) {
 		MSG_ERR("Failed to init method call: %s\n",
 			strerror(-rc));
@@ -156,7 +158,7 @@
 
 	msg.cmd = DBUS_C_PING;
 
-	rc = send_dbus_msg(context, &msg, &resp);
+	rc = send_dbus_msg_legacy(context, &msg, &resp);
 	if (rc < 0) {
 		MSG_ERR("Failed to send ping command\n");
 		return rc;
@@ -181,7 +183,7 @@
 		return -E_DBUS_NO_MEM;
 	}
 
-	rc = send_dbus_msg(context, &msg, &resp);
+	rc = send_dbus_msg_legacy(context, &msg, &resp);
 	if (rc < 0) {
 		MSG_ERR("Failed to send daemon state command\n");
 		goto out;
@@ -214,7 +216,7 @@
 		return -E_DBUS_NO_MEM;
 	}
 
-	rc = send_dbus_msg(context, &msg, &resp);
+	rc = send_dbus_msg_legacy(context, &msg, &resp);
 	if (rc < 0) {
 		MSG_ERR("Failed to send lpc state command\n");
 		goto out;
@@ -244,7 +246,7 @@
 
 	msg.cmd = DBUS_C_KILL;
 
-	rc = send_dbus_msg(context, &msg, &resp);
+	rc = send_dbus_msg_legacy(context, &msg, &resp);
 	if (rc < 0) {
 		MSG_ERR("Failed to send kill command\n");
 		return rc;
@@ -263,7 +265,7 @@
 
 	msg.cmd = DBUS_C_RESET;
 
-	rc = send_dbus_msg(context, &msg, &resp);
+	rc = send_dbus_msg_legacy(context, &msg, &resp);
 	if (rc < 0) {
 		MSG_ERR("Failed to send reset command\n");
 		return rc;
@@ -282,7 +284,7 @@
 
 	msg.cmd = DBUS_C_SUSPEND;
 
-	rc = send_dbus_msg(context, &msg, &resp);
+	rc = send_dbus_msg_legacy(context, &msg, &resp);
 	if (rc < 0) {
 		MSG_ERR("Failed to send suspend command\n");
 		return rc;
@@ -323,7 +325,7 @@
 		goto out;
 	}
 
-	rc = send_dbus_msg(context, &msg, &resp);
+	rc = send_dbus_msg_legacy(context, &msg, &resp);
 	if (rc < 0) {
 		MSG_ERR("Failed to send resume command\n");
 		goto out;
@@ -344,7 +346,7 @@
 
 	msg.cmd = DBUS_C_MODIFIED;
 
-	rc = send_dbus_msg(context, &msg, &resp);
+	rc = send_dbus_msg_legacy(context, &msg, &resp);
 	if (rc < 0) {
 		MSG_ERR("Failed to send flash modified command\n");
 		return rc;
diff --git a/mboxd_dbus.c b/mboxd_dbus.c
index 4a0b38f..1f47026 100644
--- a/mboxd_dbus.c
+++ b/mboxd_dbus.c
@@ -2,343 +2,12 @@
 // Copyright (C) 2018 IBM Corp.
 
 #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 "mbox.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 reset the lpc bus
-	 * mapping back to flash, or memory in case we're using a virtual pnor.
-	 * Better set the bmc event to notify the host of this.
-	 */
-	reset_all_windows(context, SET_BMC_EVENT);
-	rc = reset_lpc(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_INFO("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) {
-		/* Call the flash modified handler */
-		dbus_handle_modified(context, req, resp);
-	}
-
-	/* Clear the bit and send the BMC Event to the host */
-	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, i;
-
-	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;
-	}
-	MSG_DBG("DBUS request: %u\n", req.cmd);
-
-	/* 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;
-	}
-	MSG_DBG("DBUS num_args: %u\n", (unsigned) req.num_args);
-	for (i = 0; i < req.num_args; i++) {
-		MSG_DBG("DBUS arg[%d]: %u\n", i, req.args[i]);
-	}
-
-	/* 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;
-	}
-	rc = sd_bus_message_new_method_return(m, &n); /* Generate response */
-	if (rc < 0) {
-		MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
-		goto cleanup;
-	}
-
-	rc = sd_bus_message_append(n, "y", resp.cmd); /* Set return code */
-	if (rc < 0) {
-		MSG_ERR("sd_bus_message_append failed: %d\n", rc);
-		goto cleanup;
-	}
-
-	rc = sd_bus_message_append_array(n, 'y', resp.args, resp.num_args);
-	if (rc < 0) {
-		MSG_ERR("sd_bus_message_append_array failed: %d\n", rc);
-		goto cleanup;
-	}
-
-	MSG_DBG("DBUS response: %u\n", resp.cmd);
-	MSG_DBG("DBUS num_args: %u\n", (unsigned) resp.num_args);
-	for (i = 0; i < resp.num_args; i++) {
-		MSG_DBG("DBUS arg[%d]: %u\n", i, resp.args[i]);
-	}
-
-	rc = sd_bus_send(NULL, n, NULL); /* Send response */
-	if (rc < 0)
-		MSG_ERR("sd_bus_send failed: %d\n", rc);
-
-cleanup:
-	free(resp.args);
-	return rc;
-}
-
-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 mboxd_dbus_init(struct mbox_context *context)
 {
@@ -351,18 +20,10 @@
 		return rc;
 	}
 
-	rc = sd_bus_add_object_vtable(context->bus, NULL, DOBJ_NAME, DBUS_NAME,
-				      mboxd_vtable, context);
+	rc = control_legacy_init(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));
+		MSG_ERR("Failed to initialise legacy DBus interface: %s\n",
+			strerror(-rc));
 		return rc;
 	}
 
@@ -379,5 +40,6 @@
 
 void mboxd_dbus_free(struct mbox_context *context)
 {
+	control_legacy_free(context);
 	sd_bus_unref(context->bus);
 }
diff --git a/mboxd_dbus.h b/mboxd_dbus.h
index 500c25b..82271fc 100644
--- a/mboxd_dbus.h
+++ b/mboxd_dbus.h
@@ -4,7 +4,23 @@
 #ifndef MBOXD_DBUS_H
 #define MBOXD_DBUS_H
 
+#include "dbus.h"
+#include "mbox.h"
+
 int mboxd_dbus_init(struct mbox_context *context);
 void mboxd_dbus_free(struct mbox_context *context);
 
+int control_legacy_init(struct mbox_context *context);
+void control_legacy_free(struct mbox_context *context);
+
+/* Control actions */
+int control_ping(struct mbox_context *context);
+int control_daemon_state(struct mbox_context *context);
+int control_lpc_state(struct mbox_context *context);
+int control_reset(struct mbox_context *context);
+int control_kill(struct mbox_context *context);
+int control_modified(struct mbox_context *context);
+int control_suspend(struct mbox_context *context);
+int control_resume(struct mbox_context *context, bool modified);
+
 #endif /* MBOXD_DBUS_H */