1 /****************************************************************************** 2 * 3 * Copyright 2004-2012 Broadcom Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 /****************************************************************************** 20 * 21 * This file contains the audio gateway functions controlling the RFCOMM 22 * connections. 23 * 24 ******************************************************************************/ 25 26 #include <cstring> 27 28 #include <base/bind.h> 29 30 #include "bt_common.h" 31 #include "bta_ag_api.h" 32 #include "bta_ag_int.h" 33 #include "btm_api.h" 34 #include "osi/include/osi.h" 35 #include "port_api.h" 36 #include "rfcdefs.h" 37 #include "utl.h" 38 39 /* Event mask for RfCOMM port callback */ 40 #define BTA_AG_PORT_EV_MASK PORT_EV_RXCHAR 41 42 /* each scb has its own rfcomm callbacks */ 43 void bta_ag_port_cback_1(uint32_t code, uint16_t port_handle); 44 void bta_ag_port_cback_2(uint32_t code, uint16_t port_handle); 45 void bta_ag_port_cback_3(uint32_t code, uint16_t port_handle); 46 void bta_ag_port_cback_4(uint32_t code, uint16_t port_handle); 47 void bta_ag_port_cback_5(uint32_t code, uint16_t port_handle); 48 void bta_ag_port_cback_6(uint32_t code, uint16_t port_handle); 49 void bta_ag_mgmt_cback_1(uint32_t code, uint16_t port_handle); 50 void bta_ag_mgmt_cback_2(uint32_t code, uint16_t port_handle); 51 void bta_ag_mgmt_cback_3(uint32_t code, uint16_t port_handle); 52 void bta_ag_mgmt_cback_4(uint32_t code, uint16_t port_handle); 53 void bta_ag_mgmt_cback_5(uint32_t code, uint16_t port_handle); 54 void bta_ag_mgmt_cback_6(uint32_t code, uint16_t port_handle); 55 56 /* rfcomm callback function tables */ 57 typedef tPORT_CALLBACK* tBTA_AG_PORT_CBACK; 58 const tBTA_AG_PORT_CBACK bta_ag_port_cback_tbl[] = { 59 bta_ag_port_cback_1, bta_ag_port_cback_2, bta_ag_port_cback_3, 60 bta_ag_port_cback_4, bta_ag_port_cback_5, bta_ag_port_cback_6}; 61 62 const tBTA_AG_PORT_CBACK bta_ag_mgmt_cback_tbl[] = { 63 bta_ag_mgmt_cback_1, bta_ag_mgmt_cback_2, bta_ag_mgmt_cback_3, 64 bta_ag_mgmt_cback_4, bta_ag_mgmt_cback_5, bta_ag_mgmt_cback_6}; 65 66 /******************************************************************************* 67 * 68 * Function bta_ag_port_cback 69 * 70 * Description RFCOMM Port callback 71 * 72 * 73 * Returns void 74 * 75 ******************************************************************************/ 76 static void bta_ag_port_cback(UNUSED_ATTR uint32_t code, uint16_t port_handle, 77 uint16_t handle) { 78 tBTA_AG_SCB* p_scb = bta_ag_scb_by_idx(handle); 79 if (p_scb != nullptr) { 80 /* ignore port events for port handles other than connected handle */ 81 if (port_handle != p_scb->conn_handle) { 82 APPL_TRACE_ERROR( 83 "ag_port_cback ignoring handle:%d conn_handle = %d other handle = %d", 84 port_handle, p_scb->conn_handle, handle); 85 return; 86 } 87 if (!bta_ag_scb_open(p_scb)) { 88 LOG(ERROR) << __func__ << ": rfcomm data on an unopened control block " 89 << handle << " peer_addr " << p_scb->peer_addr << " state " 90 << std::to_string(p_scb->state); 91 } 92 do_in_bta_thread(FROM_HERE, 93 base::Bind(&bta_ag_sm_execute_by_handle, handle, 94 BTA_AG_RFC_DATA_EVT, tBTA_AG_DATA::kEmpty)); 95 } 96 } 97 98 /******************************************************************************* 99 * 100 * Function bta_ag_mgmt_cback 101 * 102 * Description RFCOMM management callback 103 * 104 * 105 * Returns void 106 * 107 ******************************************************************************/ 108 static void bta_ag_mgmt_cback(uint32_t code, uint16_t port_handle, 109 uint16_t handle) { 110 tBTA_AG_SCB* p_scb = bta_ag_scb_by_idx(handle); 111 APPL_TRACE_DEBUG("%s: code=%d, port_handle=%d, scb_handle=%d, p_scb=0x%08x", 112 __func__, code, port_handle, handle, p_scb); 113 if (p_scb == nullptr) { 114 LOG(WARNING) << __func__ << ": cannot find scb, code=" << code 115 << ", port_handle=" << port_handle << ", handle=" << handle; 116 return; 117 } 118 /* ignore close event for port handles other than connected handle */ 119 if ((code != PORT_SUCCESS) && (port_handle != p_scb->conn_handle)) { 120 LOG(WARNING) << __func__ << ": ignore open failure for unmatched " 121 << "port_handle " << port_handle << ", scb_handle=" << handle; 122 return; 123 } 124 uint16_t event; 125 if (code == PORT_SUCCESS) { 126 bool found_handle = false; 127 if (p_scb->conn_handle) { 128 /* Outgoing connection */ 129 if (port_handle == p_scb->conn_handle) { 130 found_handle = true; 131 } 132 } else { 133 /* Incoming connection */ 134 for (uint16_t service_port_handle : p_scb->serv_handle) { 135 if (port_handle == service_port_handle) { 136 found_handle = true; 137 break; 138 } 139 } 140 } 141 if (!found_handle) { 142 LOG(ERROR) << __func__ << ": port opened successfully, but port_handle " 143 << port_handle << " is unknown" 144 << ", scb_handle=" << handle; 145 return; 146 } 147 event = BTA_AG_RFC_OPEN_EVT; 148 } else if (port_handle == p_scb->conn_handle) { 149 /* distinguish server close events */ 150 event = BTA_AG_RFC_CLOSE_EVT; 151 } else { 152 event = BTA_AG_RFC_SRV_CLOSE_EVT; 153 } 154 155 tBTA_AG_DATA data = {}; 156 data.rfc.port_handle = port_handle; 157 do_in_bta_thread( 158 FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, handle, event, data)); 159 } 160 161 /******************************************************************************* 162 * 163 * Function bta_ag_port_cback_1 to 6 164 * bta_ag_mgmt_cback_1 to 6 165 * 166 * Description RFCOMM callback functions. This is an easy way to 167 * distinguish scb from the callback. 168 * 169 * 170 * Returns void 171 * 172 ******************************************************************************/ 173 void bta_ag_mgmt_cback_1(uint32_t code, uint16_t port_handle) { 174 bta_ag_mgmt_cback(code, port_handle, 1); 175 } 176 void bta_ag_mgmt_cback_2(uint32_t code, uint16_t port_handle) { 177 bta_ag_mgmt_cback(code, port_handle, 2); 178 } 179 void bta_ag_mgmt_cback_3(uint32_t code, uint16_t port_handle) { 180 bta_ag_mgmt_cback(code, port_handle, 3); 181 } 182 void bta_ag_mgmt_cback_4(uint32_t code, uint16_t port_handle) { 183 bta_ag_mgmt_cback(code, port_handle, 4); 184 } 185 void bta_ag_mgmt_cback_5(uint32_t code, uint16_t port_handle) { 186 bta_ag_mgmt_cback(code, port_handle, 5); 187 } 188 void bta_ag_mgmt_cback_6(uint32_t code, uint16_t port_handle) { 189 bta_ag_mgmt_cback(code, port_handle, 6); 190 } 191 void bta_ag_port_cback_1(uint32_t code, uint16_t port_handle) { 192 bta_ag_port_cback(code, port_handle, 1); 193 } 194 void bta_ag_port_cback_2(uint32_t code, uint16_t port_handle) { 195 bta_ag_port_cback(code, port_handle, 2); 196 } 197 void bta_ag_port_cback_3(uint32_t code, uint16_t port_handle) { 198 bta_ag_port_cback(code, port_handle, 3); 199 } 200 void bta_ag_port_cback_4(uint32_t code, uint16_t port_handle) { 201 bta_ag_port_cback(code, port_handle, 4); 202 } 203 void bta_ag_port_cback_5(uint32_t code, uint16_t port_handle) { 204 bta_ag_port_cback(code, port_handle, 5); 205 } 206 void bta_ag_port_cback_6(uint32_t code, uint16_t port_handle) { 207 bta_ag_port_cback(code, port_handle, 6); 208 } 209 210 /******************************************************************************* 211 * 212 * Function bta_ag_setup_port 213 * 214 * Description Setup RFCOMM port for use by AG. 215 * 216 * 217 * Returns void 218 * 219 ******************************************************************************/ 220 void bta_ag_setup_port(tBTA_AG_SCB* p_scb, uint16_t handle) { 221 int port_callback_index = bta_ag_scb_to_idx(p_scb) - 1; 222 CHECK_GE(port_callback_index, 0) 223 << "invalid callback index, handle=" << handle << ", bd_addr" 224 << p_scb->peer_addr; 225 CHECK_LT(port_callback_index, 226 static_cast<int>(sizeof(bta_ag_port_cback_tbl) / 227 sizeof(bta_ag_port_cback_tbl[0]))) 228 << "callback index out of bound, handle=" << handle << ", bd_addr" 229 << p_scb->peer_addr; 230 PORT_SetEventMask(handle, BTA_AG_PORT_EV_MASK); 231 PORT_SetEventCallback(handle, bta_ag_port_cback_tbl[port_callback_index]); 232 } 233 234 /******************************************************************************* 235 * 236 * Function bta_ag_start_servers 237 * 238 * Description Setup RFCOMM servers for use by AG. 239 * 240 * 241 * Returns void 242 * 243 ******************************************************************************/ 244 void bta_ag_start_servers(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK services) { 245 services >>= BTA_HSP_SERVICE_ID; 246 for (int i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) { 247 /* if service is set in mask */ 248 if (services & 1) { 249 BTM_SetSecurityLevel(false, "", bta_ag_sec_id[i], p_scb->serv_sec_mask, 250 BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 251 bta_ag_cb.profile[i].scn); 252 int management_callback_index = bta_ag_scb_to_idx(p_scb) - 1; 253 CHECK_GE(management_callback_index, 0) 254 << "invalid callback index, services=" << loghex(services) 255 << ", bd_addr=" << p_scb->peer_addr; 256 CHECK_LT(management_callback_index, 257 static_cast<int>(sizeof(bta_ag_mgmt_cback_tbl) / 258 sizeof(bta_ag_mgmt_cback_tbl[0]))) 259 << "callback index out of bound, services=" << loghex(services) 260 << ", bd_addr" << p_scb->peer_addr; 261 int status = RFCOMM_CreateConnection( 262 bta_ag_uuid[i], bta_ag_cb.profile[i].scn, true, BTA_AG_MTU, 263 RawAddress::kAny, &(p_scb->serv_handle[i]), 264 bta_ag_mgmt_cback_tbl[management_callback_index]); 265 if (status == PORT_SUCCESS) { 266 bta_ag_setup_port(p_scb, p_scb->serv_handle[i]); 267 } else { 268 /* TODO: CR#137125 to handle to error properly */ 269 LOG(ERROR) << __func__ << ": RFCOMM_CreateConnection ERROR " << status 270 << ", p_scb=" << p_scb << ", services=" << loghex(services) 271 << ", mgmt_cback_index=" << management_callback_index; 272 } 273 APPL_TRACE_DEBUG("%s: p_scb=0x%08x, services=0x%04x, mgmt_cback_index=%d", 274 __func__, p_scb, services, management_callback_index); 275 } 276 } 277 } 278 279 /******************************************************************************* 280 * 281 * Function bta_ag_close_servers 282 * 283 * Description Close RFCOMM servers port for use by AG. 284 * 285 * 286 * Returns void 287 * 288 ******************************************************************************/ 289 void bta_ag_close_servers(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK services) { 290 services >>= BTA_HSP_SERVICE_ID; 291 for (int i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) { 292 /* if service is set in mask */ 293 if (services & 1) { 294 RFCOMM_RemoveServer(p_scb->serv_handle[i]); 295 p_scb->serv_handle[i] = 0; 296 } 297 } 298 } 299 300 /******************************************************************************* 301 * 302 * Function bta_ag_is_server_closed 303 * 304 * Description Returns true if all servers are closed. 305 * 306 * 307 * Returns true if all servers are closed, false otherwise 308 * 309 ******************************************************************************/ 310 bool bta_ag_is_server_closed(tBTA_AG_SCB* p_scb) { 311 uint8_t xx; 312 bool is_closed = true; 313 314 for (xx = 0; xx < BTA_AG_NUM_IDX; xx++) { 315 if (p_scb->serv_handle[xx] != 0) is_closed = false; 316 } 317 318 return is_closed; 319 } 320 321 /******************************************************************************* 322 * 323 * Function bta_ag_rfc_do_open 324 * 325 * Description Open an RFCOMM connection to the peer device. 326 * 327 * 328 * Returns void 329 * 330 ******************************************************************************/ 331 void bta_ag_rfc_do_open(tBTA_AG_SCB* p_scb, const tBTA_AG_DATA& data) { 332 BTM_SetSecurityLevel(true, "", bta_ag_sec_id[p_scb->conn_service], 333 p_scb->cli_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 334 p_scb->peer_scn); 335 336 int management_callback_index = bta_ag_scb_to_idx(p_scb) - 1; 337 int status = RFCOMM_CreateConnection( 338 bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn, false, BTA_AG_MTU, 339 p_scb->peer_addr, &(p_scb->conn_handle), 340 bta_ag_mgmt_cback_tbl[management_callback_index]); 341 APPL_TRACE_DEBUG( 342 "%s: p_scb=0x%08x, conn_handle=%d, mgmt_cback_index=%d," 343 " status=%d", 344 __func__, p_scb, p_scb->conn_handle, management_callback_index, status); 345 if (status == PORT_SUCCESS) { 346 bta_ag_setup_port(p_scb, p_scb->conn_handle); 347 } else { 348 /* RFCOMM create connection failed; send ourselves RFCOMM close event */ 349 LOG(ERROR) << __func__ << ": RFCOMM_CreateConnection ERROR " << status 350 << " for " << p_scb->peer_addr; 351 bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, data); 352 } 353 } 354 355 /******************************************************************************* 356 * 357 * Function bta_ag_rfc_do_close 358 * 359 * Description Close RFCOMM connection. 360 * 361 * 362 * Returns void 363 * 364 ******************************************************************************/ 365 void bta_ag_rfc_do_close(tBTA_AG_SCB* p_scb, 366 UNUSED_ATTR const tBTA_AG_DATA& data) { 367 if (p_scb->conn_handle) { 368 RFCOMM_RemoveConnection(p_scb->conn_handle); 369 } else { 370 /* Close API was called while AG is in Opening state. */ 371 /* Need to trigger the state machine to send callback to the app */ 372 /* and move back to INIT state. */ 373 do_in_bta_thread( 374 FROM_HERE, 375 base::Bind(&bta_ag_sm_execute_by_handle, bta_ag_scb_to_idx(p_scb), 376 BTA_AG_RFC_CLOSE_EVT, tBTA_AG_DATA::kEmpty)); 377 378 /* Cancel SDP if it had been started. */ 379 /* 380 if(p_scb->p_disc_db) 381 { 382 (void)SDP_CancelServiceSearch (p_scb->p_disc_db); 383 } 384 */ 385 } 386 } 387