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