1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright (C) 2018 IBM Corp. 3 #include "config.h" 4 5 #include <assert.h> 6 #include <errno.h> 7 #include <string.h> 8 #include <systemd/sd-bus.h> 9 10 #include "common.h" 11 #include "dbus.h" 12 #include "mboxd.h" 13 #include "protocol.h" 14 #include "transport.h" 15 16 static int transport_dbus_property_update(struct mbox_context *context, 17 uint8_t events) 18 { 19 /* Two properties plus a terminating NULL */ 20 char *props[5] = { 0 }; 21 int i = 0; 22 int rc; 23 24 if (events & BMC_EVENT_FLASH_CTRL_LOST) { 25 props[i++] = "FlashControlLost"; 26 } 27 28 if (events & BMC_EVENT_DAEMON_READY) { 29 props[i++] = "DaemonReady"; 30 } 31 32 if (events & BMC_EVENT_WINDOW_RESET) { 33 props[i++] = "WindowReset"; 34 } 35 36 if (events & BMC_EVENT_PROTOCOL_RESET) { 37 props[i++] = "ProtocolReset"; 38 } 39 40 rc = sd_bus_emit_properties_changed_strv(context->bus, 41 MBOX_DBUS_OBJECT, 42 /* FIXME: Hard-coding v2 */ 43 MBOX_DBUS_PROTOCOL_IFACE_V2, 44 props); 45 46 return (rc < 0) ? rc : 0; 47 } 48 49 50 static int transport_dbus_put_events(struct mbox_context *context, uint8_t mask) 51 { 52 return transport_dbus_property_update(context, mask); 53 } 54 55 static int transport_dbus_set_events(struct mbox_context *context, 56 uint8_t events, uint8_t mask) 57 { 58 return transport_dbus_property_update(context, events & mask); 59 } 60 61 static int transport_dbus_clear_events(struct mbox_context *context, 62 uint8_t events, uint8_t mask) 63 { 64 return transport_dbus_property_update(context, events & mask); 65 } 66 67 static const struct transport_ops transport_dbus_ops = { 68 .put_events = transport_dbus_put_events, 69 .set_events = transport_dbus_set_events, 70 .clear_events = transport_dbus_clear_events, 71 }; 72 73 static int transport_dbus_reset(sd_bus_message *m, void *userdata, 74 sd_bus_error *ret_error) 75 { 76 struct mbox_context *context = userdata; 77 sd_bus_message *n; 78 int rc; 79 80 if (!context) { 81 MSG_ERR("DBUS Internal Error\n"); 82 return -EINVAL; 83 } 84 85 rc = context->protocol->reset(context); 86 if (rc < 0) { 87 return rc; 88 } 89 90 rc = sd_bus_message_new_method_return(m, &n); 91 if (rc < 0) { 92 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 93 return rc; 94 } 95 96 return sd_bus_send(NULL, n, NULL); 97 } 98 99 static int transport_dbus_get_info(sd_bus_message *m, void *userdata, 100 sd_bus_error *ret_error) 101 { 102 struct mbox_context *context = userdata; 103 struct protocol_get_info io; 104 sd_bus_message *n; 105 int rc; 106 107 if (!context) { 108 MSG_ERR("DBUS Internal Error\n"); 109 return -EINVAL; 110 } 111 112 rc = sd_bus_message_read_basic(m, 'y', &io.req.api_version); 113 if (rc < 0) { 114 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 115 return rc; 116 } 117 118 rc = context->protocol->get_info(context, &io); 119 if (rc < 0) { 120 return rc; 121 } 122 123 /* Switch transport to DBus. This is fine as DBus signals are async */ 124 context->transport = &transport_dbus_ops; 125 /* A bit messy, but we need the correct event mask */ 126 protocol_events_set(context, context->bmc_events); 127 128 rc = sd_bus_message_new_method_return(m, &n); 129 if (rc < 0) { 130 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 131 return rc; 132 } 133 134 if (API_VERSION_2 != io.resp.api_version) { 135 MSG_ERR("Unsupported protocol version for DBus transport: %d\n", 136 io.resp.api_version); 137 return rc; 138 } 139 140 rc = sd_bus_message_append(n, "yyq", 141 io.resp.api_version, 142 io.resp.v2.block_size_shift, 143 io.resp.v2.timeout); 144 if (rc < 0) { 145 MSG_ERR("sd_bus_message_append failed!\n"); 146 return rc; 147 } 148 149 return sd_bus_send(NULL, n, NULL); 150 } 151 152 static int transport_dbus_get_flash_info(sd_bus_message *m, void *userdata, 153 sd_bus_error *ret_error) 154 { 155 struct mbox_context *context = userdata; 156 struct protocol_get_flash_info io; 157 sd_bus_message *n; 158 int rc; 159 160 if (!context) { 161 MSG_ERR("DBUS Internal Error\n"); 162 return -EINVAL; 163 } 164 165 rc = context->protocol->get_flash_info(context, &io); 166 if (rc < 0) { 167 return rc; 168 } 169 170 rc = sd_bus_message_new_method_return(m, &n); 171 if (rc < 0) { 172 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 173 return rc; 174 } 175 176 rc = sd_bus_message_append(n, "qq", 177 io.resp.v2.flash_size, 178 io.resp.v2.erase_size); 179 if (rc < 0) { 180 MSG_ERR("sd_bus_message_append failed!\n"); 181 return rc; 182 } 183 184 return sd_bus_send(NULL, n, NULL); 185 } 186 187 static int transport_dbus_create_window(struct mbox_context *context, 188 bool ro, 189 sd_bus_message *m, 190 sd_bus_error *ret_error) 191 { 192 struct protocol_create_window io; 193 sd_bus_message *n; 194 int rc; 195 196 if (!context) { 197 MSG_ERR("DBUS Internal Error\n"); 198 return -EINVAL; 199 } 200 201 rc = sd_bus_message_read(m, "qq", &io.req.offset, &io.req.size); 202 if (rc < 0) { 203 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 204 return rc; 205 } 206 207 io.req.ro = ro; 208 rc = context->protocol->create_window(context, &io); 209 if (rc < 0) { 210 return rc; 211 } 212 213 rc = sd_bus_message_new_method_return(m, &n); 214 if (rc < 0) { 215 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 216 return rc; 217 } 218 219 rc = sd_bus_message_append(n, "qqq", 220 io.resp.lpc_address, 221 io.resp.size, 222 io.resp.offset); 223 if (rc < 0) { 224 MSG_ERR("sd_bus_message_append failed!\n"); 225 return rc; 226 } 227 228 return sd_bus_send(NULL, n, NULL); 229 } 230 231 static int transport_dbus_create_read_window(sd_bus_message *m, void *userdata, 232 sd_bus_error *ret_error) 233 { 234 struct mbox_context *context = userdata; 235 236 return transport_dbus_create_window(context, true, m, ret_error); 237 } 238 239 static int transport_dbus_create_write_window(sd_bus_message *m, void *userdata, 240 sd_bus_error *ret_error) 241 { 242 struct mbox_context *context = userdata; 243 244 return transport_dbus_create_window(context, false, m, ret_error); 245 } 246 247 static int transport_dbus_close_window(sd_bus_message *m, void *userdata, 248 sd_bus_error *ret_error) 249 { 250 struct mbox_context *context = userdata; 251 struct protocol_close io; 252 sd_bus_message *n; 253 int rc; 254 255 if (!context) { 256 MSG_ERR("DBUS Internal Error\n"); 257 return -EINVAL; 258 } 259 260 rc = sd_bus_message_read(m, "y", &io.req.flags); 261 if (rc < 0) { 262 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 263 return rc; 264 } 265 266 rc = context->protocol->close(context, &io); 267 if (rc < 0) { 268 return rc; 269 } 270 271 rc = sd_bus_message_new_method_return(m, &n); 272 if (rc < 0) { 273 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 274 return rc; 275 } 276 277 return sd_bus_send(NULL, n, NULL); 278 279 } 280 281 static int transport_dbus_mark_dirty(sd_bus_message *m, void *userdata, 282 sd_bus_error *ret_error) 283 { 284 struct mbox_context *context = userdata; 285 struct protocol_mark_dirty io; 286 sd_bus_message *n; 287 int rc; 288 289 if (!context) { 290 MSG_ERR("DBUS Internal Error\n"); 291 return -EINVAL; 292 } 293 294 rc = sd_bus_message_read(m, "qq", &io.req.v2.offset, &io.req.v2.size); 295 if (rc < 0) { 296 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 297 return rc; 298 } 299 300 rc = context->protocol->mark_dirty(context, &io); 301 if (rc < 0) { 302 return rc; 303 } 304 305 rc = sd_bus_message_new_method_return(m, &n); 306 if (rc < 0) { 307 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 308 return rc; 309 } 310 311 return sd_bus_send(NULL, n, NULL); 312 } 313 314 static int transport_dbus_write_flush(sd_bus_message *m, void *userdata, 315 sd_bus_error *ret_error) 316 { 317 struct mbox_context *context = userdata; 318 sd_bus_message *n; 319 int rc; 320 321 if (!context) { 322 MSG_ERR("DBUS Internal Error\n"); 323 return -EINVAL; 324 } 325 326 rc = context->protocol->flush(context, NULL /* No args in v2 */); 327 if (rc < 0) { 328 return rc; 329 } 330 331 rc = sd_bus_message_new_method_return(m, &n); 332 if (rc < 0) { 333 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 334 return rc; 335 } 336 337 return sd_bus_send(NULL, n, NULL); 338 } 339 340 static int transport_dbus_ack(sd_bus_message *m, void *userdata, 341 sd_bus_error *ret_error) 342 { 343 struct mbox_context *context = userdata; 344 struct protocol_ack io; 345 sd_bus_message *n; 346 int rc; 347 348 if (!context) { 349 MSG_ERR("DBUS Internal Error\n"); 350 return -EINVAL; 351 } 352 353 rc = sd_bus_message_read_basic(m, 'y', &io.req.flags); 354 if (rc < 0) { 355 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 356 return rc; 357 } 358 359 rc = context->protocol->ack(context, &io); 360 if (rc < 0) { 361 return rc; 362 } 363 364 rc = sd_bus_message_new_method_return(m, &n); 365 if (rc < 0) { 366 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 367 return rc; 368 } 369 370 return sd_bus_send(NULL, n, NULL); 371 } 372 373 static int transport_dbus_erase(sd_bus_message *m, void *userdata, 374 sd_bus_error *ret_error) 375 { 376 struct mbox_context *context = userdata; 377 struct protocol_erase io; 378 sd_bus_message *n; 379 int rc; 380 381 if (!context) { 382 MSG_ERR("DBUS Internal Error\n"); 383 return -EINVAL; 384 } 385 386 rc = sd_bus_message_read(m, "qq", &io.req.offset, &io.req.size); 387 if (rc < 0) { 388 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 389 return rc; 390 } 391 392 rc = context->protocol->erase(context, &io); 393 if (rc < 0) { 394 return rc; 395 } 396 397 rc = sd_bus_message_new_method_return(m, &n); 398 if (rc < 0) { 399 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 400 return rc; 401 } 402 403 return sd_bus_send(NULL, n, NULL); 404 } 405 406 static int transport_dbus_get_property(sd_bus *bus, 407 const char *path, 408 const char *interface, 409 const char *property, 410 sd_bus_message *reply, 411 void *userdata, 412 sd_bus_error *ret_error) 413 { 414 struct mbox_context *context = userdata; 415 bool value; 416 417 assert(!strcmp(MBOX_DBUS_OBJECT, path)); 418 assert(!strcmp(MBOX_DBUS_PROTOCOL_IFACE_V2, interface)); 419 420 if (!strcmp("FlashControlLost", property)) { 421 value = context->bmc_events & BMC_EVENT_FLASH_CTRL_LOST; 422 } else if (!strcmp("DaemonReady", property)) { 423 value = context->bmc_events & BMC_EVENT_DAEMON_READY; 424 } else if (!strcmp("WindowReset", property)) { 425 value = context->bmc_events & BMC_EVENT_WINDOW_RESET; 426 } else if (!strcmp("ProtocolReset", property)) { 427 value = context->bmc_events & BMC_EVENT_PROTOCOL_RESET; 428 } else { 429 MSG_ERR("Unknown DBus property: %s\n", property); 430 return -EINVAL; 431 } 432 433 return sd_bus_message_append(reply, "b", value); 434 } 435 436 static const sd_bus_vtable protocol_unversioned_vtable[] = { 437 SD_BUS_VTABLE_START(0), 438 SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset, 439 SD_BUS_VTABLE_UNPRIVILEGED), 440 SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info, 441 SD_BUS_VTABLE_UNPRIVILEGED), 442 SD_BUS_METHOD("Ack", "y", NULL, &transport_dbus_ack, 443 SD_BUS_VTABLE_UNPRIVILEGED), 444 SD_BUS_VTABLE_END 445 }; 446 447 static const sd_bus_vtable protocol_v2_vtable[] = { 448 SD_BUS_VTABLE_START(0), 449 SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset, 450 SD_BUS_VTABLE_UNPRIVILEGED), 451 SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info, 452 SD_BUS_VTABLE_UNPRIVILEGED), 453 SD_BUS_METHOD("GetFlashInfo", NULL, "qq", 454 &transport_dbus_get_flash_info, 455 SD_BUS_VTABLE_UNPRIVILEGED), 456 SD_BUS_METHOD("CreateReadWindow", "qq", "qqq", 457 &transport_dbus_create_read_window, 458 SD_BUS_VTABLE_UNPRIVILEGED), 459 SD_BUS_METHOD("CreateWriteWindow", "qq", "qqq", 460 &transport_dbus_create_write_window, 461 SD_BUS_VTABLE_UNPRIVILEGED), 462 SD_BUS_METHOD("CloseWindow", "y", NULL, &transport_dbus_close_window, 463 SD_BUS_VTABLE_UNPRIVILEGED), 464 SD_BUS_METHOD("MarkDirty", "qq", NULL, &transport_dbus_mark_dirty, 465 SD_BUS_VTABLE_UNPRIVILEGED), 466 SD_BUS_METHOD("Flush", NULL, NULL, &transport_dbus_write_flush, 467 SD_BUS_VTABLE_UNPRIVILEGED), 468 SD_BUS_METHOD("Ack", "y", NULL, &transport_dbus_ack, 469 SD_BUS_VTABLE_UNPRIVILEGED), 470 SD_BUS_METHOD("Erase", "qq", NULL, &transport_dbus_erase, 471 SD_BUS_VTABLE_UNPRIVILEGED), 472 SD_BUS_PROPERTY("FlashControlLost", "b", transport_dbus_get_property, 473 0, /* Just a pointer to struct mbox_context */ 474 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), 475 SD_BUS_PROPERTY("DaemonReady", "b", transport_dbus_get_property, 476 0, /* Just a pointer to struct mbox_context */ 477 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), 478 SD_BUS_PROPERTY("ProtocolReset", "b", 479 transport_dbus_get_property, 480 0, /* Just a pointer to struct mbox_context */ 481 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), 482 SD_BUS_PROPERTY("WindowReset", "b", 483 transport_dbus_get_property, 484 0, /* Just a pointer to struct mbox_context */ 485 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), 486 SD_BUS_VTABLE_END 487 }; 488 489 int transport_dbus_init(struct mbox_context *context, 490 const struct transport_ops **ops) 491 { 492 int rc; 493 494 rc = sd_bus_add_object_vtable(context->bus, NULL, 495 MBOX_DBUS_OBJECT, 496 MBOX_DBUS_PROTOCOL_IFACE, 497 protocol_unversioned_vtable, 498 context); 499 if (rc < 0) { 500 return rc; 501 } 502 503 rc = sd_bus_add_object_vtable(context->bus, NULL, 504 MBOX_DBUS_OBJECT, 505 MBOX_DBUS_PROTOCOL_IFACE_V2, 506 protocol_v2_vtable, context); 507 if (rc < 0) { 508 return rc; 509 } 510 511 if (ops) { 512 *ops = &transport_dbus_ops; 513 } 514 515 return 0; 516 } 517 518 #define __unused __attribute__((unused)) 519 void transport_dbus_free(struct mbox_context *context __unused) 520 { 521 return; 522 } 523