proxy.c revision b5519a1fede5ea4f480c788789f957d9af80efc6
1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org> 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24#ifdef HAVE_CONFIG_H 25#include <config.h> 26#endif 27 28#include <ctype.h> 29#include <dirent.h> 30#include <errno.h> 31#include <fcntl.h> 32#include <stdio.h> 33#include <stdlib.h> 34#include <string.h> 35#include <termios.h> 36#include <unistd.h> 37#include <arpa/inet.h> 38#include <sys/param.h> 39#include <sys/ioctl.h> 40#include <sys/stat.h> 41#include <sys/types.h> 42#include <sys/un.h> 43 44#include <bluetooth/bluetooth.h> 45#include <bluetooth/hci.h> 46#include <bluetooth/hci_lib.h> 47#include <bluetooth/sdp.h> 48#include <bluetooth/sdp_lib.h> 49#include <bluetooth/rfcomm.h> 50 51#include <glib.h> 52#include <gdbus.h> 53 54#include "../src/dbus-common.h" 55 56#include "logging.h" 57#include "textfile.h" 58 59#include "error.h" 60#include "storage.h" 61#include "sdpd.h" 62#include "glib-helper.h" 63#include "btio.h" 64#include "proxy.h" 65 66#define SERIAL_PORT_NAME "spp" 67#define SERIAL_PORT_UUID "00001101-0000-1000-8000-00805F9B34FB" 68 69#define DIALUP_NET_NAME "dun" 70#define DIALUP_NET_UUID "00001103-0000-1000-8000-00805F9B34FB" 71 72#define SERIAL_PROXY_INTERFACE "org.bluez.SerialProxy" 73#define SERIAL_MANAGER_INTERFACE "org.bluez.SerialProxyManager" 74#define BUF_SIZE 1024 75 76typedef enum { 77 TTY_PROXY, 78 UNIX_SOCKET_PROXY, 79 TCP_SOCKET_PROXY, 80 UNKNOWN_PROXY_TYPE = 0xFF 81} proxy_type_t; 82 83struct serial_adapter { 84 bdaddr_t src; /* Adapter address */ 85 char *path; /* D-Bus path */ 86 DBusConnection *conn; /* Adapter connection */ 87 GSList *proxies; /* Proxies list */ 88}; 89 90struct serial_proxy { 91 bdaddr_t dst; /* Remote address */ 92 char *path; /* Proxy path */ 93 char *uuid128; /* UUID 128 */ 94 char *address; /* TTY or Unix socket name */ 95 short int port; /* TCP port */ 96 proxy_type_t type; /* TTY or Unix socket */ 97 struct termios sys_ti; /* Default TTY setting */ 98 struct termios proxy_ti; /* Proxy TTY settings */ 99 uint8_t channel; /* RFCOMM channel */ 100 uint32_t record_id; /* Service record id */ 101 GIOChannel *io; /* Server listen */ 102 guint rfcomm_watch; /* RFCOMM watch: Remote */ 103 guint local_watch; /* Local watch: TTY or Unix socket */ 104 struct serial_adapter *adapter; /* Adapter pointer */ 105}; 106 107static GSList *adapters = NULL; 108static int sk_counter = 0; 109 110static void disable_proxy(struct serial_proxy *prx) 111{ 112 if (prx->rfcomm_watch) { 113 g_source_remove(prx->rfcomm_watch); 114 prx->rfcomm_watch = 0; 115 } 116 117 if (prx->local_watch) { 118 g_source_remove(prx->local_watch); 119 prx->local_watch = 0; 120 } 121 122 remove_record_from_server(prx->record_id); 123 prx->record_id = 0; 124 125 g_io_channel_unref(prx->io); 126 prx->io = NULL; 127} 128 129static void proxy_free(struct serial_proxy *prx) 130{ 131 g_free(prx->path); 132 g_free(prx->address); 133 g_free(prx->uuid128); 134 g_free(prx); 135} 136 137static inline DBusMessage *does_not_exist(DBusMessage *msg, 138 const char *description) 139{ 140 return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExist", 141 description); 142} 143 144static inline DBusMessage *invalid_arguments(DBusMessage *msg, 145 const char *description) 146{ 147 return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments", 148 description); 149} 150 151static inline DBusMessage *failed(DBusMessage *msg, const char *description) 152{ 153 return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", 154 description); 155} 156 157static void add_lang_attr(sdp_record_t *r) 158{ 159 sdp_lang_attr_t base_lang; 160 sdp_list_t *langs = 0; 161 162 /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */ 163 base_lang.code_ISO639 = (0x65 << 8) | 0x6e; 164 base_lang.encoding = 106; 165 base_lang.base_offset = SDP_PRIMARY_LANG_BASE; 166 langs = sdp_list_append(0, &base_lang); 167 sdp_set_lang_attr(r, langs); 168 sdp_list_free(langs, 0); 169} 170 171static sdp_record_t *proxy_record_new(const char *uuid128, uint8_t channel) 172{ 173 sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id; 174 uuid_t uuid, root_uuid, l2cap, rfcomm; 175 sdp_profile_desc_t profile; 176 sdp_record_t *record; 177 sdp_data_t *ch; 178 179 record = sdp_record_alloc(); 180 if (!record) 181 return NULL; 182 183 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); 184 root = sdp_list_append(NULL, &root_uuid); 185 sdp_set_browse_groups(record, root); 186 sdp_list_free(root, NULL); 187 188 bt_string2uuid(&uuid, uuid128); 189 svclass_id = sdp_list_append(NULL, &uuid); 190 sdp_set_service_classes(record, svclass_id); 191 sdp_list_free(svclass_id, NULL); 192 193 sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID); 194 profile.version = 0x0100; 195 profiles = sdp_list_append(NULL, &profile); 196 sdp_set_profile_descs(record, profiles); 197 sdp_list_free(profiles, NULL); 198 199 sdp_uuid16_create(&l2cap, L2CAP_UUID); 200 proto[0] = sdp_list_append(NULL, &l2cap); 201 apseq = sdp_list_append(NULL, proto[0]); 202 203 sdp_uuid16_create(&rfcomm, RFCOMM_UUID); 204 proto[1] = sdp_list_append(NULL, &rfcomm); 205 ch = sdp_data_alloc(SDP_UINT8, &channel); 206 proto[1] = sdp_list_append(proto[1], ch); 207 apseq = sdp_list_append(apseq, proto[1]); 208 209 aproto = sdp_list_append(NULL, apseq); 210 sdp_set_access_protos(record, aproto); 211 212 add_lang_attr(record); 213 214 sdp_set_info_attr(record, "Port Proxy Entity", 215 NULL, "Port Proxy Entity"); 216 217 sdp_data_free(ch); 218 sdp_list_free(proto[0], NULL); 219 sdp_list_free(proto[1], NULL); 220 sdp_list_free(apseq, NULL); 221 sdp_list_free(aproto, NULL); 222 223 return record; 224} 225 226static GIOError channel_write(GIOChannel *chan, char *buf, size_t size) 227{ 228 GIOError err = G_IO_ERROR_NONE; 229 gsize wbytes, written; 230 231 wbytes = written = 0; 232 while (wbytes < size) { 233 err = g_io_channel_write(chan, 234 buf + wbytes, 235 size - wbytes, 236 &written); 237 238 if (err != G_IO_ERROR_NONE) 239 return err; 240 241 wbytes += written; 242 } 243 244 return err; 245} 246 247static gboolean forward_data(GIOChannel *chan, GIOCondition cond, gpointer data) 248{ 249 char buf[BUF_SIZE]; 250 GIOChannel *dest = data; 251 GIOError err; 252 size_t rbytes; 253 254 if (cond & G_IO_NVAL) 255 return FALSE; 256 257 if (cond & (G_IO_HUP | G_IO_ERR)) { 258 /* Try forward remaining data */ 259 do { 260 rbytes = 0; 261 err = g_io_channel_read(chan, buf, sizeof(buf), &rbytes); 262 if (err != G_IO_ERROR_NONE || rbytes == 0) 263 break; 264 265 err = channel_write(dest, buf, rbytes); 266 } while (err == G_IO_ERROR_NONE); 267 268 g_io_channel_close(dest); 269 return FALSE; 270 } 271 272 rbytes = 0; 273 err = g_io_channel_read(chan, buf, sizeof(buf), &rbytes); 274 if (err != G_IO_ERROR_NONE) 275 return FALSE; 276 277 err = channel_write(dest, buf, rbytes); 278 if (err != G_IO_ERROR_NONE) 279 return FALSE; 280 281 return TRUE; 282} 283 284static inline int unix_socket_connect(const char *address) 285{ 286 struct sockaddr_un addr; 287 int err, sk; 288 289 memset(&addr, 0, sizeof(addr)); 290 addr.sun_family = PF_UNIX; 291 292 if (strncmp("x00", address, 3) == 0) { 293 /* 294 * Abstract namespace: first byte NULL, x00 295 * must be removed from the original address. 296 */ 297 strcpy(addr.sun_path + 1, address + 3); 298 } else { 299 /* Filesystem address */ 300 strcpy(addr.sun_path, address); 301 } 302 303 /* Unix socket */ 304 sk = socket(AF_UNIX, SOCK_STREAM, 0); 305 if (sk < 0) { 306 err = errno; 307 error("Unix socket(%s) create failed: %s(%d)", 308 address, strerror(err), err); 309 return -err; 310 } 311 312 if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 313 err = errno; 314 error("Unix socket(%s) connect failed: %s(%d)", 315 address, strerror(err), err); 316 close(sk); 317 errno = err; 318 return -err; 319 } 320 321 return sk; 322} 323 324static int tcp_socket_connect(const char *address) 325{ 326 struct sockaddr_in addr; 327 int err, sk; 328 unsigned short int port; 329 330 memset(&addr, 0, sizeof(addr)); 331 332 if (strncmp(address, "localhost", 9) != 0) { 333 error("Address should have the form localhost:port."); 334 return -1; 335 } 336 port = atoi(strchr(address, ':') + 1); 337 if (port <= 0) { 338 error("Invalid port '%d'.", port); 339 return -1; 340 } 341 addr.sin_family = AF_INET; 342 addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 343 addr.sin_port = htons(port); 344 345 sk = socket(PF_INET, SOCK_STREAM, 0); 346 if (sk < 0) { 347 err = errno; 348 error("TCP socket(%s) create failed %s(%d)", address, 349 strerror(err), err); 350 return -err; 351 } 352 if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 353 err = errno; 354 error("TCP socket(%s) connect failed: %s(%d)", 355 address, strerror(err), err); 356 close(sk); 357 errno = err; 358 return -err; 359 } 360 return sk; 361} 362 363static inline int tty_open(const char *tty, struct termios *ti) 364{ 365 int err, sk; 366 367 sk = open(tty, O_RDWR | O_NOCTTY); 368 if (sk < 0) { 369 err = errno; 370 error("Can't open TTY %s: %s(%d)", tty, strerror(err), err); 371 return -err; 372 } 373 374 if (ti && tcsetattr(sk, TCSANOW, ti) < 0) { 375 err = errno; 376 error("Can't change serial settings: %s(%d)", 377 strerror(err), err); 378 close(sk); 379 errno = err; 380 return -err; 381 } 382 383 return sk; 384} 385 386static void connect_event_cb(GIOChannel *chan, GError *conn_err, gpointer data) 387{ 388 struct serial_proxy *prx = data; 389 GIOChannel *io; 390 int sk; 391 GError *err = NULL; 392 393 if (conn_err) { 394 error("%s", conn_err->message); 395 return; 396 } 397 398 bt_io_get(chan, BT_IO_RFCOMM, &err, 399 BT_IO_OPT_DEST_BDADDR, &prx->dst, 400 NULL); 401 if (err) { 402 error("%s", err->message); 403 g_error_free(err); 404 return; 405 } 406 407 switch (prx->type) { 408 case UNIX_SOCKET_PROXY: 409 sk = unix_socket_connect(prx->address); 410 break; 411 case TTY_PROXY: 412 sk = tty_open(prx->address, &prx->proxy_ti); 413 break; 414 case TCP_SOCKET_PROXY: 415 sk = tcp_socket_connect(prx->address); 416 break; 417 default: 418 sk = -1; 419 } 420 421 if (sk < 0) { 422 g_io_channel_unref(chan); 423 return; 424 } 425 426 g_io_channel_set_close_on_unref(chan, TRUE); 427 io = g_io_channel_unix_new(sk); 428 g_io_channel_set_close_on_unref(io, TRUE); 429 430 prx->rfcomm_watch = g_io_add_watch(chan, 431 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, 432 forward_data, io); 433 434 prx->local_watch = g_io_add_watch(io, 435 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, 436 forward_data, chan); 437 438 g_io_channel_unref(chan); 439 g_io_channel_unref(io); 440 441 return; 442} 443 444static DBusMessage *proxy_enable(DBusConnection *conn, 445 DBusMessage *msg, void *data) 446{ 447 struct serial_proxy *prx = data; 448 struct serial_adapter *adapter = prx->adapter; 449 sdp_record_t *record; 450 GError *err = NULL; 451 452 if (prx->io) 453 return failed(msg, "Already enabled"); 454 455 /* Listen */ 456 prx->io = bt_io_listen(BT_IO_RFCOMM, connect_event_cb, NULL, prx, 457 NULL, &err, 458 BT_IO_OPT_SOURCE_BDADDR, &adapter->src, 459 BT_IO_OPT_CHANNEL, prx->channel, 460 BT_IO_OPT_INVALID); 461 if (!prx->io) { 462 DBusMessage *reply; 463 464 error("%s", err->message); 465 reply = failed(msg, err->message); 466 g_error_free(err); 467 return reply; 468 } 469 470 g_io_channel_set_close_on_unref(prx->io, TRUE); 471 472 record = proxy_record_new(prx->uuid128, prx->channel); 473 if (!record) { 474 g_io_channel_unref(prx->io); 475 return failed(msg, "Unable to allocate new service record"); 476 } 477 478 if (add_record_to_server(&adapter->src, record) < 0) { 479 sdp_record_free(record); 480 g_io_channel_unref(prx->io); 481 return failed(msg, "Service registration failed"); 482 } 483 484 prx->record_id = record->handle; 485 486 return dbus_message_new_method_return(msg); 487} 488 489static DBusMessage *proxy_disable(DBusConnection *conn, 490 DBusMessage *msg, void *data) 491{ 492 struct serial_proxy *prx = data; 493 494 if (!prx->io) 495 return failed(msg, "Not enabled"); 496 497 /* Remove the watches and unregister the record */ 498 disable_proxy(prx); 499 500 return dbus_message_new_method_return(msg); 501} 502 503static DBusMessage *proxy_get_info(DBusConnection *conn, 504 DBusMessage *msg, void *data) 505{ 506 struct serial_proxy *prx = data; 507 DBusMessage *reply; 508 DBusMessageIter iter, dict; 509 dbus_bool_t boolean; 510 511 reply = dbus_message_new_method_return(msg); 512 if (!reply) 513 return NULL; 514 515 dbus_message_iter_init_append(reply, &iter); 516 517 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 518 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING 519 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING 520 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); 521 522 dict_append_entry(&dict, "uuid", DBUS_TYPE_STRING, &prx->uuid128); 523 524 dict_append_entry(&dict, "address", DBUS_TYPE_STRING, &prx->address); 525 526 if (prx->channel) 527 dict_append_entry(&dict, "channel", 528 DBUS_TYPE_BYTE, &prx->channel); 529 530 boolean = (prx->io ? TRUE : FALSE); 531 dict_append_entry(&dict, "enabled", DBUS_TYPE_BOOLEAN, &boolean); 532 533 boolean = (prx->rfcomm_watch ? TRUE : FALSE); 534 dict_append_entry(&dict, "connected", DBUS_TYPE_BOOLEAN, &boolean); 535 536 /* If connected: append the remote address */ 537 if (boolean) { 538 char bda[18]; 539 const char *pstr = bda; 540 541 ba2str(&prx->dst, bda); 542 dict_append_entry(&dict, "address", DBUS_TYPE_STRING, &pstr); 543 } 544 545 dbus_message_iter_close_container(&iter, &dict); 546 547 return reply; 548} 549 550static struct { 551 const char *str; 552 speed_t speed; 553} supported_speed[] = { 554 {"50", B50 }, 555 {"300", B300 }, 556 {"600", B600 }, 557 {"1200", B1200 }, 558 {"1800", B1800 }, 559 {"2400", B2400 }, 560 {"4800", B4800 }, 561 {"9600", B9600 }, 562 {"19200", B19200 }, 563 {"38400", B38400 }, 564 {"57600", B57600 }, 565 {"115200", B115200 }, 566 { NULL, B0 } 567}; 568 569static speed_t str2speed(const char *str, speed_t *speed) 570{ 571 int i; 572 573 for (i = 0; supported_speed[i].str; i++) { 574 if (strcmp(supported_speed[i].str, str) != 0) 575 continue; 576 577 if (speed) 578 *speed = supported_speed[i].speed; 579 580 return supported_speed[i].speed; 581 } 582 583 return B0; 584} 585 586static int set_parity(const char *str, tcflag_t *ctrl) 587{ 588 if (strcasecmp("even", str) == 0) { 589 *ctrl |= PARENB; 590 *ctrl &= ~PARODD; 591 } else if (strcasecmp("odd", str) == 0) { 592 *ctrl |= PARENB; 593 *ctrl |= PARODD; 594 } else if (strcasecmp("mark", str) == 0) 595 *ctrl |= PARENB; 596 else if ((strcasecmp("none", str) == 0) || 597 (strcasecmp("space", str) == 0)) 598 *ctrl &= ~PARENB; 599 else 600 return -1; 601 602 return 0; 603} 604 605static int set_databits(uint8_t databits, tcflag_t *ctrl) 606{ 607 if (databits < 5 || databits > 8) 608 return -EINVAL; 609 610 *ctrl &= ~CSIZE; 611 switch (databits) { 612 case 5: 613 *ctrl |= CS5; 614 break; 615 case 6: 616 *ctrl |= CS6; 617 break; 618 case 7: 619 *ctrl |= CS7; 620 break; 621 case 8: 622 *ctrl |= CS8; 623 break; 624 } 625 626 return 0; 627} 628 629static int set_stopbits(uint8_t stopbits, tcflag_t *ctrl) 630{ 631 /* 1.5 will not be allowed */ 632 switch (stopbits) { 633 case 1: 634 *ctrl &= ~CSTOPB; 635 return 0; 636 case 2: 637 *ctrl |= CSTOPB; 638 return 0; 639 } 640 641 return -EINVAL; 642} 643 644static DBusMessage *proxy_set_serial_params(DBusConnection *conn, 645 DBusMessage *msg, void *data) 646{ 647 struct serial_proxy *prx = data; 648 struct serial_adapter *adapter = prx->adapter; 649 const char *ratestr, *paritystr; 650 uint8_t databits, stopbits; 651 tcflag_t ctrl; /* Control mode flags */ 652 speed_t speed = B0; /* In/Out speed */ 653 654 /* Don't allow change TTY settings if it is open */ 655 if (prx->local_watch) 656 return failed(msg, "Not allowed"); 657 658 if (!dbus_message_get_args(msg, NULL, 659 DBUS_TYPE_STRING, &ratestr, 660 DBUS_TYPE_BYTE, &databits, 661 DBUS_TYPE_BYTE, &stopbits, 662 DBUS_TYPE_STRING, &paritystr, 663 DBUS_TYPE_INVALID)) 664 return NULL; 665 666 if (str2speed(ratestr, &speed) == B0) 667 return invalid_arguments(msg, "Invalid baud rate"); 668 669 ctrl = prx->proxy_ti.c_cflag; 670 if (set_databits(databits, &ctrl) < 0) 671 return invalid_arguments(msg, "Invalid data bits"); 672 673 if (set_stopbits(stopbits, &ctrl) < 0) 674 return invalid_arguments(msg, "Invalid stop bits"); 675 676 if (set_parity(paritystr, &ctrl) < 0) 677 return invalid_arguments(msg, "Invalid parity"); 678 679 prx->proxy_ti.c_cflag = ctrl; 680 prx->proxy_ti.c_cflag |= (CLOCAL | CREAD); 681 cfsetispeed(&prx->proxy_ti, speed); 682 cfsetospeed(&prx->proxy_ti, speed); 683 684 proxy_store(&adapter->src, prx->uuid128, prx->address, NULL, 685 prx->channel, 0, &prx->proxy_ti); 686 687 return dbus_message_new_method_return(msg); 688} 689 690static GDBusMethodTable proxy_methods[] = { 691 { "Enable", "", "", proxy_enable }, 692 { "Disable", "", "", proxy_disable }, 693 { "GetInfo", "", "a{sv}",proxy_get_info }, 694 { "SetSerialParameters", "syys", "", proxy_set_serial_params }, 695 { }, 696}; 697 698static void proxy_path_unregister(gpointer data) 699{ 700 struct serial_proxy *prx = data; 701 int sk; 702 703 info("Unregistered proxy: %s", prx->address); 704 705 if (prx->type != TTY_PROXY) 706 goto done; 707 708 /* Restore the initial TTY configuration */ 709 sk = open(prx->address, O_RDWR | O_NOCTTY); 710 if (sk) { 711 tcsetattr(sk, TCSAFLUSH, &prx->sys_ti); 712 close(sk); 713 } 714done: 715 716 proxy_free(prx); 717} 718 719static int register_proxy_object(struct serial_proxy *prx, char *outpath, size_t size) 720{ 721 struct serial_adapter *adapter = prx->adapter; 722 char path[MAX_PATH_LENGTH + 1]; 723 724 snprintf(path, MAX_PATH_LENGTH, "%s/proxy%d", 725 adapter->path, sk_counter++); 726 727 if (!g_dbus_register_interface(adapter->conn, path, 728 SERIAL_PROXY_INTERFACE, 729 proxy_methods, NULL, NULL, 730 prx, proxy_path_unregister)) { 731 error("D-Bus failed to register %s path", path); 732 return -1; 733 } 734 735 prx->path = g_strdup(path); 736 adapter->proxies = g_slist_append(adapter->proxies, prx); 737 738 if (outpath) 739 strncpy(outpath, path, size); 740 741 info("Registered proxy: %s", path); 742 743 return 0; 744} 745 746static int proxy_tty_register(struct serial_adapter *adapter, 747 const char *uuid128, const char *address, 748 struct termios *ti, char *outpath, size_t size, 749 gboolean save) 750{ 751 struct termios sys_ti; 752 struct serial_proxy *prx; 753 int sk, ret; 754 755 sk = open(address, O_RDONLY | O_NOCTTY); 756 if (sk < 0) { 757 error("Cant open TTY: %s(%d)", strerror(errno), errno); 758 return -EINVAL; 759 } 760 761 prx = g_new0(struct serial_proxy, 1); 762 prx->address = g_strdup(address); 763 prx->uuid128 = g_strdup(uuid128); 764 prx->type = TTY_PROXY; 765 prx->adapter = adapter; 766 767 /* Current TTY settings */ 768 memset(&sys_ti, 0, sizeof(sys_ti)); 769 tcgetattr(sk, &sys_ti); 770 memcpy(&prx->sys_ti, &sys_ti, sizeof(sys_ti)); 771 close(sk); 772 773 if (!ti) { 774 /* Use current settings */ 775 memcpy(&prx->proxy_ti, &sys_ti, sizeof(sys_ti)); 776 } else { 777 /* New TTY settings: user provided */ 778 memcpy(&prx->proxy_ti, ti, sizeof(*ti)); 779 } 780 781 ret = register_proxy_object(prx, outpath, size); 782 if (ret < 0) 783 proxy_free(prx); 784 785 if (save) 786 proxy_store(&adapter->src, uuid128, address, NULL, 787 prx->channel, 0, &prx->proxy_ti); 788 789 return ret; 790} 791 792static int proxy_socket_register(struct serial_adapter *adapter, 793 const char *uuid128, const char *address, 794 char *outpath, size_t size, gboolean save) 795{ 796 struct serial_proxy *prx; 797 int ret; 798 799 prx = g_new0(struct serial_proxy, 1); 800 prx->address = g_strdup(address); 801 prx->uuid128 = g_strdup(uuid128); 802 prx->type = UNIX_SOCKET_PROXY; 803 prx->adapter = adapter; 804 805 ret = register_proxy_object(prx, outpath, size); 806 if (ret < 0) 807 proxy_free(prx); 808 809 if (save) 810 proxy_store(&adapter->src, uuid128, address, NULL, 811 prx->channel, 0, NULL); 812 813 return ret; 814} 815 816static int proxy_tcp_register(struct serial_adapter *adapter, 817 const char *uuid128, const char *address, 818 char *outpath, size_t size, gboolean save) 819{ 820 struct serial_proxy *prx; 821 int ret; 822 823 prx = g_new0(struct serial_proxy, 1); 824 prx->address = g_strdup(address); 825 prx->uuid128 = g_strdup(uuid128); 826 prx->type = TCP_SOCKET_PROXY; 827 prx->adapter = adapter; 828 829 ret = register_proxy_object(prx, outpath, size); 830 if (ret < 0) 831 proxy_free(prx); 832 833 if (save) 834 proxy_store(&adapter->src, uuid128, address, NULL, 835 prx->channel, 0, NULL); 836 837 return ret; 838} 839 840static proxy_type_t addr2type(const char *address) 841{ 842 struct stat st; 843 844 if (stat(address, &st) < 0) { 845 /* 846 * Unix socket: if the sun_path starts with null byte 847 * it refers to abstract namespace. 'x00' will be used 848 * to represent the null byte. 849 */ 850 if (strncmp("localhost:", address, 10) == 0) 851 return TCP_SOCKET_PROXY; 852 if (strncmp("x00", address, 3) != 0) 853 return UNKNOWN_PROXY_TYPE; 854 else 855 return UNIX_SOCKET_PROXY; 856 } else { 857 /* Filesystem: char device or unix socket */ 858 if (S_ISCHR(st.st_mode) && strncmp("/dev/", address, 4) == 0) 859 return TTY_PROXY; 860 else if (S_ISSOCK(st.st_mode)) 861 return UNIX_SOCKET_PROXY; 862 else 863 return UNKNOWN_PROXY_TYPE; 864 } 865} 866 867static int proxy_addrcmp(gconstpointer proxy, gconstpointer addr) 868{ 869 const struct serial_proxy *prx = proxy; 870 const char *address = addr; 871 872 return strcmp(prx->address, address); 873} 874 875static int proxy_pathcmp(gconstpointer proxy, gconstpointer p) 876{ 877 const struct serial_proxy *prx = proxy; 878 const char *path = p; 879 880 return strcmp(prx->path, path); 881} 882 883static DBusMessage *create_proxy(DBusConnection *conn, 884 DBusMessage *msg, void *data) 885{ 886 struct serial_adapter *adapter = data; 887 char path[MAX_PATH_LENGTH + 1]; 888 const char *uuid128, *address, *ppath = path; 889 DBusMessage *reply; 890 proxy_type_t type; 891 uuid_t uuid; 892 int ret; 893 894 if (!dbus_message_get_args(msg, NULL, 895 DBUS_TYPE_STRING, &uuid128, 896 DBUS_TYPE_STRING, &address, 897 DBUS_TYPE_INVALID)) 898 return NULL; 899 900 if (bt_string2uuid(&uuid, uuid128) < 0) 901 return invalid_arguments(msg, "Invalid UUID"); 902 903 type = addr2type(address); 904 if (type == UNKNOWN_PROXY_TYPE) 905 return invalid_arguments(msg, "Invalid address"); 906 907 /* Only one proxy per address(TTY or unix socket) is allowed */ 908 if (g_slist_find_custom(adapter->proxies, address, proxy_addrcmp)) 909 return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyExist", 910 "Proxy already exists"); 911 912 reply = dbus_message_new_method_return(msg); 913 if (!reply) 914 return NULL; 915 916 switch (type) { 917 case UNIX_SOCKET_PROXY: 918 ret = proxy_socket_register(adapter, uuid128, address, 919 path, sizeof(path), TRUE); 920 break; 921 case TTY_PROXY: 922 ret = proxy_tty_register(adapter, uuid128, address, 923 NULL, path, sizeof(path), TRUE); 924 break; 925 case TCP_SOCKET_PROXY: 926 ret = proxy_tcp_register(adapter, uuid128, address, 927 path, sizeof(path), TRUE); 928 break; 929 default: 930 ret = -1; 931 } 932 if (ret < 0) { 933 dbus_message_unref(reply); 934 return failed(msg, "Create object path failed"); 935 } 936 937 g_dbus_emit_signal(adapter->conn, adapter->path, 938 SERIAL_MANAGER_INTERFACE, "ProxyCreated", 939 DBUS_TYPE_STRING, &ppath, 940 DBUS_TYPE_INVALID); 941 942 dbus_message_append_args(reply, 943 DBUS_TYPE_STRING, &ppath, 944 DBUS_TYPE_INVALID); 945 946 return reply; 947} 948 949static DBusMessage *list_proxies(DBusConnection *conn, 950 DBusMessage *msg, void *data) 951{ 952 struct serial_adapter *adapter = data; 953 const GSList *l; 954 DBusMessage *reply; 955 DBusMessageIter iter, iter_array; 956 957 reply = dbus_message_new_method_return(msg); 958 if (!reply) 959 return NULL; 960 961 dbus_message_iter_init_append(reply, &iter); 962 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 963 DBUS_TYPE_STRING_AS_STRING, &iter_array); 964 965 for (l = adapter->proxies; l; l = l->next) { 966 struct serial_proxy *prx = l->data; 967 968 dbus_message_iter_append_basic(&iter_array, 969 DBUS_TYPE_STRING, &prx->path); 970 } 971 972 dbus_message_iter_close_container(&iter, &iter_array); 973 974 return reply; 975} 976 977static DBusMessage *remove_proxy(DBusConnection *conn, 978 DBusMessage *msg, void *data) 979{ 980 struct serial_adapter *adapter = data; 981 struct serial_proxy *prx; 982 const char *path; 983 GSList *l; 984 985 if (!dbus_message_get_args(msg, NULL, 986 DBUS_TYPE_STRING, &path, 987 DBUS_TYPE_INVALID)) 988 return NULL; 989 990 l = g_slist_find_custom(adapter->proxies, path, proxy_pathcmp); 991 if (!l) 992 return does_not_exist(msg, "Invalid proxy path"); 993 994 g_dbus_emit_signal(conn, adapter->path, 995 SERIAL_MANAGER_INTERFACE, "ProxyRemoved", 996 DBUS_TYPE_STRING, &path, 997 DBUS_TYPE_INVALID); 998 999 prx = l->data; 1000 proxy_delete(&adapter->src, prx->address); 1001 adapter->proxies = g_slist_remove(adapter->proxies, prx); 1002 1003 g_dbus_unregister_interface(conn, path, SERIAL_PROXY_INTERFACE); 1004 1005 return dbus_message_new_method_return(msg); 1006} 1007 1008static void manager_path_unregister(void *data) 1009{ 1010 struct serial_adapter *adapter = data; 1011 GSList *l; 1012 1013 /* Remove proxy objects */ 1014 for (l = adapter->proxies; l; l = l->next) { 1015 struct serial_proxy *prx = l->data; 1016 char *path = g_strdup(prx->path); 1017 1018 g_dbus_unregister_interface(adapter->conn, path, 1019 SERIAL_PROXY_INTERFACE); 1020 g_free(path); 1021 } 1022 1023 if (adapter->conn) 1024 dbus_connection_unref(adapter->conn); 1025 1026 adapters = g_slist_remove(adapters, adapter); 1027 g_slist_free(adapter->proxies); 1028 g_free(adapter->path); 1029 g_free(adapter); 1030} 1031 1032static GDBusMethodTable manager_methods[] = { 1033 { "CreateProxy", "ss", "s", create_proxy }, 1034 { "ListProxies", "", "as", list_proxies }, 1035 { "RemoveProxy", "s", "", remove_proxy }, 1036 { }, 1037}; 1038 1039static GDBusSignalTable manager_signals[] = { 1040 { "ProxyCreated", "s" }, 1041 { "ProxyRemoved", "s" }, 1042 { } 1043}; 1044 1045static void parse_proxy(char *key, char *value, void *data) 1046{ 1047 struct serial_adapter *adapter = data; 1048 char uuid128[MAX_LEN_UUID_STR], tmp[3]; 1049 char *pvalue; 1050 proxy_type_t type; 1051 unsigned int pos; 1052 int ch, opts; 1053 struct termios ti; 1054 uint8_t *pti; 1055 1056 memset(uuid128, 0, sizeof(uuid128)); 1057 ch = opts = pos = 0; 1058 if (sscanf(value,"%s %d 0x%04X %n", uuid128, &ch, &opts, &pos) != 3) 1059 return; 1060 1061 /* Extracting name */ 1062 value += pos; 1063 pvalue = strchr(value, ':'); 1064 if (!pvalue) 1065 return; 1066 1067 /* FIXME: currently name is not used */ 1068 *pvalue = '\0'; 1069 1070 type = addr2type(key); 1071 switch (type) { 1072 case TTY_PROXY: 1073 /* Extracting termios */ 1074 pvalue++; 1075 if (!pvalue || strlen(pvalue) != (2 * sizeof(ti))) 1076 return; 1077 1078 memset(&ti, 0, sizeof(ti)); 1079 memset(tmp, 0, sizeof(tmp)); 1080 1081 /* Converting to termios struct */ 1082 pti = (uint8_t *) &ti; 1083 for (pos = 0; pos < sizeof(ti); pos++, pvalue += 2, pti++) { 1084 memcpy(tmp, pvalue, 2); 1085 *pti = (uint8_t) strtol(tmp, NULL, 16); 1086 } 1087 1088 proxy_tty_register(adapter, uuid128, key, &ti, NULL, 0, FALSE); 1089 break; 1090 case UNIX_SOCKET_PROXY: 1091 proxy_socket_register(adapter, uuid128, key, NULL, 0, FALSE); 1092 break; 1093 case TCP_SOCKET_PROXY: 1094 proxy_tcp_register(adapter, uuid128, key, NULL, 0, FALSE); 1095 break; 1096 default: 1097 return; 1098 } 1099} 1100 1101static void register_stored(struct serial_adapter *adapter) 1102{ 1103 char filename[PATH_MAX + 1]; 1104 char address[18]; 1105 1106 ba2str(&adapter->src, address); 1107 snprintf(filename, PATH_MAX, "%s/%s/proxy", STORAGEDIR, address); 1108 textfile_foreach(filename, parse_proxy, adapter); 1109} 1110 1111static struct serial_adapter *find_adapter(GSList *list, const char *path) 1112{ 1113 GSList *l; 1114 1115 for (l = list; l; l = l->next) { 1116 struct serial_adapter *adapter = l->data; 1117 1118 if (g_str_equal(adapter->path, path)) 1119 return adapter; 1120 } 1121 1122 return NULL; 1123} 1124 1125int proxy_register(DBusConnection *conn, const char *path, bdaddr_t *src) 1126{ 1127 struct serial_adapter *adapter; 1128 1129 adapter = find_adapter(adapters, path); 1130 if (adapter) 1131 return -EINVAL; 1132 1133 adapter = g_new0(struct serial_adapter, 1); 1134 adapter->conn = dbus_connection_ref(conn); 1135 bacpy(&adapter->src, src); 1136 adapter->path = g_strdup(path); 1137 1138 if (!g_dbus_register_interface(conn, path, 1139 SERIAL_MANAGER_INTERFACE, 1140 manager_methods, manager_signals, NULL, 1141 adapter, manager_path_unregister)) { 1142 error("Failed to register %s interface to %s", 1143 SERIAL_MANAGER_INTERFACE, path); 1144 return -1; 1145 } 1146 1147 register_stored(adapter); 1148 1149 adapters = g_slist_append(adapters, adapter); 1150 1151 info("Registered interface %s on path %s", 1152 SERIAL_MANAGER_INTERFACE, path); 1153 1154 return 0; 1155} 1156 1157void proxy_unregister(const char *path) 1158{ 1159 struct serial_adapter *adapter; 1160 1161 adapter = find_adapter(adapters, path); 1162 if (!adapter) 1163 return; 1164 1165 g_dbus_unregister_interface(adapter->conn, path, 1166 SERIAL_MANAGER_INTERFACE); 1167} 1168