1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright (C) 2018 IBM Corp. 3 #include <errno.h> 4 #include <stdlib.h> 5 6 #include "common.h" 7 #include "dbus.h" 8 #include "control_dbus.h" 9 #include "mboxd.h" 10 11 /* Command IDs (Legacy interface) */ 12 #define DBUS_C_PING 0x00 13 #define DBUS_C_DAEMON_STATE 0x01 14 #define DBUS_C_RESET 0x02 15 #define DBUS_C_SUSPEND 0x03 16 #define DBUS_C_RESUME 0x04 17 #define DBUS_C_MODIFIED 0x05 18 #define DBUS_C_KILL 0x06 19 #define DBUS_C_LPC_STATE 0x07 20 #define NUM_DBUS_CMDS (DBUS_C_LPC_STATE + 1) 21 22 /* Return Values (Legacy interface) */ 23 #define DBUS_SUCCESS 0x00 /* Command Succeded */ 24 #define E_DBUS_INTERNAL 0x01 /* Internal DBUS Error */ 25 #define E_DBUS_INVAL 0x02 /* Invalid Command */ 26 #define E_DBUS_REJECTED 0x03 /* Daemon Rejected Request */ 27 #define E_DBUS_HARDWARE 0x04 /* BMC Hardware Error */ 28 #define E_DBUS_NO_MEM 0x05 /* Failed Memory Allocation */ 29 30 struct mbox_dbus_msg { 31 uint8_t cmd; 32 size_t num_args; 33 uint8_t *args; 34 }; 35 36 /* 37 * Command: DBUS Ping 38 * Ping the daemon 39 * 40 * Args: NONE 41 * Resp: NONE 42 */ 43 static int control_legacy_ping(struct mbox_context *context, 44 struct mbox_dbus_msg *req __attribute__((unused)), 45 struct mbox_dbus_msg *resp __attribute__((unused))) 46 { 47 return control_ping(context); 48 } 49 50 /* 51 * Command: DBUS Status 52 * Get the status of the daemon 53 * 54 * Args: NONE 55 * Resp[0]: Status Code 56 */ 57 static int control_legacy_daemon_state(struct mbox_context *context, 58 struct mbox_dbus_msg *req __attribute__((unused)), 59 struct mbox_dbus_msg *resp) 60 { 61 resp->num_args = DAEMON_STATE_NUM_ARGS; 62 resp->args = calloc(resp->num_args, sizeof(*resp->args)); 63 resp->args[0] = control_daemon_state(context); 64 65 return 0; 66 } 67 68 /* 69 * Command: DBUS LPC State 70 * Get the state of the lpc bus mapping (whether it points to memory or flash 71 * 72 * Args: NONE 73 * Resp[0]: LPC Bus State Code 74 */ 75 static int control_legacy_lpc_state(struct mbox_context *context, 76 struct mbox_dbus_msg *req __attribute__((unused)), 77 struct mbox_dbus_msg *resp) 78 { 79 80 resp->num_args = LPC_STATE_NUM_ARGS; 81 resp->args = calloc(resp->num_args, sizeof(*resp->args)); 82 resp->args[0] = control_lpc_state(context); 83 84 return 0; 85 } 86 87 /* 88 * Command: DBUS Reset 89 * Reset the daemon state, final operation TBA. 90 * For now we just point the lpc mapping back at the flash. 91 * 92 * Args: NONE 93 * Resp: NONE 94 */ 95 static int control_legacy_reset(struct mbox_context *context, 96 struct mbox_dbus_msg *req __attribute__((unused)), 97 struct mbox_dbus_msg *resp __attribute__((unused))) 98 { 99 int rc; 100 101 rc = control_reset(context); 102 103 /* Map return codes for compatibility */ 104 if (rc == -EBUSY) { 105 return -E_DBUS_REJECTED; 106 } else if (rc < 0) { 107 return -E_DBUS_HARDWARE; 108 } 109 110 return rc; 111 } 112 113 /* 114 * Command: DBUS Kill 115 * Stop the daemon 116 * 117 * Args: NONE 118 * Resp: NONE 119 */ 120 static int control_legacy_kill(struct mbox_context *context, 121 struct mbox_dbus_msg *req __attribute__((unused)), 122 struct mbox_dbus_msg *resp __attribute__((unused))) 123 { 124 return control_kill(context); 125 } 126 127 /* 128 * Command: DBUS Flash Modified 129 * Used to notify the daemon that the flash has been modified out from under 130 * it - We need to reset all out windows to ensure flash will be reloaded 131 * when a new window is opened. 132 * Note: We don't flush any previously opened windows 133 * 134 * Args: NONE 135 * Resp: NONE 136 */ 137 static int control_legacy_modified(struct mbox_context *context, 138 struct mbox_dbus_msg *req __attribute__((unused)), 139 struct mbox_dbus_msg *resp __attribute__((unused))) 140 { 141 return control_modified(context); 142 } 143 144 /* 145 * Command: DBUS Suspend 146 * Suspend the daemon to inhibit it from performing flash accesses. 147 * This is used to synchronise access to the flash between the daemon and 148 * directly from the BMC. 149 * 150 * Args: NONE 151 * Resp: NONE 152 */ 153 static int control_legacy_suspend(struct mbox_context *context, 154 struct mbox_dbus_msg *req __attribute__((unused)), 155 struct mbox_dbus_msg *resp __attribute__((unused))) 156 { 157 int rc; 158 159 rc = control_suspend(context); 160 if (rc < 0) { 161 /* Map return codes for compatibility */ 162 return -E_DBUS_HARDWARE; 163 } 164 165 return rc; 166 } 167 168 /* 169 * Command: DBUS Resume 170 * Resume the daemon to let it perform flash accesses again. 171 * 172 * Args[0]: Flash Modified (0 - no | 1 - yes) 173 * Resp: NONE 174 */ 175 static int control_legacy_resume(struct mbox_context *context, 176 struct mbox_dbus_msg *req, 177 struct mbox_dbus_msg *resp __attribute__((unused))) 178 { 179 int rc; 180 181 if (req->num_args != 1) { 182 return -E_DBUS_INVAL; 183 } 184 185 rc = control_resume(context, req->args[0] == RESUME_FLASH_MODIFIED); 186 if (rc < 0) { 187 /* Map return codes for compatibility */ 188 rc = -E_DBUS_HARDWARE; 189 } 190 191 return rc; 192 } 193 194 typedef int (*control_action)(struct mbox_context *context, 195 struct mbox_dbus_msg *req, 196 struct mbox_dbus_msg *resp); 197 static const control_action dbus_handlers[NUM_DBUS_CMDS] = { 198 control_legacy_ping, 199 control_legacy_daemon_state, 200 control_legacy_reset, 201 control_legacy_suspend, 202 control_legacy_resume, 203 control_legacy_modified, 204 control_legacy_kill, 205 control_legacy_lpc_state 206 }; 207 208 static int method_cmd(sd_bus_message *m, void *userdata, 209 sd_bus_error *ret_error __attribute__((unused))) 210 { 211 struct mbox_dbus_msg req = { 0 }, resp = { 0 }; 212 struct mbox_context *context; 213 sd_bus_message *n; 214 int rc; 215 size_t i; 216 217 context = (struct mbox_context *) userdata; 218 if (!context) { 219 MSG_ERR("DBUS Internal Error\n"); 220 rc = -E_DBUS_INTERNAL; 221 goto out; 222 } 223 224 /* Read the command */ 225 rc = sd_bus_message_read(m, "y", &req.cmd); 226 if (rc < 0) { 227 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 228 rc = -E_DBUS_INTERNAL; 229 goto out; 230 } 231 MSG_DBG("DBUS request: %u\n", req.cmd); 232 233 /* Read the args */ 234 rc = sd_bus_message_read_array(m, 'y', (const void **) &req.args, 235 &req.num_args); 236 if (rc < 0) { 237 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 238 rc = -E_DBUS_INTERNAL; 239 goto out; 240 } 241 MSG_DBG("DBUS num_args: %u\n", (unsigned) req.num_args); 242 for (i = 0; i < req.num_args; i++) { 243 MSG_DBG("DBUS arg[%zd]: %u\n", i, req.args[i]); 244 } 245 246 /* Handle the command */ 247 if (req.cmd >= NUM_DBUS_CMDS) { 248 rc = -E_DBUS_INVAL; 249 MSG_ERR("Received unknown dbus cmd: %d\n", req.cmd); 250 } else { 251 rc = dbus_handlers[req.cmd](context, &req, &resp); 252 } 253 254 out: 255 if (rc < 0) { 256 resp.cmd = -rc; 257 } 258 rc = sd_bus_message_new_method_return(m, &n); /* Generate response */ 259 if (rc < 0) { 260 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 261 goto cleanup; 262 } 263 264 rc = sd_bus_message_append(n, "y", resp.cmd); /* Set return code */ 265 if (rc < 0) { 266 MSG_ERR("sd_bus_message_append failed: %d\n", rc); 267 goto cleanup; 268 } 269 270 rc = sd_bus_message_append_array(n, 'y', resp.args, resp.num_args); 271 if (rc < 0) { 272 MSG_ERR("sd_bus_message_append_array failed: %d\n", rc); 273 goto cleanup; 274 } 275 276 MSG_DBG("DBUS response: %u\n", resp.cmd); 277 MSG_DBG("DBUS num_args: %u\n", (unsigned) resp.num_args); 278 for (i = 0; i < resp.num_args; i++) { 279 MSG_DBG("DBUS arg[%zd]: %u\n", i, resp.args[i]); 280 } 281 282 rc = sd_bus_send(NULL, n, NULL); /* Send response */ 283 sd_bus_message_unref(n); 284 if (rc < 0) 285 MSG_ERR("sd_bus_send failed: %d\n", rc); 286 287 cleanup: 288 free(resp.args); 289 return rc; 290 } 291 292 static const sd_bus_vtable control_legacy_vtable[] = { 293 SD_BUS_VTABLE_START(0), 294 SD_BUS_METHOD("cmd", "yay", "yay", &method_cmd, 295 SD_BUS_VTABLE_UNPRIVILEGED), 296 SD_BUS_VTABLE_END 297 }; 298 299 int control_legacy_init(struct mbox_context *context) 300 { 301 int rc; 302 303 rc = sd_bus_add_object_vtable(context->bus, NULL, 304 MBOX_DBUS_LEGACY_OBJECT, 305 MBOX_DBUS_LEGACY_NAME, 306 control_legacy_vtable, context); 307 if (rc < 0) { 308 MSG_ERR("Failed to register vtable: %s\n", strerror(-rc)); 309 return rc; 310 } 311 312 return sd_bus_request_name(context->bus, MBOX_DBUS_LEGACY_NAME, 313 SD_BUS_NAME_ALLOW_REPLACEMENT | 314 SD_BUS_NAME_REPLACE_EXISTING); 315 } 316 317 void control_legacy_free(struct mbox_context *context __attribute__((unused))) 318 { 319 return; 320 } 321