168023074SAndrew Jeffery // SPDX-License-Identifier: Apache-2.0
268023074SAndrew Jeffery // Copyright (C) 2018 IBM Corp.
368023074SAndrew Jeffery #include <errno.h>
468023074SAndrew Jeffery #include <stdlib.h>
568023074SAndrew Jeffery
668023074SAndrew Jeffery #include "common.h"
768023074SAndrew Jeffery #include "dbus.h"
855f4d6f9SAndrew Jeffery #include "control_dbus.h"
926558dbbSAndrew Jeffery #include "mboxd.h"
1068023074SAndrew Jeffery
11ef9e62d3SAndrew Jeffery /* Command IDs (Legacy interface) */
12ef9e62d3SAndrew Jeffery #define DBUS_C_PING 0x00
13ef9e62d3SAndrew Jeffery #define DBUS_C_DAEMON_STATE 0x01
14ef9e62d3SAndrew Jeffery #define DBUS_C_RESET 0x02
15ef9e62d3SAndrew Jeffery #define DBUS_C_SUSPEND 0x03
16ef9e62d3SAndrew Jeffery #define DBUS_C_RESUME 0x04
17ef9e62d3SAndrew Jeffery #define DBUS_C_MODIFIED 0x05
18ef9e62d3SAndrew Jeffery #define DBUS_C_KILL 0x06
19ef9e62d3SAndrew Jeffery #define DBUS_C_LPC_STATE 0x07
20ef9e62d3SAndrew Jeffery #define NUM_DBUS_CMDS (DBUS_C_LPC_STATE + 1)
21ef9e62d3SAndrew Jeffery
22ef9e62d3SAndrew Jeffery /* Return Values (Legacy interface) */
23ef9e62d3SAndrew Jeffery #define DBUS_SUCCESS 0x00 /* Command Succeded */
24ef9e62d3SAndrew Jeffery #define E_DBUS_INTERNAL 0x01 /* Internal DBUS Error */
25ef9e62d3SAndrew Jeffery #define E_DBUS_INVAL 0x02 /* Invalid Command */
26ef9e62d3SAndrew Jeffery #define E_DBUS_REJECTED 0x03 /* Daemon Rejected Request */
27ef9e62d3SAndrew Jeffery #define E_DBUS_HARDWARE 0x04 /* BMC Hardware Error */
28ef9e62d3SAndrew Jeffery #define E_DBUS_NO_MEM 0x05 /* Failed Memory Allocation */
29ef9e62d3SAndrew Jeffery
30ef9e62d3SAndrew Jeffery struct mbox_dbus_msg {
31ef9e62d3SAndrew Jeffery uint8_t cmd;
32ef9e62d3SAndrew Jeffery size_t num_args;
33ef9e62d3SAndrew Jeffery uint8_t *args;
34ef9e62d3SAndrew Jeffery };
35ef9e62d3SAndrew Jeffery
3668023074SAndrew Jeffery /*
3768023074SAndrew Jeffery * Command: DBUS Ping
3868023074SAndrew Jeffery * Ping the daemon
3968023074SAndrew Jeffery *
4068023074SAndrew Jeffery * Args: NONE
4168023074SAndrew Jeffery * Resp: NONE
4268023074SAndrew Jeffery */
control_legacy_ping(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)4368023074SAndrew Jeffery static int control_legacy_ping(struct mbox_context *context,
44*68a24c9eSPatrick Williams struct mbox_dbus_msg *req __attribute__((unused)),
45*68a24c9eSPatrick Williams struct mbox_dbus_msg *resp __attribute__((unused)))
4668023074SAndrew Jeffery {
4768023074SAndrew Jeffery return control_ping(context);
4868023074SAndrew Jeffery }
4968023074SAndrew Jeffery
5068023074SAndrew Jeffery /*
5168023074SAndrew Jeffery * Command: DBUS Status
5268023074SAndrew Jeffery * Get the status of the daemon
5368023074SAndrew Jeffery *
5468023074SAndrew Jeffery * Args: NONE
5568023074SAndrew Jeffery * Resp[0]: Status Code
5668023074SAndrew Jeffery */
control_legacy_daemon_state(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)5768023074SAndrew Jeffery static int control_legacy_daemon_state(struct mbox_context *context,
58*68a24c9eSPatrick Williams struct mbox_dbus_msg *req __attribute__((unused)),
5968023074SAndrew Jeffery struct mbox_dbus_msg *resp)
6068023074SAndrew Jeffery {
6168023074SAndrew Jeffery resp->num_args = DAEMON_STATE_NUM_ARGS;
6268023074SAndrew Jeffery resp->args = calloc(resp->num_args, sizeof(*resp->args));
6368023074SAndrew Jeffery resp->args[0] = control_daemon_state(context);
6468023074SAndrew Jeffery
6568023074SAndrew Jeffery return 0;
6668023074SAndrew Jeffery }
6768023074SAndrew Jeffery
6868023074SAndrew Jeffery /*
6968023074SAndrew Jeffery * Command: DBUS LPC State
7068023074SAndrew Jeffery * Get the state of the lpc bus mapping (whether it points to memory or flash
7168023074SAndrew Jeffery *
7268023074SAndrew Jeffery * Args: NONE
7368023074SAndrew Jeffery * Resp[0]: LPC Bus State Code
7468023074SAndrew Jeffery */
control_legacy_lpc_state(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)7568023074SAndrew Jeffery static int control_legacy_lpc_state(struct mbox_context *context,
76*68a24c9eSPatrick Williams struct mbox_dbus_msg *req __attribute__((unused)),
7768023074SAndrew Jeffery struct mbox_dbus_msg *resp)
7868023074SAndrew Jeffery {
79*68a24c9eSPatrick Williams
8068023074SAndrew Jeffery resp->num_args = LPC_STATE_NUM_ARGS;
8168023074SAndrew Jeffery resp->args = calloc(resp->num_args, sizeof(*resp->args));
8268023074SAndrew Jeffery resp->args[0] = control_lpc_state(context);
8368023074SAndrew Jeffery
8468023074SAndrew Jeffery return 0;
8568023074SAndrew Jeffery }
8668023074SAndrew Jeffery
8768023074SAndrew Jeffery /*
8868023074SAndrew Jeffery * Command: DBUS Reset
8968023074SAndrew Jeffery * Reset the daemon state, final operation TBA.
9068023074SAndrew Jeffery * For now we just point the lpc mapping back at the flash.
9168023074SAndrew Jeffery *
9268023074SAndrew Jeffery * Args: NONE
9368023074SAndrew Jeffery * Resp: NONE
9468023074SAndrew Jeffery */
control_legacy_reset(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)9568023074SAndrew Jeffery static int control_legacy_reset(struct mbox_context *context,
96*68a24c9eSPatrick Williams struct mbox_dbus_msg *req __attribute__((unused)),
97*68a24c9eSPatrick Williams struct mbox_dbus_msg *resp __attribute__((unused)))
9868023074SAndrew Jeffery {
9968023074SAndrew Jeffery int rc;
10068023074SAndrew Jeffery
10168023074SAndrew Jeffery rc = control_reset(context);
10268023074SAndrew Jeffery
10368023074SAndrew Jeffery /* Map return codes for compatibility */
10468023074SAndrew Jeffery if (rc == -EBUSY) {
10568023074SAndrew Jeffery return -E_DBUS_REJECTED;
10668023074SAndrew Jeffery } else if (rc < 0) {
10768023074SAndrew Jeffery return -E_DBUS_HARDWARE;
10868023074SAndrew Jeffery }
10968023074SAndrew Jeffery
11068023074SAndrew Jeffery return rc;
11168023074SAndrew Jeffery }
11268023074SAndrew Jeffery
11368023074SAndrew Jeffery /*
11468023074SAndrew Jeffery * Command: DBUS Kill
11568023074SAndrew Jeffery * Stop the daemon
11668023074SAndrew Jeffery *
11768023074SAndrew Jeffery * Args: NONE
11868023074SAndrew Jeffery * Resp: NONE
11968023074SAndrew Jeffery */
control_legacy_kill(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)12068023074SAndrew Jeffery static int control_legacy_kill(struct mbox_context *context,
121*68a24c9eSPatrick Williams struct mbox_dbus_msg *req __attribute__((unused)),
122*68a24c9eSPatrick Williams struct mbox_dbus_msg *resp __attribute__((unused)))
12368023074SAndrew Jeffery {
12468023074SAndrew Jeffery return control_kill(context);
12568023074SAndrew Jeffery }
12668023074SAndrew Jeffery
12768023074SAndrew Jeffery /*
12868023074SAndrew Jeffery * Command: DBUS Flash Modified
12968023074SAndrew Jeffery * Used to notify the daemon that the flash has been modified out from under
13068023074SAndrew Jeffery * it - We need to reset all out windows to ensure flash will be reloaded
13168023074SAndrew Jeffery * when a new window is opened.
13268023074SAndrew Jeffery * Note: We don't flush any previously opened windows
13368023074SAndrew Jeffery *
13468023074SAndrew Jeffery * Args: NONE
13568023074SAndrew Jeffery * Resp: NONE
13668023074SAndrew Jeffery */
control_legacy_modified(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)13768023074SAndrew Jeffery static int control_legacy_modified(struct mbox_context *context,
138*68a24c9eSPatrick Williams struct mbox_dbus_msg *req __attribute__((unused)),
139*68a24c9eSPatrick Williams struct mbox_dbus_msg *resp __attribute__((unused)))
14068023074SAndrew Jeffery {
14168023074SAndrew Jeffery return control_modified(context);
14268023074SAndrew Jeffery }
14368023074SAndrew Jeffery
14468023074SAndrew Jeffery /*
14568023074SAndrew Jeffery * Command: DBUS Suspend
14668023074SAndrew Jeffery * Suspend the daemon to inhibit it from performing flash accesses.
14768023074SAndrew Jeffery * This is used to synchronise access to the flash between the daemon and
14868023074SAndrew Jeffery * directly from the BMC.
14968023074SAndrew Jeffery *
15068023074SAndrew Jeffery * Args: NONE
15168023074SAndrew Jeffery * Resp: NONE
15268023074SAndrew Jeffery */
control_legacy_suspend(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)15368023074SAndrew Jeffery static int control_legacy_suspend(struct mbox_context *context,
154*68a24c9eSPatrick Williams struct mbox_dbus_msg *req __attribute__((unused)),
155*68a24c9eSPatrick Williams struct mbox_dbus_msg *resp __attribute__((unused)))
15668023074SAndrew Jeffery {
15768023074SAndrew Jeffery int rc;
15868023074SAndrew Jeffery
15968023074SAndrew Jeffery rc = control_suspend(context);
16068023074SAndrew Jeffery if (rc < 0) {
16168023074SAndrew Jeffery /* Map return codes for compatibility */
16268023074SAndrew Jeffery return -E_DBUS_HARDWARE;
16368023074SAndrew Jeffery }
16468023074SAndrew Jeffery
16568023074SAndrew Jeffery return rc;
16668023074SAndrew Jeffery }
16768023074SAndrew Jeffery
16868023074SAndrew Jeffery /*
16968023074SAndrew Jeffery * Command: DBUS Resume
17068023074SAndrew Jeffery * Resume the daemon to let it perform flash accesses again.
17168023074SAndrew Jeffery *
17268023074SAndrew Jeffery * Args[0]: Flash Modified (0 - no | 1 - yes)
17368023074SAndrew Jeffery * Resp: NONE
17468023074SAndrew Jeffery */
control_legacy_resume(struct mbox_context * context,struct mbox_dbus_msg * req,struct mbox_dbus_msg * resp)17568023074SAndrew Jeffery static int control_legacy_resume(struct mbox_context *context,
17668023074SAndrew Jeffery struct mbox_dbus_msg *req,
177*68a24c9eSPatrick Williams struct mbox_dbus_msg *resp __attribute__((unused)))
17868023074SAndrew Jeffery {
17968023074SAndrew Jeffery int rc;
18068023074SAndrew Jeffery
18168023074SAndrew Jeffery if (req->num_args != 1) {
18268023074SAndrew Jeffery return -E_DBUS_INVAL;
18368023074SAndrew Jeffery }
18468023074SAndrew Jeffery
18568023074SAndrew Jeffery rc = control_resume(context, req->args[0] == RESUME_FLASH_MODIFIED);
18668023074SAndrew Jeffery if (rc < 0) {
18768023074SAndrew Jeffery /* Map return codes for compatibility */
18868023074SAndrew Jeffery rc = -E_DBUS_HARDWARE;
18968023074SAndrew Jeffery }
19068023074SAndrew Jeffery
19168023074SAndrew Jeffery return rc;
19268023074SAndrew Jeffery }
19368023074SAndrew Jeffery
19468023074SAndrew Jeffery typedef int (*control_action)(struct mbox_context *context,
19568023074SAndrew Jeffery struct mbox_dbus_msg *req,
19668023074SAndrew Jeffery struct mbox_dbus_msg *resp);
19768023074SAndrew Jeffery static const control_action dbus_handlers[NUM_DBUS_CMDS] = {
19868023074SAndrew Jeffery control_legacy_ping,
19968023074SAndrew Jeffery control_legacy_daemon_state,
20068023074SAndrew Jeffery control_legacy_reset,
20168023074SAndrew Jeffery control_legacy_suspend,
20268023074SAndrew Jeffery control_legacy_resume,
20368023074SAndrew Jeffery control_legacy_modified,
20468023074SAndrew Jeffery control_legacy_kill,
20568023074SAndrew Jeffery control_legacy_lpc_state
20668023074SAndrew Jeffery };
20768023074SAndrew Jeffery
method_cmd(sd_bus_message * m,void * userdata,sd_bus_error * ret_error)20868023074SAndrew Jeffery static int method_cmd(sd_bus_message *m, void *userdata,
209*68a24c9eSPatrick Williams sd_bus_error *ret_error __attribute__((unused)))
21068023074SAndrew Jeffery {
21168023074SAndrew Jeffery struct mbox_dbus_msg req = { 0 }, resp = { 0 };
21268023074SAndrew Jeffery struct mbox_context *context;
21368023074SAndrew Jeffery sd_bus_message *n;
214*68a24c9eSPatrick Williams int rc;
215*68a24c9eSPatrick Williams size_t i;
21668023074SAndrew Jeffery
21768023074SAndrew Jeffery context = (struct mbox_context *) userdata;
21868023074SAndrew Jeffery if (!context) {
21968023074SAndrew Jeffery MSG_ERR("DBUS Internal Error\n");
22068023074SAndrew Jeffery rc = -E_DBUS_INTERNAL;
22168023074SAndrew Jeffery goto out;
22268023074SAndrew Jeffery }
22368023074SAndrew Jeffery
22468023074SAndrew Jeffery /* Read the command */
22568023074SAndrew Jeffery rc = sd_bus_message_read(m, "y", &req.cmd);
22668023074SAndrew Jeffery if (rc < 0) {
22768023074SAndrew Jeffery MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
22868023074SAndrew Jeffery rc = -E_DBUS_INTERNAL;
22968023074SAndrew Jeffery goto out;
23068023074SAndrew Jeffery }
23168023074SAndrew Jeffery MSG_DBG("DBUS request: %u\n", req.cmd);
23268023074SAndrew Jeffery
23368023074SAndrew Jeffery /* Read the args */
23468023074SAndrew Jeffery rc = sd_bus_message_read_array(m, 'y', (const void **) &req.args,
23568023074SAndrew Jeffery &req.num_args);
23668023074SAndrew Jeffery if (rc < 0) {
23768023074SAndrew Jeffery MSG_ERR("DBUS error reading message: %s\n", strerror(-rc));
23868023074SAndrew Jeffery rc = -E_DBUS_INTERNAL;
23968023074SAndrew Jeffery goto out;
24068023074SAndrew Jeffery }
24168023074SAndrew Jeffery MSG_DBG("DBUS num_args: %u\n", (unsigned) req.num_args);
24268023074SAndrew Jeffery for (i = 0; i < req.num_args; i++) {
243*68a24c9eSPatrick Williams MSG_DBG("DBUS arg[%zd]: %u\n", i, req.args[i]);
24468023074SAndrew Jeffery }
24568023074SAndrew Jeffery
24668023074SAndrew Jeffery /* Handle the command */
24768023074SAndrew Jeffery if (req.cmd >= NUM_DBUS_CMDS) {
24868023074SAndrew Jeffery rc = -E_DBUS_INVAL;
24968023074SAndrew Jeffery MSG_ERR("Received unknown dbus cmd: %d\n", req.cmd);
25068023074SAndrew Jeffery } else {
25168023074SAndrew Jeffery rc = dbus_handlers[req.cmd](context, &req, &resp);
25268023074SAndrew Jeffery }
25368023074SAndrew Jeffery
25468023074SAndrew Jeffery out:
25568023074SAndrew Jeffery if (rc < 0) {
25668023074SAndrew Jeffery resp.cmd = -rc;
25768023074SAndrew Jeffery }
25868023074SAndrew Jeffery rc = sd_bus_message_new_method_return(m, &n); /* Generate response */
25968023074SAndrew Jeffery if (rc < 0) {
26068023074SAndrew Jeffery MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc);
26168023074SAndrew Jeffery goto cleanup;
26268023074SAndrew Jeffery }
26368023074SAndrew Jeffery
26468023074SAndrew Jeffery rc = sd_bus_message_append(n, "y", resp.cmd); /* Set return code */
26568023074SAndrew Jeffery if (rc < 0) {
26668023074SAndrew Jeffery MSG_ERR("sd_bus_message_append failed: %d\n", rc);
26768023074SAndrew Jeffery goto cleanup;
26868023074SAndrew Jeffery }
26968023074SAndrew Jeffery
27068023074SAndrew Jeffery rc = sd_bus_message_append_array(n, 'y', resp.args, resp.num_args);
27168023074SAndrew Jeffery if (rc < 0) {
27268023074SAndrew Jeffery MSG_ERR("sd_bus_message_append_array failed: %d\n", rc);
27368023074SAndrew Jeffery goto cleanup;
27468023074SAndrew Jeffery }
27568023074SAndrew Jeffery
27668023074SAndrew Jeffery MSG_DBG("DBUS response: %u\n", resp.cmd);
27768023074SAndrew Jeffery MSG_DBG("DBUS num_args: %u\n", (unsigned) resp.num_args);
27868023074SAndrew Jeffery for (i = 0; i < resp.num_args; i++) {
279*68a24c9eSPatrick Williams MSG_DBG("DBUS arg[%zd]: %u\n", i, resp.args[i]);
28068023074SAndrew Jeffery }
28168023074SAndrew Jeffery
28268023074SAndrew Jeffery rc = sd_bus_send(NULL, n, NULL); /* Send response */
283fac3689eSAndrew Jeffery sd_bus_message_unref(n);
28468023074SAndrew Jeffery if (rc < 0)
28568023074SAndrew Jeffery MSG_ERR("sd_bus_send failed: %d\n", rc);
28668023074SAndrew Jeffery
28768023074SAndrew Jeffery cleanup:
28868023074SAndrew Jeffery free(resp.args);
28968023074SAndrew Jeffery return rc;
29068023074SAndrew Jeffery }
29168023074SAndrew Jeffery
29268023074SAndrew Jeffery static const sd_bus_vtable control_legacy_vtable[] = {
29368023074SAndrew Jeffery SD_BUS_VTABLE_START(0),
29468023074SAndrew Jeffery SD_BUS_METHOD("cmd", "yay", "yay", &method_cmd,
29568023074SAndrew Jeffery SD_BUS_VTABLE_UNPRIVILEGED),
29668023074SAndrew Jeffery SD_BUS_VTABLE_END
29768023074SAndrew Jeffery };
29868023074SAndrew Jeffery
control_legacy_init(struct mbox_context * context)29968023074SAndrew Jeffery int control_legacy_init(struct mbox_context *context)
30068023074SAndrew Jeffery {
30168023074SAndrew Jeffery int rc;
30268023074SAndrew Jeffery
30368023074SAndrew Jeffery rc = sd_bus_add_object_vtable(context->bus, NULL,
30468023074SAndrew Jeffery MBOX_DBUS_LEGACY_OBJECT,
30568023074SAndrew Jeffery MBOX_DBUS_LEGACY_NAME,
30668023074SAndrew Jeffery control_legacy_vtable, context);
30768023074SAndrew Jeffery if (rc < 0) {
30868023074SAndrew Jeffery MSG_ERR("Failed to register vtable: %s\n", strerror(-rc));
30968023074SAndrew Jeffery return rc;
31068023074SAndrew Jeffery }
31168023074SAndrew Jeffery
31268023074SAndrew Jeffery return sd_bus_request_name(context->bus, MBOX_DBUS_LEGACY_NAME,
31368023074SAndrew Jeffery SD_BUS_NAME_ALLOW_REPLACEMENT |
31468023074SAndrew Jeffery SD_BUS_NAME_REPLACE_EXISTING);
31568023074SAndrew Jeffery }
31668023074SAndrew Jeffery
control_legacy_free(struct mbox_context * context)31768023074SAndrew Jeffery void control_legacy_free(struct mbox_context *context __attribute__((unused)))
31868023074SAndrew Jeffery {
31968023074SAndrew Jeffery return;
32068023074SAndrew Jeffery }
321