1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2009 Marcel Holtmann <marcel (at) 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) */ 39 void 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 54 static 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 82 static 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 104 static 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 memset(&addr, 0, sizeof(addr)); 122 addr.hci_family = AF_BLUETOOTH; 123 addr.hci_dev = 0; // hci0 124 if(bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 125 error("Can't attach to device hci0. %s(%d)\n", 126 strerror(errno), 127 errno); 128 return -1; 129 } 130 return sock; 131 } 132 133 static int get_acl_handle(int fd, bdaddr_t *bdaddr) { 134 int i; 135 int ret = -1; 136 struct hci_conn_list_req *conn_list; 137 struct hci_conn_info *conn_info; 138 int max_conn = 10; 139 140 conn_list = malloc(max_conn * ( 141 sizeof(struct hci_conn_list_req) + sizeof(struct hci_conn_info))); 142 if (!conn_list) { 143 error("Out of memory in %s\n", __FUNCTION__); 144 return -1; 145 } 146 147 conn_list->dev_id = 0; /* hardcoded to HCI device 0 */ 148 conn_list->conn_num = max_conn; 149 150 if (ioctl(fd, HCIGETCONNLIST, (void *)conn_list)) { 151 error("Failed to get connection list\n"); 152 goto out; 153 } 154 155 for (i=0; i < conn_list->conn_num; i++) { 156 conn_info = &conn_list->conn_info[i]; 157 if (conn_info->type == ACL_LINK && 158 !memcmp((void *)&conn_info->bdaddr, (void *)bdaddr, 159 sizeof(bdaddr_t))) { 160 ret = conn_info->handle; 161 goto out; 162 } 163 } 164 ret = 0; 165 166 out: 167 free(conn_list); 168 return ret; 169 } 170 171 /* Request that the ACL link to a given Bluetooth connection be high priority, 172 * for improved coexistance support 173 */ 174 int android_set_high_priority(bdaddr_t *ba) { 175 int ret; 176 int fd = get_hci_sock(); 177 int acl_handle; 178 179 if (fd < 0) 180 return fd; 181 182 acl_handle = get_acl_handle(fd, ba); 183 if (acl_handle < 0) { 184 ret = acl_handle; 185 goto out; 186 } 187 188 ret = vendor_high_priority(fd, acl_handle); 189 if (ret < 0) 190 goto out; 191 ret = write_flush_timeout(fd, acl_handle, 200); 192 193 out: 194 close(fd); 195 196 return ret; 197 } 198 199 #else 200 201 int android_set_high_priority(bdaddr_t *ba) { 202 return 0; 203 } 204 205 #endif 206