blob: 8ef9ea96a2e0325838070ae3404a3a0e09646e03 [file] [log] [blame]
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2018 IBM Corp.
#include <errno.h>
#include <stdlib.h>
#include "common.h"
#include "dbus.h"
#include "control_dbus.h"
#include "mbox.h"
/* Command IDs (Legacy interface) */
#define DBUS_C_PING 0x00
#define DBUS_C_DAEMON_STATE 0x01
#define DBUS_C_RESET 0x02
#define DBUS_C_SUSPEND 0x03
#define DBUS_C_RESUME 0x04
#define DBUS_C_MODIFIED 0x05
#define DBUS_C_KILL 0x06
#define DBUS_C_LPC_STATE 0x07
#define NUM_DBUS_CMDS (DBUS_C_LPC_STATE + 1)
/* 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 */
#define E_DBUS_REJECTED 0x03 /* Daemon Rejected Request */
#define E_DBUS_HARDWARE 0x04 /* BMC Hardware Error */
#define E_DBUS_NO_MEM 0x05 /* Failed Memory Allocation */
struct mbox_dbus_msg {
uint8_t cmd;
size_t num_args;
uint8_t *args;
};
/*
* 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;
}