|
21 | 21 |
|
22 | 22 | #include <ccan/endian/endian.h> |
23 | 23 |
|
| 24 | +#ifdef CONFIG_LIBSYSTEMD |
| 25 | +#include <systemd/sd-event.h> |
| 26 | +#include <systemd/sd-bus.h> |
| 27 | +#include <systemd/sd-id128.h> |
| 28 | +#endif |
| 29 | + |
24 | 30 | #include "private.h" |
25 | 31 | #include "log.h" |
26 | 32 | #include "mi.h" |
@@ -74,6 +80,10 @@ struct nvme_mi_transport_mctp { |
74 | 80 | int sd; |
75 | 81 | }; |
76 | 82 |
|
| 83 | +#define MCTP_DBUS_PATH "/xyz/openbmc_project/mctp" |
| 84 | +#define MCTP_DBUS_IFACE "xyz.openbmc_project.MCTP" |
| 85 | +#define MCTP_DBUS_IFACE_ENDPOINT "xyz.openbmc_project.MCTP.Endpoint" |
| 86 | + |
77 | 87 | static const struct nvme_mi_transport nvme_mi_transport_mctp; |
78 | 88 |
|
79 | 89 | static int nvme_mi_mctp_submit(struct nvme_mi_ep *ep, |
@@ -245,3 +255,294 @@ nvme_mi_ep_t nvme_mi_open_mctp(nvme_root_t root, unsigned int netid, __u8 eid) |
245 | 255 | free(ep); |
246 | 256 | return NULL; |
247 | 257 | } |
| 258 | + |
| 259 | +#ifdef CONFIG_LIBSYSTEMD |
| 260 | + |
| 261 | +static void _dbus_err(nvme_root_t root, int rc, int line) { |
| 262 | + nvme_msg(root, LOG_ERR, "MCTP D-Bus failed line %d: %s %d\n", |
| 263 | + line, strerror(-rc), rc); |
| 264 | +} |
| 265 | + |
| 266 | +#define dbus_err(r, rc) _dbus_err(r, rc, __LINE__) |
| 267 | + |
| 268 | +/* Returns -EEXISTS on duplicate */ |
| 269 | +static int nvme_mi_mctp_add(nvme_root_t root, unsigned int netid, __u8 eid) |
| 270 | +{ |
| 271 | + nvme_mi_ep_t ep = NULL; |
| 272 | + |
| 273 | + /* ensure we don't already have an endpoint with the same net/eid */ |
| 274 | + list_for_each(&root->endpoints, ep, root_entry) { |
| 275 | + if (ep->transport != &nvme_mi_transport_mctp) { |
| 276 | + continue; |
| 277 | + } |
| 278 | + const struct nvme_mi_transport_mctp *t = ep->transport_data; |
| 279 | + if (t->eid == eid && t->net == netid) { |
| 280 | + return -EEXIST; |
| 281 | + } |
| 282 | + } |
| 283 | + |
| 284 | + ep = nvme_mi_open_mctp(root, netid, eid); |
| 285 | + if (!ep) { |
| 286 | + return -ENOMEM; |
| 287 | + } |
| 288 | + |
| 289 | + return 0; |
| 290 | +} |
| 291 | + |
| 292 | +/* We can't rely on sd_bus_message_enter_container() == 0 at the end of |
| 293 | + a dictionary (it returns -ENXIO) so we test separately */ |
| 294 | +static bool container_end(sd_bus_message *m) |
| 295 | +{ |
| 296 | + return sd_bus_message_peek_type(m, NULL, NULL) == 0; |
| 297 | +} |
| 298 | + |
| 299 | +static int handle_mctp_endpoint(nvme_root_t root, const char* objpath, |
| 300 | + sd_bus_message *m) |
| 301 | +{ |
| 302 | + bool have_eid = false, have_net = false, have_nvmemi = false; |
| 303 | + mctp_eid_t eid; |
| 304 | + int net; |
| 305 | + int rc; |
| 306 | + |
| 307 | + /* Iterate properties on this interface */ |
| 308 | + while (!container_end(m)) { |
| 309 | + /* Enter property dict */ |
| 310 | + rc = sd_bus_message_enter_container(m, 'a', "{sv}"); |
| 311 | + if (rc < 0) { |
| 312 | + dbus_err(root, rc); |
| 313 | + return rc; |
| 314 | + } |
| 315 | + |
| 316 | + while (!container_end(m)) { |
| 317 | + char *propname = NULL; |
| 318 | + size_t sz; |
| 319 | + const uint8_t *types = NULL; |
| 320 | + /* Enter property item */ |
| 321 | + rc = sd_bus_message_enter_container(m, 'e', "sv"); |
| 322 | + if (rc < 0) { |
| 323 | + dbus_err(root, rc); |
| 324 | + return rc; |
| 325 | + } |
| 326 | + |
| 327 | + rc = sd_bus_message_read(m, "s", &propname); |
| 328 | + if (rc < 0) { |
| 329 | + dbus_err(root, rc); |
| 330 | + return rc; |
| 331 | + } |
| 332 | + |
| 333 | + if (strcmp(propname, "EID") == 0) { |
| 334 | + rc = sd_bus_message_read(m, "v", "y", &eid); |
| 335 | + have_eid = true; |
| 336 | + } else if (strcmp(propname, "NetworkId") == 0) { |
| 337 | + rc = sd_bus_message_read(m, "v", "i", &net); |
| 338 | + have_net = true; |
| 339 | + } else if (strcmp(propname, "SupportedMessageTypes") == 0) { |
| 340 | + sd_bus_message_enter_container(m, 'v', "ay"); |
| 341 | + rc = sd_bus_message_read_array(m, 'y', (const void**)&types, &sz); |
| 342 | + if (rc >= 0) |
| 343 | + for (size_t s = 0; s < sz; s++) |
| 344 | + if (types[s] == MCTP_TYPE_NVME) |
| 345 | + have_nvmemi = true; |
| 346 | + sd_bus_message_exit_container(m); |
| 347 | + } else { |
| 348 | + rc = sd_bus_message_skip(m, "v"); |
| 349 | + } |
| 350 | + |
| 351 | + if (rc < 0) { |
| 352 | + dbus_err(root, rc); |
| 353 | + return rc; |
| 354 | + } |
| 355 | + |
| 356 | + /* Exit prop item */ |
| 357 | + rc = sd_bus_message_exit_container(m); |
| 358 | + if (rc < 0) { |
| 359 | + dbus_err(root, rc); |
| 360 | + return rc; |
| 361 | + } |
| 362 | + } |
| 363 | + |
| 364 | + /* Exit property dict */ |
| 365 | + rc = sd_bus_message_exit_container(m); |
| 366 | + if (rc < 0) { |
| 367 | + dbus_err(root, rc); |
| 368 | + return rc; |
| 369 | + } |
| 370 | + } |
| 371 | + |
| 372 | + if (have_nvmemi) { |
| 373 | + if (!(have_eid && have_net)) { |
| 374 | + nvme_msg(root, LOG_ERR, |
| 375 | + "Missing property for %s\n", objpath); |
| 376 | + return -ENOENT; |
| 377 | + } |
| 378 | + rc = nvme_mi_mctp_add(root, net, eid); |
| 379 | + if (rc < 0) { |
| 380 | + nvme_msg(root, LOG_ERR, |
| 381 | + "Error adding net %d eid %d: %s\n", |
| 382 | + net, eid, strerror(-rc)); |
| 383 | + } |
| 384 | + } else { |
| 385 | + /* Ignore other endpoints */ |
| 386 | + rc = 0; |
| 387 | + } |
| 388 | + return rc; |
| 389 | +} |
| 390 | + |
| 391 | +static int handle_mctp_obj(nvme_root_t root, sd_bus_message *m) |
| 392 | +{ |
| 393 | + char *objpath = NULL; |
| 394 | + char *ifname = NULL; |
| 395 | + int rc; |
| 396 | + |
| 397 | + rc = sd_bus_message_read(m, "o", &objpath); |
| 398 | + if (rc < 0) { |
| 399 | + dbus_err(root, rc); |
| 400 | + return rc; |
| 401 | + } |
| 402 | + |
| 403 | + /* Enter response object: our array of (string, property dict) |
| 404 | + * values */ |
| 405 | + rc = sd_bus_message_enter_container(m, 'a', "{sa{sv}}"); |
| 406 | + if (rc < 0) { |
| 407 | + dbus_err(root, rc); |
| 408 | + return rc; |
| 409 | + } |
| 410 | + |
| 411 | + |
| 412 | + /* for each interface */ |
| 413 | + while (!container_end(m)) { |
| 414 | + /* Enter interface item */ |
| 415 | + rc = sd_bus_message_enter_container(m, 'e', "sa{sv}"); |
| 416 | + if (rc < 0) { |
| 417 | + dbus_err(root, rc); |
| 418 | + return rc; |
| 419 | + } |
| 420 | + |
| 421 | + rc = sd_bus_message_read(m, "s", &ifname); |
| 422 | + if (rc < 0) { |
| 423 | + dbus_err(root, rc); |
| 424 | + return rc; |
| 425 | + } |
| 426 | + |
| 427 | + if (!strcmp(ifname, MCTP_DBUS_IFACE_ENDPOINT)) { |
| 428 | + |
| 429 | + rc = handle_mctp_endpoint(root, objpath, m); |
| 430 | + if (rc < 0) { |
| 431 | + /* continue to next object */ |
| 432 | + } |
| 433 | + } else { |
| 434 | + /* skip the interfaces we don't care about */ |
| 435 | + rc = sd_bus_message_skip(m, "a{sv}"); |
| 436 | + if (rc < 0) { |
| 437 | + dbus_err(root, rc); |
| 438 | + return rc; |
| 439 | + } |
| 440 | + } |
| 441 | + |
| 442 | + /* Exit interface item */ |
| 443 | + rc = sd_bus_message_exit_container(m); |
| 444 | + if (rc < 0) { |
| 445 | + dbus_err(root, rc); |
| 446 | + return rc; |
| 447 | + } |
| 448 | + } |
| 449 | + |
| 450 | + /* Exit response object */ |
| 451 | + rc = sd_bus_message_exit_container(m); |
| 452 | + if (rc < 0) { |
| 453 | + dbus_err(root, rc); |
| 454 | + return rc; |
| 455 | + } |
| 456 | + |
| 457 | + return 0; |
| 458 | +} |
| 459 | + |
| 460 | +nvme_root_t nvme_mi_scan_mctp(void) |
| 461 | +{ |
| 462 | + sd_bus *bus = NULL; |
| 463 | + sd_bus_message *resp = NULL; |
| 464 | + sd_bus_error berr = SD_BUS_ERROR_NULL; |
| 465 | + nvme_root_t root; |
| 466 | + int rc; |
| 467 | + |
| 468 | + root = nvme_mi_create_root(NULL, DEFAULT_LOGLEVEL); |
| 469 | + if (!root) { |
| 470 | + rc = -ENOMEM; |
| 471 | + goto out; |
| 472 | + } |
| 473 | + |
| 474 | + rc = sd_bus_default_system(&bus); |
| 475 | + if (rc < 0) { |
| 476 | + nvme_msg(root, LOG_ERR, "Failed opening D-Bus: %s\n", |
| 477 | + strerror(-rc)); |
| 478 | + goto out; |
| 479 | + } |
| 480 | + |
| 481 | + rc = sd_bus_call_method(bus, |
| 482 | + MCTP_DBUS_IFACE, |
| 483 | + MCTP_DBUS_PATH, |
| 484 | + "org.freedesktop.DBus.ObjectManager", |
| 485 | + "GetManagedObjects", |
| 486 | + &berr, |
| 487 | + &resp, |
| 488 | + ""); |
| 489 | + if (rc < 0) { |
| 490 | + nvme_msg(root, LOG_ERR, "Failed querying MCTP D-Bus: %s (%s)\n", |
| 491 | + berr.message, berr.name); |
| 492 | + goto out; |
| 493 | + } |
| 494 | + |
| 495 | + rc = sd_bus_message_enter_container(resp, 'a', "{oa{sa{sv}}}"); |
| 496 | + if (rc != 1) { |
| 497 | + dbus_err(root, rc); |
| 498 | + if (rc == 0) |
| 499 | + rc = -EPROTO; |
| 500 | + goto out; |
| 501 | + } |
| 502 | + |
| 503 | + /* Iterate over all managed objects */ |
| 504 | + while (!container_end(resp)) { |
| 505 | + rc = sd_bus_message_enter_container(resp, 'e', "oa{sa{sv}}"); |
| 506 | + if (rc < 0) { |
| 507 | + dbus_err(root, rc); |
| 508 | + goto out; |
| 509 | + } |
| 510 | + |
| 511 | + handle_mctp_obj(root, resp); |
| 512 | + |
| 513 | + rc = sd_bus_message_exit_container(resp); |
| 514 | + if (rc < 0) { |
| 515 | + dbus_err(root, rc); |
| 516 | + goto out; |
| 517 | + } |
| 518 | + } |
| 519 | + |
| 520 | + rc = sd_bus_message_exit_container(resp); |
| 521 | + if (rc < 0) { |
| 522 | + dbus_err(root, rc); |
| 523 | + goto out; |
| 524 | + } |
| 525 | + rc = 0; |
| 526 | + |
| 527 | +out: |
| 528 | + sd_bus_error_free(&berr); |
| 529 | + sd_bus_message_unref(resp); |
| 530 | + sd_bus_unref(bus); |
| 531 | + |
| 532 | + if (rc < 0) { |
| 533 | + if (root) { |
| 534 | + nvme_mi_free_root(root); |
| 535 | + } |
| 536 | + root = NULL; |
| 537 | + } |
| 538 | + return root; |
| 539 | +} |
| 540 | + |
| 541 | +#else /* CONFIG_LIBSYSTEMD */ |
| 542 | + |
| 543 | +nvme_root_t nvme_mi_scan_mctp(void) |
| 544 | +{ |
| 545 | + return NULL; |
| 546 | +} |
| 547 | + |
| 548 | +#endif /* CONFIG_LIBSYSTEMD */ |
0 commit comments