1 /* Copyright 2015 IBM 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #include <assert.h> 17 #include <errno.h> 18 #include <fcntl.h> 19 #include <getopt.h> 20 #include <inttypes.h> 21 #include <limits.h> 22 #include <poll.h> 23 #include <stdint.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <syslog.h> 28 #include <sys/mman.h> 29 #include <sys/ioctl.h> 30 #include <sys/stat.h> 31 #include <sys/timerfd.h> 32 #include <time.h> 33 #include <unistd.h> 34 35 #include <linux/bt-bmc.h> 36 37 #include <systemd/sd-bus.h> 38 39 static const char *bt_bmc_device = "/dev/ipmi-bt-host"; 40 41 #define PREFIX "BTBRIDGED" 42 43 #define BT_BMC_PATH bt_bmc_device 44 #define BT_BMC_TIMEOUT_SEC 5 45 #define BT_MAX_MESSAGE 64 46 47 #define DBUS_NAME "org.openbmc.HostIpmi" 48 #define OBJ_NAME "/org/openbmc/HostIpmi/1" 49 50 #define SD_BUS_FD 0 51 #define BT_FD 1 52 #define TIMER_FD 2 53 #define TOTAL_FDS 3 54 55 #define MSG_OUT(f_, ...) do { if (verbosity != BT_LOG_NONE) { bt_log(LOG_INFO, f_, ##__VA_ARGS__); } } while(0) 56 #define MSG_ERR(f_, ...) do { if (verbosity != BT_LOG_NONE) { bt_log(LOG_ERR, f_, ##__VA_ARGS__); } } while(0) 57 58 struct ipmi_msg { 59 uint8_t netfn; 60 uint8_t lun; 61 uint8_t seq; 62 uint8_t cmd; 63 uint8_t cc; /* Only used on responses */ 64 uint8_t *data; 65 size_t data_len; 66 }; 67 68 struct bt_queue { 69 struct ipmi_msg req; 70 struct ipmi_msg rsp; 71 struct timespec start; 72 int expired; 73 sd_bus_message *call; 74 struct bt_queue *next; 75 }; 76 77 struct btbridged_context { 78 struct pollfd fds[TOTAL_FDS]; 79 struct sd_bus *bus; 80 struct bt_queue *bt_q; 81 }; 82 83 static void (*bt_vlog)(int p, const char *fmt, va_list args); 84 static int running = 1; 85 static enum { 86 BT_LOG_NONE = 0, 87 BT_LOG_VERBOSE, 88 BT_LOG_DEBUG 89 } verbosity; 90 91 static void bt_log_console(int p, const char *fmt, va_list args) 92 { 93 struct timespec time; 94 FILE *s = (p < LOG_WARNING) ? stdout : stderr; 95 96 clock_gettime(CLOCK_REALTIME, &time); 97 98 fprintf(s, "[%s %ld.%.9ld] ", PREFIX, time.tv_sec, time.tv_nsec); 99 100 vfprintf(s, fmt, args); 101 } 102 103 __attribute__((format(printf, 2, 3))) 104 static void bt_log(int p, const char *fmt, ...) 105 { 106 va_list args; 107 108 va_start(args, fmt); 109 bt_vlog(p, fmt, args); 110 va_end(args); 111 } 112 113 static struct bt_queue *bt_q_get_head(struct btbridged_context *context) 114 { 115 return context ? context->bt_q : NULL; 116 } 117 118 static struct bt_queue *bt_q_get_seq(struct btbridged_context *context, uint8_t seq) 119 { 120 struct bt_queue *t; 121 122 assert(context); 123 124 t = context->bt_q; 125 126 while (t && t->req.seq != seq) 127 t = t->next; 128 129 return t; 130 } 131 132 static struct bt_queue *bt_q_get_msg(struct btbridged_context *context) 133 { 134 struct bt_queue *t; 135 136 assert(context); 137 138 t = context->bt_q; 139 140 while (t && (!t->call && !t->expired)) 141 t = t->next; 142 143 return t; 144 } 145 146 static struct bt_queue *bt_q_enqueue(struct btbridged_context *context, uint8_t *bt_data) 147 { 148 struct bt_queue *n; 149 struct bt_queue *bt_q; 150 int len; 151 152 assert(context && bt_data); 153 154 /* 155 * len here is the length of the array. 156 * Helpfully BT doesn't count the length byte 157 */ 158 len = bt_data[0] + 1; 159 if (len < 4) { 160 MSG_ERR("Trying to queue a BT message with a short length (%d)\n", len); 161 return NULL; 162 } 163 164 bt_q = context->bt_q; 165 166 n = calloc(1, sizeof(struct bt_queue)); 167 if (!n) 168 return NULL; 169 170 if (verbosity == BT_LOG_DEBUG) { 171 n->req.data = malloc(len - 4); 172 if (n->req.data) 173 n->req.data = memcpy(n->req.data, bt_data + 4, len - 4); 174 } 175 n->req.data_len = len - 4; 176 /* Don't count the lenfn/ln, seq and command */ 177 n->req.netfn = bt_data[1] >> 2; 178 n->req.lun = bt_data[1] & 0x3; 179 n->req.seq = bt_data[2]; 180 n->req.cmd = bt_data[3]; 181 if (clock_gettime(CLOCK_MONOTONIC, &n->start) == -1) { 182 MSG_ERR("Couldn't clock_gettime(): %s\n", strerror(errno)); 183 free(n); 184 return NULL; 185 } 186 if (!bt_q) { 187 context->bt_q = n; 188 } else { 189 struct bt_queue *t = bt_q; 190 191 while (t->next) 192 t = t->next; 193 194 t->next = n; 195 } 196 197 return n; 198 } 199 200 static void bt_q_free(struct bt_queue *bt_q) 201 { 202 if (!bt_q) 203 return; 204 205 /* Unrefing sd_bus_message should free(rsp.data) */ 206 if (bt_q->call) 207 sd_bus_message_unref(bt_q->call); 208 209 free(bt_q->req.data); 210 free(bt_q); 211 } 212 213 static struct bt_queue *bt_q_drop(struct btbridged_context *context, struct bt_queue *element) 214 { 215 struct bt_queue *r; 216 217 assert(context); 218 219 if (!element || !context || !context->bt_q) 220 return NULL; 221 222 if (element == context->bt_q) { 223 context->bt_q = context->bt_q->next; 224 } else { 225 r = context->bt_q; 226 while (r && r->next != element) 227 r = r->next; 228 229 if (!r) { 230 MSG_ERR("Didn't find element %p in queue\n", element); 231 bt_q_free(element); 232 return NULL; 233 } 234 r->next = r->next->next; 235 } 236 bt_q_free(element); 237 238 return context->bt_q; 239 } 240 241 static struct bt_queue *bt_q_dequeue(struct btbridged_context *context) 242 { 243 struct bt_queue *r; 244 struct bt_queue *bt_q; 245 246 assert(context); 247 248 bt_q = context->bt_q; 249 if (!bt_q) { 250 MSG_ERR("Dequeuing empty queue!\n"); 251 return NULL; 252 } 253 254 r = bt_q->next; 255 bt_q_free(bt_q); 256 context->bt_q = r; 257 258 return r; 259 } 260 261 static int method_send_sms_atn(sd_bus_message *msg, void *userdata, 262 sd_bus_error *ret_error) 263 { 264 int r; 265 struct btbridged_context *bt_fd = userdata; 266 267 MSG_OUT("Sending SMS_ATN ioctl (%d) to %s\n", 268 BT_BMC_IOCTL_SMS_ATN, BT_BMC_PATH); 269 270 r = ioctl(bt_fd->fds[BT_FD].fd, BT_BMC_IOCTL_SMS_ATN); 271 if (r == -1) { 272 r = errno; 273 MSG_ERR("Couldn't ioctl() to 0x%x, %s: %s\n", bt_fd->fds[BT_FD].fd, BT_BMC_PATH, strerror(r)); 274 return sd_bus_reply_method_errno(msg, errno, ret_error); 275 } 276 277 r = 0; 278 return sd_bus_reply_method_return(msg, "x", r); 279 } 280 281 static int method_send_message(sd_bus_message *msg, void *userdata, sd_bus_error *ret_error) 282 { 283 struct btbridged_context *context; 284 struct bt_queue *bt_msg; 285 uint8_t *data; 286 size_t data_sz; 287 uint8_t netfn, lun, seq, cmd, cc; 288 /* 289 * Doesn't say it anywhere explicitly but it looks like returning 0 or 290 * negative is BAD... 291 */ 292 int r = 1; 293 294 context = (struct btbridged_context *)userdata; 295 if (!context) { 296 sd_bus_error_set_const(ret_error, "org.openbmc.error", "Internal error"); 297 r = 0; 298 goto out; 299 } 300 r = sd_bus_message_read(msg, "yyyyy", &seq, &netfn, &lun, &cmd, &cc); 301 if (r < 0) { 302 MSG_ERR("Couldn't parse leading bytes of message: %s\n", strerror(-r)); 303 sd_bus_error_set_const(ret_error, "org.openbmc.error", "Bad message"); 304 r = -EINVAL; 305 goto out; 306 } 307 r = sd_bus_message_read_array(msg, 'y', (const void **)&data, &data_sz); 308 if (r < 0) { 309 MSG_ERR("Couldn't parse data bytes of message: %s\n", strerror(-r)); 310 sd_bus_error_set_const(ret_error, "org.openbmc.error", "Bad message data"); 311 r = -EINVAL; 312 goto out; 313 } 314 315 bt_msg = bt_q_get_seq(context, seq); 316 if (!bt_msg) { 317 sd_bus_error_set_const(ret_error, "org.openbmc.error", "No matching request"); 318 MSG_ERR("Failed to find matching request for dbus method with seq: 0x%02x\n", seq); 319 r = -EINVAL; 320 goto out; 321 } 322 MSG_OUT("Received a dbus response for msg with seq 0x%02x\n", seq); 323 bt_msg->call = sd_bus_message_ref(msg); 324 bt_msg->rsp.netfn = netfn; 325 bt_msg->rsp.lun = lun; 326 bt_msg->rsp.seq = seq; 327 bt_msg->rsp.cmd = cmd; 328 bt_msg->rsp.cc = cc; 329 bt_msg->rsp.data_len = data_sz; 330 /* Because we've ref'ed the msg, I hope we don't need to memcpy data */ 331 bt_msg->rsp.data = data; 332 333 /* Now that we have a response */ 334 context->fds[BT_FD].events |= POLLOUT; 335 336 out: 337 return r; 338 } 339 340 static int bt_host_write(struct btbridged_context *context, struct bt_queue *bt_msg) 341 { 342 struct bt_queue *head; 343 uint8_t data[BT_MAX_MESSAGE] = { 0 }; 344 sd_bus_message *msg = NULL; 345 int r = 0, len; 346 347 assert(context); 348 349 if (!bt_msg) 350 return -EINVAL; 351 352 head = bt_q_get_head(context); 353 if (bt_msg == head) { 354 struct itimerspec ts; 355 /* Need to adjust the timer */ 356 ts.it_interval.tv_sec = 0; 357 ts.it_interval.tv_nsec = 0; 358 if (head->next) { 359 ts.it_value = head->next->start; 360 ts.it_value.tv_sec += BT_BMC_TIMEOUT_SEC; 361 MSG_OUT("Adjusting timer for next element\n"); 362 } else { 363 ts.it_value.tv_nsec = 0; 364 ts.it_value.tv_sec = 0; 365 MSG_OUT("Disabling timer, no elements remain in queue\n"); 366 } 367 r = timerfd_settime(context->fds[TIMER_FD].fd, TFD_TIMER_ABSTIME, &ts, NULL); 368 if (r == -1) 369 MSG_ERR("Couldn't set timerfd\n"); 370 } 371 data[1] = (bt_msg->rsp.netfn << 2) | (bt_msg->rsp.lun & 0x3); 372 data[2] = bt_msg->rsp.seq; 373 data[3] = bt_msg->rsp.cmd; 374 data[4] = bt_msg->rsp.cc; 375 if (bt_msg->rsp.data_len > sizeof(data) - 5) { 376 MSG_ERR("Response message size (%zu) too big, truncating\n", bt_msg->rsp.data_len); 377 bt_msg->rsp.data_len = sizeof(data) - 5; 378 } 379 /* netfn/len + seq + cmd + cc = 4 */ 380 data[0] = bt_msg->rsp.data_len + 4; 381 if (bt_msg->rsp.data_len) 382 memcpy(data + 5, bt_msg->rsp.data, bt_msg->rsp.data_len); 383 /* Count the data[0] byte */ 384 len = write(context->fds[BT_FD].fd, data, data[0] + 1); 385 if (len == -1) { 386 r = errno; 387 MSG_ERR("Error writing to %s: %s\n", BT_BMC_PATH, strerror(errno)); 388 if (bt_msg->call) { 389 r = sd_bus_message_new_method_errno(bt_msg->call, &msg, r, NULL); 390 if (r < 0) 391 MSG_ERR("Couldn't create response error\n"); 392 } 393 goto out; 394 } else { 395 if (len != data[0] + 1) 396 MSG_ERR("Possible short write to %s, desired len: %d, written len: %d\n", BT_BMC_PATH, data[0] + 1, len); 397 else 398 MSG_OUT("Successfully wrote %d of %d bytes to %s\n", len, data[0] + 1, BT_BMC_PATH); 399 400 if (bt_msg->call) { 401 r = sd_bus_message_new_method_return(bt_msg->call, &msg); 402 if (r < 0) { 403 MSG_ERR("Couldn't create response message\n"); 404 goto out; 405 } 406 r = 0; /* Just to be explicit about what we're sending back */ 407 r = sd_bus_message_append(msg, "x", r); 408 if (r < 0) { 409 MSG_ERR("Couldn't append result to response\n"); 410 goto out; 411 } 412 413 } 414 } 415 416 out: 417 if (bt_msg->call) { 418 if (sd_bus_send(context->bus, msg, NULL) < 0) 419 MSG_ERR("Couldn't send response message\n"); 420 sd_bus_message_unref(msg); 421 } 422 bt_q_drop(context, bt_msg); 423 424 /* 425 * There isn't another message ready to be sent so turn off POLLOUT 426 */ 427 if (!bt_q_get_msg(context)) { 428 MSG_OUT("Turning off POLLOUT for the BT in poll()\n"); 429 context->fds[BT_FD].events = POLLIN; 430 } 431 432 return r; 433 } 434 435 static int dispatch_timer(struct btbridged_context *context) 436 { 437 int r = 0; 438 if (context->fds[TIMER_FD].revents & POLLIN) { 439 struct bt_queue *head; 440 sd_bus_message *msg; 441 uint64_t counter; 442 443 /* Empty out timerfd so we won't trigger POLLIN continuously */ 444 r = read(context->fds[TIMER_FD].fd, &counter, sizeof(counter)); 445 MSG_OUT("Timer fired %" PRIu64 " times\n", counter); 446 447 head = bt_q_get_head(context); 448 if (!head) { 449 /* Odd, timer expired but we didn't have a message to timeout */ 450 MSG_ERR("No message found to send timeout\n"); 451 return 0; 452 } 453 if (head->call) { 454 r = sd_bus_message_new_method_errno(head->call, &msg, ETIMEDOUT, NULL); 455 if (r < 0) { 456 MSG_ERR("Couldn't create response error\n"); 457 } else { 458 if (sd_bus_send(context->bus, msg, NULL) < 0) 459 MSG_ERR("Couldn't send response message\n"); 460 sd_bus_message_unref(msg); 461 } 462 MSG_ERR("Message with seq 0x%02x is being timed out despite " 463 "appearing to have been responded to. Slow BT?\n", head->rsp.seq); 464 } 465 466 /* Set expiry */ 467 head->expired = 1; 468 head->rsp.seq = head->req.seq; 469 head->rsp.netfn = head->req.netfn + 1; 470 head->rsp.lun = head->req.lun; 471 head->rsp.cc = 0xce; /* Command response could not be provided */ 472 head->rsp.cmd = head->req.cmd; 473 /* These should already be zeroed but best to be sure */ 474 head->rsp.data_len = 0; 475 head->rsp.data = NULL; 476 head->call = NULL; 477 MSG_OUT("Timeout on msg with seq: 0x%02x\n", head->rsp.seq); 478 /* Turn on POLLOUT so we'll write this one next */ 479 context->fds[BT_FD].events |= POLLOUT; 480 } 481 482 return 0; 483 } 484 485 static int dispatch_sd_bus(struct btbridged_context *context) 486 { 487 int r = 0; 488 if (context->fds[SD_BUS_FD].revents) { 489 r = sd_bus_process(context->bus, NULL); 490 if (r > 0) 491 MSG_OUT("Processed %d dbus events\n", r); 492 } 493 494 return r; 495 } 496 497 static int dispatch_bt(struct btbridged_context *context) 498 { 499 int err = 0; 500 int r = 0; 501 502 assert(context); 503 504 if (context->fds[BT_FD].revents & POLLIN) { 505 sd_bus_message *msg; 506 struct bt_queue *new; 507 uint8_t data[BT_MAX_MESSAGE] = { 0 }; 508 509 r = read(context->fds[BT_FD].fd, data, sizeof(data)); 510 if (r < 0) { 511 MSG_ERR("Couldn't read from bt: %s\n", strerror(-r)); 512 goto out1; 513 } 514 if (r < data[0] + 1) { 515 MSG_ERR("Short read from bt (%d vs %d)\n", r, data[0] + 1); 516 r = 0; 517 goto out1; 518 } 519 520 new = bt_q_enqueue(context, data); 521 if (!new) { 522 r = -ENOMEM; 523 goto out1; 524 } 525 if (new == bt_q_get_head(context)) { 526 struct itimerspec ts; 527 /* 528 * Enqueued onto an empty list, setup a timer for sending a 529 * timeout 530 */ 531 ts.it_interval.tv_sec = 0; 532 ts.it_interval.tv_nsec = 0; 533 ts.it_value.tv_nsec = 0; 534 ts.it_value.tv_sec = BT_BMC_TIMEOUT_SEC; 535 r = timerfd_settime(context->fds[TIMER_FD].fd, 0, &ts, NULL); 536 if (r == -1) 537 MSG_ERR("Couldn't set timerfd\n"); 538 } 539 540 r = sd_bus_message_new_signal(context->bus, &msg, OBJ_NAME, DBUS_NAME, "ReceivedMessage"); 541 if (r < 0) { 542 MSG_ERR("Failed to create signal: %s\n", strerror(-r)); 543 goto out1; 544 } 545 546 r = sd_bus_message_append(msg, "yyyy", new->req.seq, new->req.netfn, new->req.lun, new->req.cmd); 547 if (r < 0) { 548 MSG_ERR("Couldn't append to signal: %s\n", strerror(-r)); 549 goto out1_free; 550 } 551 552 r = sd_bus_message_append_array(msg, 'y', data + 4, new->req.data_len); 553 if (r < 0) { 554 MSG_ERR("Couldn't append array to signal: %s\n", strerror(-r)); 555 goto out1_free; 556 } 557 558 MSG_OUT("Sending dbus signal with seq 0x%02x, netfn 0x%02x, lun 0x%02x, cmd 0x%02x\n", 559 new->req.seq, new->req.netfn, new->req.lun, new->req.cmd); 560 561 if (verbosity == BT_LOG_DEBUG) { 562 int i; 563 for (i = 0; i < new->req.data_len; i++) { 564 if (i % 8 == 0) { 565 if (i) 566 printf("\n"); 567 MSG_OUT("\t"); 568 } 569 printf("0x%02x ", data[i + 4]); 570 } 571 if (new->req.data_len) 572 printf("\n"); 573 } 574 575 /* Note we only actually keep the request data in the queue when debugging */ 576 r = sd_bus_send(context->bus, msg, NULL); 577 if (r < 0) { 578 MSG_ERR("Couldn't emit dbus signal: %s\n", strerror(-r)); 579 goto out1_free; 580 } 581 r = 0; 582 out1_free: 583 sd_bus_message_unref(msg); 584 out1: 585 err = r; 586 } 587 588 if (context->fds[BT_FD].revents & POLLOUT) { 589 struct bt_queue *bt_msg; 590 bt_msg = bt_q_get_msg(context); 591 if (!bt_msg) { 592 /* Odd, this shouldn't really happen */ 593 MSG_ERR("Got a POLLOUT but no message is ready to be written\n"); 594 r = 0; 595 goto out; 596 } 597 r = bt_host_write(context, bt_msg); 598 if (r < 0) 599 MSG_ERR("Problem putting request with seq 0x%02x, netfn 0x%02x, lun 0x%02x, cmd 0x%02x, cc 0x%02x\n" 600 "out to %s", bt_msg->rsp.seq, bt_msg->rsp.netfn, bt_msg->rsp.lun, 601 bt_msg->rsp.cmd, bt_msg->rsp.cc, BT_BMC_PATH); 602 else 603 MSG_OUT("Completed request with seq 0x%02x, netfn 0x%02x, lun 0x%02x, cmd 0x%02x, cc 0x%02x\n", 604 bt_msg->rsp.seq, bt_msg->rsp.netfn, bt_msg->rsp.lun, bt_msg->rsp.cmd, bt_msg->rsp.cc); 605 } 606 out: 607 return err ? err : r; 608 } 609 610 static void usage(const char *name) 611 { 612 fprintf(stderr, "\ 613 Usage %s [--v[v] | --syslog] [-d <DEVICE>]\n\ 614 --v Be verbose\n\ 615 --vv Be verbose and dump entire messages\n\ 616 -s, --syslog Log output to syslog (pointless without --verbose)\n\ 617 -d, --device <DEVICE> use <DEVICE> file. Default is '%s'\n\n", 618 name, bt_bmc_device); 619 } 620 621 static const sd_bus_vtable ipmid_vtable[] = { 622 SD_BUS_VTABLE_START(0), 623 SD_BUS_METHOD("sendMessage", "yyyyyay", "x", &method_send_message, SD_BUS_VTABLE_UNPRIVILEGED), 624 SD_BUS_METHOD("setAttention", "", "x", &method_send_sms_atn, SD_BUS_VTABLE_UNPRIVILEGED), 625 SD_BUS_SIGNAL("ReceivedMessage", "yyyyay", 0), 626 SD_BUS_VTABLE_END 627 }; 628 629 int main(int argc, char *argv[]) { 630 struct btbridged_context *context; 631 const char *name = argv[0]; 632 int opt, polled, r; 633 634 static const struct option long_options[] = { 635 { "device", required_argument, NULL, 'd' }, 636 { "v", no_argument, (int *)&verbosity, BT_LOG_VERBOSE }, 637 { "vv", no_argument, (int *)&verbosity, BT_LOG_DEBUG }, 638 { "syslog", no_argument, 0, 's' }, 639 { 0, 0, 0, 0 } 640 }; 641 642 context = calloc(1, sizeof(*context)); 643 644 bt_vlog = &bt_log_console; 645 while ((opt = getopt_long(argc, argv, "", long_options, NULL)) != -1) { 646 switch (opt) { 647 case 0: 648 break; 649 case 'd': 650 bt_bmc_device = optarg; 651 break; 652 case 's': 653 /* Avoid a double openlog() */ 654 if (bt_vlog != &vsyslog) { 655 openlog(PREFIX, LOG_ODELAY, LOG_DAEMON); 656 bt_vlog = &vsyslog; 657 } 658 break; 659 default: 660 usage(name); 661 exit(EXIT_FAILURE); 662 } 663 } 664 665 if (verbosity == BT_LOG_VERBOSE) 666 MSG_OUT("Verbose logging\n"); 667 668 if (verbosity == BT_LOG_DEBUG) 669 MSG_OUT("Debug logging\n"); 670 671 MSG_OUT("Starting\n"); 672 r = sd_bus_default_system(&context->bus); 673 if (r < 0) { 674 MSG_ERR("Failed to connect to system bus: %s\n", strerror(-r)); 675 goto finish; 676 } 677 678 MSG_OUT("Registering dbus methods/signals\n"); 679 r = sd_bus_add_object_vtable(context->bus, 680 NULL, 681 OBJ_NAME, 682 DBUS_NAME, 683 ipmid_vtable, 684 context); 685 if (r < 0) { 686 MSG_ERR("Failed to issue method call: %s\n", strerror(-r)); 687 goto finish; 688 } 689 690 MSG_OUT("Requesting dbus name: %s\n", DBUS_NAME); 691 r = sd_bus_request_name(context->bus, DBUS_NAME, SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING); 692 if (r < 0) { 693 MSG_ERR("Failed to acquire service name: %s\n", strerror(-r)); 694 goto finish; 695 } 696 697 MSG_OUT("Getting dbus file descriptors\n"); 698 context->fds[SD_BUS_FD].fd = sd_bus_get_fd(context->bus); 699 if (context->fds[SD_BUS_FD].fd < 0) { 700 r = -errno; 701 MSG_OUT("Couldn't get the bus file descriptor: %s\n", strerror(errno)); 702 goto finish; 703 } 704 705 MSG_OUT("Opening %s\n", BT_BMC_PATH); 706 context->fds[BT_FD].fd = open(BT_BMC_PATH, O_RDWR | O_NONBLOCK); 707 if (context->fds[BT_FD].fd < 0) { 708 r = -errno; 709 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n", BT_BMC_PATH, strerror(errno)); 710 goto finish; 711 } 712 713 MSG_OUT("Creating timer fd\n"); 714 context->fds[TIMER_FD].fd = timerfd_create(CLOCK_MONOTONIC, 0); 715 if (context->fds[TIMER_FD].fd < 0) { 716 r = -errno; 717 MSG_ERR("Couldn't create timer fd: %s\n", strerror(errno)); 718 goto finish; 719 } 720 context->fds[SD_BUS_FD].events = POLLIN; 721 context->fds[BT_FD].events = POLLIN; 722 context->fds[TIMER_FD].events = POLLIN; 723 724 MSG_OUT("Entering polling loop\n"); 725 726 while (running) { 727 polled = poll(context->fds, TOTAL_FDS, 1000); 728 if (polled == 0) 729 continue; 730 if (polled < 0) { 731 r = -errno; 732 MSG_ERR("Error from poll(): %s\n", strerror(errno)); 733 goto finish; 734 } 735 r = dispatch_sd_bus(context); 736 if (r < 0) { 737 MSG_ERR("Error handling dbus event: %s\n", strerror(-r)); 738 goto finish; 739 } 740 r = dispatch_bt(context); 741 if (r < 0) { 742 MSG_ERR("Error handling BT event: %s\n", strerror(-r)); 743 goto finish; 744 } 745 r = dispatch_timer(context); 746 if (r < 0) { 747 MSG_ERR("Error handling timer event: %s\n", strerror(-r)); 748 goto finish; 749 } 750 } 751 752 finish: 753 if (bt_q_get_head(context)) { 754 MSG_ERR("Unresponded BT Message!\n"); 755 while (bt_q_dequeue(context)); 756 } 757 close(context->fds[BT_FD].fd); 758 close(context->fds[TIMER_FD].fd); 759 sd_bus_unref(context->bus); 760 free(context); 761 762 return r; 763 } 764 765