1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org> 6 * Copyright (C) 2009 The Android Open Source Project 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#include <unistd.h> 25#include <errno.h> 26#include <sys/ioctl.h> 27#include <sys/types.h> 28#include <sys/socket.h> 29 30#include <private/android_filesystem_config.h> 31#include <sys/prctl.h> 32#include <linux/capability.h> 33 34#include <bluetooth/bluetooth.h> 35#include <bluetooth/hci.h> 36 37/* Set UID to bluetooth w/ CAP_NET_RAW, CAP_NET_ADMIN and CAP_NET_BIND_SERVICE 38 * (Android's init.rc does not yet support applying linux capabilities) */ 39void android_set_aid_and_cap() { 40 prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); 41 setuid(AID_BLUETOOTH); 42 43 struct __user_cap_header_struct header; 44 struct __user_cap_data_struct cap; 45 header.version = _LINUX_CAPABILITY_VERSION; 46 header.pid = 0; 47 cap.effective = cap.permitted = 1 << CAP_NET_RAW | 48 1 << CAP_NET_ADMIN | 49 1 << CAP_NET_BIND_SERVICE; 50 cap.inheritable = 0; 51 capset(&header, &cap); 52} 53 54static int write_flush_timeout(int fd, uint16_t handle, 55 unsigned int timeout_ms) { 56 uint16_t timeout = (timeout_ms * 1000) / 625; // timeout units of 0.625ms 57 unsigned char hci_write_flush_cmd[] = { 58 0x01, // HCI command packet 59 0x28, 0x0C, // HCI_Write_Automatic_Flush_Timeout 60 0x04, // Length 61 0x00, 0x00, // Handle 62 0x00, 0x00, // Timeout 63 }; 64 65 hci_write_flush_cmd[4] = (uint8_t)handle; 66 hci_write_flush_cmd[5] = (uint8_t)(handle >> 8); 67 hci_write_flush_cmd[6] = (uint8_t)timeout; 68 hci_write_flush_cmd[7] = (uint8_t)(timeout >> 8); 69 70 int ret = write(fd, hci_write_flush_cmd, sizeof(hci_write_flush_cmd)); 71 if (ret < 0) { 72 error("write(): %s (%d)]", strerror(errno), errno); 73 return -1; 74 } else if (ret != sizeof(hci_write_flush_cmd)) { 75 error("write(): unexpected length %d", ret); 76 return -1; 77 } 78 return 0; 79} 80 81#ifdef BOARD_HAVE_BLUETOOTH_BCM 82static int vendor_high_priority(int fd, uint16_t handle) { 83 unsigned char hci_sleep_cmd[] = { 84 0x01, // HCI command packet 85 0x57, 0xfc, // HCI_Write_High_Priority_Connection 86 0x02, // Length 87 0x00, 0x00 // Handle 88 }; 89 90 hci_sleep_cmd[4] = (uint8_t)handle; 91 hci_sleep_cmd[5] = (uint8_t)(handle >> 8); 92 93 int ret = write(fd, hci_sleep_cmd, sizeof(hci_sleep_cmd)); 94 if (ret < 0) { 95 error("write(): %s (%d)]", strerror(errno), errno); 96 return -1; 97 } else if (ret != sizeof(hci_sleep_cmd)) { 98 error("write(): unexpected length %d", ret); 99 return -1; 100 } 101 return 0; 102} 103 104static int get_hci_sock() { 105 int sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 106 struct sockaddr_hci addr; 107 int opt; 108 109 if(sock < 0) { 110 error("Can't create raw HCI socket!"); 111 return -1; 112 } 113 114 opt = 1; 115 if (setsockopt(sock, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) { 116 error("Error setting data direction\n"); 117 return -1; 118 } 119 120 /* Bind socket to the HCI device */ 121 addr.hci_family = AF_BLUETOOTH; 122 addr.hci_dev = 0; // hci0 123 if(bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 124 error("Can't attach to device hci0. %s(%d)\n", 125 strerror(errno), 126 errno); 127 return -1; 128 } 129 return sock; 130} 131 132static int get_acl_handle(int fd, bdaddr_t *bdaddr) { 133 int i; 134 int ret = -1; 135 struct hci_conn_list_req *conn_list; 136 struct hci_conn_info *conn_info; 137 int max_conn = 10; 138 139 conn_list = malloc(max_conn * ( 140 sizeof(struct hci_conn_list_req) + sizeof(struct hci_conn_info))); 141 if (!conn_list) { 142 error("Out of memory in %s\n", __FUNCTION__); 143 return -1; 144 } 145 146 conn_list->dev_id = 0; /* hardcoded to HCI device 0 */ 147 conn_list->conn_num = max_conn; 148 149 if (ioctl(fd, HCIGETCONNLIST, (void *)conn_list)) { 150 error("Failed to get connection list\n"); 151 goto out; 152 } 153 154 for (i=0; i < conn_list->conn_num; i++) { 155 conn_info = &conn_list->conn_info[i]; 156 if (conn_info->type == ACL_LINK && 157 !memcmp((void *)&conn_info->bdaddr, (void *)bdaddr, 158 sizeof(bdaddr_t))) { 159 ret = conn_info->handle; 160 goto out; 161 } 162 } 163 ret = 0; 164 165out: 166 free(conn_list); 167 return ret; 168} 169 170/* Request that the ACL link to a given Bluetooth connection be high priority, 171 * for improved coexistance support 172 */ 173int android_set_high_priority(bdaddr_t *ba) { 174 int ret; 175 int fd = get_hci_sock(); 176 int acl_handle; 177 178 if (fd < 0) 179 return fd; 180 181 acl_handle = get_acl_handle(fd, ba); 182 if (acl_handle < 0) { 183 ret = acl_handle; 184 goto out; 185 } 186 187 ret = vendor_high_priority(fd, acl_handle); 188 if (ret < 0) 189 goto out; 190 ret = write_flush_timeout(fd, acl_handle, 200); 191 192out: 193 close(fd); 194 195 return ret; 196} 197 198#else 199 200int android_set_high_priority(bdaddr_t *ba) { 201 return 0; 202} 203 204#endif 205