1b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh/*
2b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *
3b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *  BlueZ - Bluetooth protocol stack for Linux
4b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *
5b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
69a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly *  Copyright (C) 2009 The Android Open Source Project
7b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *
8b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *  This program is free software; you can redistribute it and/or modify
9b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *  it under the terms of the GNU General Public License as published by
10b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *  the Free Software Foundation; either version 2 of the License, or
11b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *  (at your option) any later version.
12b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *
13b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *  This program is distributed in the hope that it will be useful,
14b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *  GNU General Public License for more details.
17b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *
18b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *  You should have received a copy of the GNU General Public License
19b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *  along with this program; if not, write to the Free Software
20b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh *
22b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh */
23b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh
249a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly#include <unistd.h>
259a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly#include <errno.h>
269a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly#include <sys/ioctl.h>
279a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly#include <sys/types.h>
289a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly#include <sys/socket.h>
299a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
30b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh#include <private/android_filesystem_config.h>
31b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh#include <sys/prctl.h>
32b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh#include <linux/capability.h>
33b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh
349a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly#include <bluetooth/bluetooth.h>
359a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly#include <bluetooth/hci.h>
369a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
37b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh/* Set UID to bluetooth w/ CAP_NET_RAW, CAP_NET_ADMIN and CAP_NET_BIND_SERVICE
38b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh * (Android's init.rc does not yet support applying linux capabilities) */
39b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganeshvoid android_set_aid_and_cap() {
40b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh	prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
41b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh	setuid(AID_BLUETOOTH);
42b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh
43b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh	struct __user_cap_header_struct header;
44b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh	struct __user_cap_data_struct cap;
45b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh	header.version = _LINUX_CAPABILITY_VERSION;
46b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh	header.pid = 0;
47b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh	cap.effective = cap.permitted = 1 << CAP_NET_RAW |
48b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh					1 << CAP_NET_ADMIN |
49b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh					1 << CAP_NET_BIND_SERVICE;
50b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh	cap.inheritable = 0;
51b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh	capset(&header, &cap);
52b99eacf38b92b116f3dbd270af01f3e1e91bc72cJaikumar Ganesh}
539a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
54810bd7416134e721c6b951d489cf0689cf08c111Nick Pellystatic int write_flush_timeout(int fd, uint16_t handle,
55810bd7416134e721c6b951d489cf0689cf08c111Nick Pelly        unsigned int timeout_ms) {
56810bd7416134e721c6b951d489cf0689cf08c111Nick Pelly    uint16_t timeout = (timeout_ms * 1000) / 625;  // timeout units of 0.625ms
5782c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly    unsigned char hci_write_flush_cmd[] = {
5882c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly        0x01,               // HCI command packet
5982c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly        0x28, 0x0C,         // HCI_Write_Automatic_Flush_Timeout
6082c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly        0x04,               // Length
6182c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly        0x00, 0x00,         // Handle
6282c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly        0x00, 0x00,         // Timeout
6382c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly    };
6482c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly
6582c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly    hci_write_flush_cmd[4] = (uint8_t)handle;
6682c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly    hci_write_flush_cmd[5] = (uint8_t)(handle >> 8);
6782c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly    hci_write_flush_cmd[6] = (uint8_t)timeout;
6882c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly    hci_write_flush_cmd[7] = (uint8_t)(timeout >> 8);
6982c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly
7082c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly    int ret = write(fd, hci_write_flush_cmd, sizeof(hci_write_flush_cmd));
7182c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly    if (ret < 0) {
7282c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly        error("write(): %s (%d)]", strerror(errno), errno);
7382c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly        return -1;
7482c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly    } else if (ret != sizeof(hci_write_flush_cmd)) {
7582c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly        error("write(): unexpected length %d", ret);
7682c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly        return -1;
7782c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly    }
7882c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly    return 0;
7982c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly}
8082c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly
819a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly#ifdef BOARD_HAVE_BLUETOOTH_BCM
829a8383ad9ee9516756abeeb5081de9651a6294edNick Pellystatic int vendor_high_priority(int fd, uint16_t handle) {
839a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    unsigned char hci_sleep_cmd[] = {
849a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        0x01,               // HCI command packet
859a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        0x57, 0xfc,         // HCI_Write_High_Priority_Connection
869a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        0x02,               // Length
879a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        0x00, 0x00          // Handle
889a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    };
899a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
909a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    hci_sleep_cmd[4] = (uint8_t)handle;
919a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    hci_sleep_cmd[5] = (uint8_t)(handle >> 8);
929a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
939a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    int ret = write(fd, hci_sleep_cmd, sizeof(hci_sleep_cmd));
949a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    if (ret < 0) {
959a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        error("write(): %s (%d)]", strerror(errno), errno);
969a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        return -1;
979a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    } else if (ret != sizeof(hci_sleep_cmd)) {
989a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        error("write(): unexpected length %d", ret);
999a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        return -1;
1009a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    }
1019a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    return 0;
1029a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly}
1039a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1049a8383ad9ee9516756abeeb5081de9651a6294edNick Pellystatic int get_hci_sock() {
1059a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    int sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
1069a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    struct sockaddr_hci addr;
1079a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    int opt;
1089a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1099a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    if(sock < 0) {
1109a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        error("Can't create raw HCI socket!");
1119a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        return -1;
1129a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    }
1139a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1149a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    opt = 1;
1159a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    if (setsockopt(sock, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
1169a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        error("Error setting data direction\n");
1179a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        return -1;
1189a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    }
1199a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1209a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    /* Bind socket to the HCI device */
1219a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    addr.hci_family = AF_BLUETOOTH;
1229a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    addr.hci_dev = 0;  // hci0
1239a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    if(bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1249a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        error("Can't attach to device hci0. %s(%d)\n",
1259a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly             strerror(errno),
1269a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly             errno);
1279a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        return -1;
1289a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    }
1299a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    return sock;
1309a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly}
1319a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1329a8383ad9ee9516756abeeb5081de9651a6294edNick Pellystatic int get_acl_handle(int fd, bdaddr_t *bdaddr) {
1339a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    int i;
1349a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    int ret = -1;
1359a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    struct hci_conn_list_req *conn_list;
1369a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    struct hci_conn_info *conn_info;
1379a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    int max_conn = 10;
1389a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1399a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    conn_list = malloc(max_conn * (
1409a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly            sizeof(struct hci_conn_list_req) + sizeof(struct hci_conn_info)));
1419a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    if (!conn_list) {
1429a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        error("Out of memory in %s\n", __FUNCTION__);
1439a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        return -1;
1449a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    }
1459a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1469a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    conn_list->dev_id = 0;  /* hardcoded to HCI device 0 */
1479a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    conn_list->conn_num = max_conn;
1489a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1499a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    if (ioctl(fd, HCIGETCONNLIST, (void *)conn_list)) {
1509a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        error("Failed to get connection list\n");
1519a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        goto out;
1529a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    }
1539a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1549a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    for (i=0; i < conn_list->conn_num; i++) {
1559a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        conn_info = &conn_list->conn_info[i];
1569a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        if (conn_info->type == ACL_LINK &&
1579a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly                !memcmp((void *)&conn_info->bdaddr, (void *)bdaddr,
1589a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly                sizeof(bdaddr_t))) {
1599a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly            ret = conn_info->handle;
1609a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly            goto out;
1619a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        }
1629a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    }
1639a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    ret = 0;
1649a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1659a8383ad9ee9516756abeeb5081de9651a6294edNick Pellyout:
1669a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    free(conn_list);
1679a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    return ret;
1689a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly}
1699a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1709a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly/* Request that the ACL link to a given Bluetooth connection be high priority,
1719a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly * for improved coexistance support
1729a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly */
1739a8383ad9ee9516756abeeb5081de9651a6294edNick Pellyint android_set_high_priority(bdaddr_t *ba) {
1749a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    int ret;
1759a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    int fd = get_hci_sock();
1769a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    int acl_handle;
1779a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1789a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    if (fd < 0)
1799a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        return fd;
1809a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1819a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    acl_handle = get_acl_handle(fd, ba);
1829a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    if (acl_handle < 0) {
1839a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        ret = acl_handle;
1849a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly        goto out;
1859a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    }
1869a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1879a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    ret = vendor_high_priority(fd, acl_handle);
18882c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly    if (ret < 0)
18982c2b608fb43d741bfc4733a9c3d310c89b01e87Nick Pelly        goto out;
19027868bbc6230d357fda189a1c63cf6fcc59bb629Nick Pelly    ret = write_flush_timeout(fd, acl_handle, 200);
1919a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1929a8383ad9ee9516756abeeb5081de9651a6294edNick Pellyout:
1939a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    close(fd);
1949a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1959a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    return ret;
1969a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly}
1979a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
1989a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly#else
1999a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
2009a8383ad9ee9516756abeeb5081de9651a6294edNick Pellyint android_set_high_priority(bdaddr_t *ba) {
2019a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly    return 0;
2029a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly}
2039a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly
2049a8383ad9ee9516756abeeb5081de9651a6294edNick Pelly#endif
205