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 static int transport_dbus_signal_update(struct mbox_context *context, 50 uint8_t events) 51 { 52 int rc; 53 54 /* 55 * Handle signals - edge triggered, only necessary when they're 56 * asserted 57 */ 58 if (events & BMC_EVENT_WINDOW_RESET) { 59 sd_bus_message *m = NULL; 60 61 rc = sd_bus_message_new_signal(context->bus, &m, 62 MBOX_DBUS_OBJECT, 63 /* FIXME: Hard-coding v2 */ 64 MBOX_DBUS_PROTOCOL_IFACE_V2, 65 "WindowReset"); 66 if (rc < 0) { 67 return rc; 68 } 69 70 rc = sd_bus_send(context->bus, m, NULL); 71 if (rc < 0) { 72 return rc; 73 } 74 } 75 76 if (events & BMC_EVENT_PROTOCOL_RESET) { 77 sd_bus_message *m = NULL; 78 79 rc = sd_bus_message_new_signal(context->bus, &m, 80 MBOX_DBUS_OBJECT, 81 /* FIXME: Hard-coding v2 */ 82 MBOX_DBUS_PROTOCOL_IFACE_V2, 83 "ProtocolReset"); 84 if (rc < 0) { 85 return rc; 86 } 87 88 rc = sd_bus_send(context->bus, m, NULL); 89 if (rc < 0) { 90 return rc; 91 } 92 } 93 94 return 0; 95 } 96 97 static int transport_dbus_put_events(struct mbox_context *context, uint8_t mask) 98 { 99 int rc; 100 101 /* Always update all properties */ 102 rc = transport_dbus_property_update(context, mask); 103 if (rc < 0) { 104 return rc; 105 } 106 107 /* 108 * Still test signals against the values set as sending them indicates 109 * the event has been asserted, so we must not send them if the bits 110 * are not set. 111 */ 112 return transport_dbus_signal_update(context, 113 context->bmc_events & mask); 114 } 115 116 static int transport_dbus_set_events(struct mbox_context *context, 117 uint8_t events, uint8_t mask) 118 { 119 int rc; 120 121 rc = transport_dbus_property_update(context, events & mask); 122 if (rc < 0) { 123 return rc; 124 } 125 126 return transport_dbus_signal_update(context, events & mask); 127 } 128 129 static int transport_dbus_clear_events(struct mbox_context *context, 130 uint8_t events, uint8_t mask) 131 { 132 /* No need to emit signals for ackable events on clear */ 133 return transport_dbus_property_update(context, events & mask); 134 } 135 136 static const struct transport_ops transport_dbus_ops = { 137 .put_events = transport_dbus_put_events, 138 .set_events = transport_dbus_set_events, 139 .clear_events = transport_dbus_clear_events, 140 }; 141 142 static int transport_dbus_reset(sd_bus_message *m, void *userdata, 143 sd_bus_error *ret_error) 144 { 145 struct mbox_context *context = userdata; 146 sd_bus_message *n; 147 int rc; 148 149 if (!context) { 150 MSG_ERR("DBUS Internal Error\n"); 151 return -EINVAL; 152 } 153 154 rc = context->protocol->reset(context); 155 if (rc < 0) { 156 return rc; 157 } 158 159 rc = sd_bus_message_new_method_return(m, &n); 160 if (rc < 0) { 161 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 162 return rc; 163 } 164 165 return sd_bus_send(NULL, n, NULL); 166 } 167 168 static int transport_dbus_get_info(sd_bus_message *m, void *userdata, 169 sd_bus_error *ret_error) 170 { 171 struct mbox_context *context = userdata; 172 struct protocol_get_info io; 173 sd_bus_message *n; 174 int rc; 175 176 if (!context) { 177 MSG_ERR("DBUS Internal Error\n"); 178 return -EINVAL; 179 } 180 181 rc = sd_bus_message_read_basic(m, 'y', &io.req.api_version); 182 if (rc < 0) { 183 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 184 return rc; 185 } 186 187 rc = context->protocol->get_info(context, &io); 188 if (rc < 0) { 189 return rc; 190 } 191 192 /* Switch transport to DBus. This is fine as DBus signals are async */ 193 context->transport = &transport_dbus_ops; 194 /* A bit messy, but we need the correct event mask */ 195 protocol_events_set(context, context->bmc_events); 196 197 rc = sd_bus_message_new_method_return(m, &n); 198 if (rc < 0) { 199 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 200 return rc; 201 } 202 203 if (API_VERSION_2 != io.resp.api_version) { 204 MSG_ERR("Unsupported protocol version for DBus transport: %d\n", 205 io.resp.api_version); 206 return rc; 207 } 208 209 rc = sd_bus_message_append(n, "yyq", 210 io.resp.api_version, 211 io.resp.v2.block_size_shift, 212 io.resp.v2.timeout); 213 if (rc < 0) { 214 MSG_ERR("sd_bus_message_append failed!\n"); 215 return rc; 216 } 217 218 return sd_bus_send(NULL, n, NULL); 219 } 220 221 static int transport_dbus_get_flash_info(sd_bus_message *m, void *userdata, 222 sd_bus_error *ret_error) 223 { 224 struct mbox_context *context = userdata; 225 struct protocol_get_flash_info io; 226 sd_bus_message *n; 227 int rc; 228 229 if (!context) { 230 MSG_ERR("DBUS Internal Error\n"); 231 return -EINVAL; 232 } 233 234 rc = context->protocol->get_flash_info(context, &io); 235 if (rc < 0) { 236 return rc; 237 } 238 239 rc = sd_bus_message_new_method_return(m, &n); 240 if (rc < 0) { 241 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 242 return rc; 243 } 244 245 rc = sd_bus_message_append(n, "qq", 246 io.resp.v2.flash_size, 247 io.resp.v2.erase_size); 248 if (rc < 0) { 249 MSG_ERR("sd_bus_message_append failed!\n"); 250 return rc; 251 } 252 253 return sd_bus_send(NULL, n, NULL); 254 } 255 256 static int transport_dbus_create_window(struct mbox_context *context, 257 bool ro, 258 sd_bus_message *m, 259 sd_bus_error *ret_error) 260 { 261 struct protocol_create_window io; 262 sd_bus_message *n; 263 int rc; 264 265 if (!context) { 266 MSG_ERR("DBUS Internal Error\n"); 267 return -EINVAL; 268 } 269 270 rc = sd_bus_message_read(m, "qq", &io.req.offset, &io.req.size); 271 if (rc < 0) { 272 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 273 return rc; 274 } 275 276 io.req.ro = ro; 277 rc = context->protocol->create_window(context, &io); 278 if (rc < 0) { 279 return rc; 280 } 281 282 rc = sd_bus_message_new_method_return(m, &n); 283 if (rc < 0) { 284 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 285 return rc; 286 } 287 288 rc = sd_bus_message_append(n, "qqq", 289 io.resp.lpc_address, 290 io.resp.size, 291 io.resp.offset); 292 if (rc < 0) { 293 MSG_ERR("sd_bus_message_append failed!\n"); 294 return rc; 295 } 296 297 return sd_bus_send(NULL, n, NULL); 298 } 299 300 static int transport_dbus_create_read_window(sd_bus_message *m, void *userdata, 301 sd_bus_error *ret_error) 302 { 303 struct mbox_context *context = userdata; 304 305 return transport_dbus_create_window(context, true, m, ret_error); 306 } 307 308 static int transport_dbus_create_write_window(sd_bus_message *m, void *userdata, 309 sd_bus_error *ret_error) 310 { 311 struct mbox_context *context = userdata; 312 313 return transport_dbus_create_window(context, false, m, ret_error); 314 } 315 316 static int transport_dbus_close_window(sd_bus_message *m, void *userdata, 317 sd_bus_error *ret_error) 318 { 319 struct mbox_context *context = userdata; 320 struct protocol_close io; 321 sd_bus_message *n; 322 int rc; 323 324 if (!context) { 325 MSG_ERR("DBUS Internal Error\n"); 326 return -EINVAL; 327 } 328 329 rc = sd_bus_message_read(m, "y", &io.req.flags); 330 if (rc < 0) { 331 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 332 return rc; 333 } 334 335 rc = context->protocol->close(context, &io); 336 if (rc < 0) { 337 return rc; 338 } 339 340 rc = sd_bus_message_new_method_return(m, &n); 341 if (rc < 0) { 342 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 343 return rc; 344 } 345 346 return sd_bus_send(NULL, n, NULL); 347 348 } 349 350 static int transport_dbus_mark_dirty(sd_bus_message *m, void *userdata, 351 sd_bus_error *ret_error) 352 { 353 struct mbox_context *context = userdata; 354 struct protocol_mark_dirty io; 355 sd_bus_message *n; 356 int rc; 357 358 if (!context) { 359 MSG_ERR("DBUS Internal Error\n"); 360 return -EINVAL; 361 } 362 363 rc = sd_bus_message_read(m, "qq", &io.req.v2.offset, &io.req.v2.size); 364 if (rc < 0) { 365 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 366 return rc; 367 } 368 369 rc = context->protocol->mark_dirty(context, &io); 370 if (rc < 0) { 371 return rc; 372 } 373 374 rc = sd_bus_message_new_method_return(m, &n); 375 if (rc < 0) { 376 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 377 return rc; 378 } 379 380 return sd_bus_send(NULL, n, NULL); 381 } 382 383 static int transport_dbus_write_flush(sd_bus_message *m, void *userdata, 384 sd_bus_error *ret_error) 385 { 386 struct mbox_context *context = userdata; 387 sd_bus_message *n; 388 int rc; 389 390 if (!context) { 391 MSG_ERR("DBUS Internal Error\n"); 392 return -EINVAL; 393 } 394 395 rc = context->protocol->flush(context, NULL /* No args in v2 */); 396 if (rc < 0) { 397 return rc; 398 } 399 400 rc = sd_bus_message_new_method_return(m, &n); 401 if (rc < 0) { 402 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 403 return rc; 404 } 405 406 return sd_bus_send(NULL, n, NULL); 407 } 408 409 static int transport_dbus_ack(sd_bus_message *m, void *userdata, 410 sd_bus_error *ret_error) 411 { 412 struct mbox_context *context = userdata; 413 struct protocol_ack io; 414 sd_bus_message *n; 415 int rc; 416 417 if (!context) { 418 MSG_ERR("DBUS Internal Error\n"); 419 return -EINVAL; 420 } 421 422 rc = sd_bus_message_read_basic(m, 'y', &io.req.flags); 423 if (rc < 0) { 424 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 425 return rc; 426 } 427 428 rc = context->protocol->ack(context, &io); 429 if (rc < 0) { 430 return rc; 431 } 432 433 rc = sd_bus_message_new_method_return(m, &n); 434 if (rc < 0) { 435 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 436 return rc; 437 } 438 439 return sd_bus_send(NULL, n, NULL); 440 } 441 442 static int transport_dbus_erase(sd_bus_message *m, void *userdata, 443 sd_bus_error *ret_error) 444 { 445 struct mbox_context *context = userdata; 446 struct protocol_erase io; 447 sd_bus_message *n; 448 int rc; 449 450 if (!context) { 451 MSG_ERR("DBUS Internal Error\n"); 452 return -EINVAL; 453 } 454 455 rc = sd_bus_message_read(m, "qq", &io.req.offset, &io.req.size); 456 if (rc < 0) { 457 MSG_ERR("DBUS error reading message: %s\n", strerror(-rc)); 458 return rc; 459 } 460 461 rc = context->protocol->erase(context, &io); 462 if (rc < 0) { 463 return rc; 464 } 465 466 rc = sd_bus_message_new_method_return(m, &n); 467 if (rc < 0) { 468 MSG_ERR("sd_bus_message_new_method_return failed: %d\n", rc); 469 return rc; 470 } 471 472 return sd_bus_send(NULL, n, NULL); 473 } 474 475 static int transport_dbus_get_property(sd_bus *bus, 476 const char *path, 477 const char *interface, 478 const char *property, 479 sd_bus_message *reply, 480 void *userdata, 481 sd_bus_error *ret_error) 482 { 483 struct mbox_context *context = userdata; 484 bool value; 485 486 assert(!strcmp(MBOX_DBUS_OBJECT, path)); 487 assert(!strcmp(MBOX_DBUS_PROTOCOL_IFACE_V2, interface)); 488 489 if (!strcmp("FlashControlLost", property)) { 490 value = context->bmc_events & BMC_EVENT_FLASH_CTRL_LOST; 491 } else if (!strcmp("DaemonReady", property)) { 492 value = context->bmc_events & BMC_EVENT_DAEMON_READY; 493 } else if (!strcmp("WindowReset", property)) { 494 value = context->bmc_events & BMC_EVENT_WINDOW_RESET; 495 } else if (!strcmp("ProtocolReset", property)) { 496 value = context->bmc_events & BMC_EVENT_PROTOCOL_RESET; 497 } else { 498 MSG_ERR("Unknown DBus property: %s\n", property); 499 return -EINVAL; 500 } 501 502 return sd_bus_message_append(reply, "b", value); 503 } 504 505 static const sd_bus_vtable protocol_unversioned_vtable[] = { 506 SD_BUS_VTABLE_START(0), 507 SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset, 508 SD_BUS_VTABLE_UNPRIVILEGED), 509 SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info, 510 SD_BUS_VTABLE_UNPRIVILEGED), 511 SD_BUS_METHOD("Ack", "y", NULL, &transport_dbus_ack, 512 SD_BUS_VTABLE_UNPRIVILEGED), 513 SD_BUS_VTABLE_END 514 }; 515 516 static const sd_bus_vtable protocol_v2_vtable[] = { 517 SD_BUS_VTABLE_START(0), 518 SD_BUS_METHOD("Reset", NULL, NULL, &transport_dbus_reset, 519 SD_BUS_VTABLE_UNPRIVILEGED), 520 SD_BUS_METHOD("GetInfo", "y", "yyq", &transport_dbus_get_info, 521 SD_BUS_VTABLE_UNPRIVILEGED), 522 SD_BUS_METHOD("GetFlashInfo", NULL, "qq", 523 &transport_dbus_get_flash_info, 524 SD_BUS_VTABLE_UNPRIVILEGED), 525 SD_BUS_METHOD("CreateReadWindow", "qq", "qqq", 526 &transport_dbus_create_read_window, 527 SD_BUS_VTABLE_UNPRIVILEGED), 528 SD_BUS_METHOD("CreateWriteWindow", "qq", "qqq", 529 &transport_dbus_create_write_window, 530 SD_BUS_VTABLE_UNPRIVILEGED), 531 SD_BUS_METHOD("CloseWindow", "y", NULL, &transport_dbus_close_window, 532 SD_BUS_VTABLE_UNPRIVILEGED), 533 SD_BUS_METHOD("MarkDirty", "qq", NULL, &transport_dbus_mark_dirty, 534 SD_BUS_VTABLE_UNPRIVILEGED), 535 SD_BUS_METHOD("Flush", NULL, NULL, &transport_dbus_write_flush, 536 SD_BUS_VTABLE_UNPRIVILEGED), 537 SD_BUS_METHOD("Ack", "y", NULL, &transport_dbus_ack, 538 SD_BUS_VTABLE_UNPRIVILEGED), 539 SD_BUS_METHOD("Erase", "qq", NULL, &transport_dbus_erase, 540 SD_BUS_VTABLE_UNPRIVILEGED), 541 SD_BUS_PROPERTY("FlashControlLost", "b", transport_dbus_get_property, 542 0, /* Just a pointer to struct mbox_context */ 543 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), 544 SD_BUS_PROPERTY("DaemonReady", "b", transport_dbus_get_property, 545 0, /* Just a pointer to struct mbox_context */ 546 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), 547 SD_BUS_SIGNAL("ProtocolReset", NULL, 0), 548 SD_BUS_SIGNAL("WindowReset", NULL, 0), 549 SD_BUS_PROPERTY("ProtocolReset", "b", 550 transport_dbus_get_property, 551 0, /* Just a pointer to struct mbox_context */ 552 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), 553 SD_BUS_PROPERTY("WindowReset", "b", 554 transport_dbus_get_property, 555 0, /* Just a pointer to struct mbox_context */ 556 SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), 557 SD_BUS_VTABLE_END 558 }; 559 560 int transport_dbus_init(struct mbox_context *context, 561 const struct transport_ops **ops) 562 { 563 int rc; 564 565 rc = sd_bus_add_object_vtable(context->bus, NULL, 566 MBOX_DBUS_OBJECT, 567 MBOX_DBUS_PROTOCOL_IFACE, 568 protocol_unversioned_vtable, 569 context); 570 if (rc < 0) { 571 return rc; 572 } 573 574 rc = sd_bus_add_object_vtable(context->bus, NULL, 575 MBOX_DBUS_OBJECT, 576 MBOX_DBUS_PROTOCOL_IFACE_V2, 577 protocol_v2_vtable, context); 578 if (rc < 0) { 579 return rc; 580 } 581 582 if (ops) { 583 *ops = &transport_dbus_ops; 584 } 585 586 return 0; 587 } 588 589 #define __unused __attribute__((unused)) 590 void transport_dbus_free(struct mbox_context *context __unused) 591 { 592 return; 593 } 594