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