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