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