1/****************************************************************************** 2 * 3 * Copyright (C) 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 <string.h> 27 28#include "bt_common.h" 29#include "bta_ag_api.h" 30#include "bta_ag_co.h" 31#include "bta_ag_int.h" 32#include "bta_api.h" 33#include "bta_sys.h" 34#include "btm_api.h" 35#include "osi/include/osi.h" 36#include "port_api.h" 37#include "rfcdefs.h" 38#include "utl.h" 39 40/* Event mask for RfCOMM port callback */ 41#define BTA_AG_PORT_EV_MASK PORT_EV_RXCHAR 42 43/* each scb has its own rfcomm callbacks */ 44void bta_ag_port_cback_1(uint32_t code, uint16_t port_handle); 45void bta_ag_port_cback_2(uint32_t code, uint16_t port_handle); 46void bta_ag_port_cback_3(uint32_t code, uint16_t port_handle); 47 48void bta_ag_mgmt_cback_1(uint32_t code, uint16_t port_handle); 49void bta_ag_mgmt_cback_2(uint32_t code, uint16_t port_handle); 50void bta_ag_mgmt_cback_3(uint32_t code, uint16_t port_handle); 51 52int bta_ag_data_cback_1(uint16_t port_handle, void* p_data, uint16_t len); 53int bta_ag_data_cback_2(uint16_t port_handle, void* p_data, uint16_t len); 54int bta_ag_data_cback_3(uint16_t port_handle, void* p_data, uint16_t len); 55 56/* rfcomm callback function tables */ 57typedef tPORT_CALLBACK* tBTA_AG_PORT_CBACK; 58const 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 61const tBTA_AG_PORT_CBACK bta_ag_mgmt_cback_tbl[] = { 62 bta_ag_mgmt_cback_1, bta_ag_mgmt_cback_2, bta_ag_mgmt_cback_3}; 63 64typedef tPORT_DATA_CALLBACK* tBTA_AG_DATA_CBACK; 65const tBTA_AG_DATA_CBACK bta_ag_data_cback_tbl[] = { 66 bta_ag_data_cback_1, bta_ag_data_cback_2, bta_ag_data_cback_3}; 67 68/******************************************************************************* 69 * 70 * Function bta_ag_port_cback 71 * 72 * Description RFCOMM Port callback 73 * 74 * 75 * Returns void 76 * 77 ******************************************************************************/ 78static void bta_ag_port_cback(UNUSED_ATTR uint32_t code, uint16_t port_handle, 79 uint16_t handle) { 80 tBTA_AG_SCB* p_scb; 81 82 p_scb = bta_ag_scb_by_idx(handle); 83 if (p_scb != NULL) { 84 /* ignore port events for port handles other than connected handle */ 85 if (port_handle != p_scb->conn_handle) { 86 APPL_TRACE_DEBUG( 87 "ag_port_cback ignoring handle:%d conn_handle = %d other handle = %d", 88 port_handle, p_scb->conn_handle, handle); 89 return; 90 } 91 92 BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR)); 93 p_buf->event = BTA_AG_RFC_DATA_EVT; 94 p_buf->layer_specific = handle; 95 bta_sys_sendmsg(p_buf); 96 } 97} 98 99/******************************************************************************* 100 * 101 * Function bta_ag_mgmt_cback 102 * 103 * Description RFCOMM management callback 104 * 105 * 106 * Returns void 107 * 108 ******************************************************************************/ 109static void bta_ag_mgmt_cback(uint32_t code, uint16_t port_handle, 110 uint16_t handle) { 111 tBTA_AG_SCB* p_scb; 112 uint16_t event; 113 uint8_t i; 114 bool found_handle = false; 115 116 APPL_TRACE_DEBUG("ag_mgmt_cback : code = %d, port_handle = %d, handle = %d", 117 code, port_handle, handle); 118 119 p_scb = bta_ag_scb_by_idx(handle); 120 if (p_scb != NULL) { 121 /* ignore close event for port handles other than connected handle */ 122 if ((code != PORT_SUCCESS) && (port_handle != p_scb->conn_handle)) { 123 APPL_TRACE_DEBUG("ag_mgmt_cback ignoring handle:%d", port_handle); 124 return; 125 } 126 127 if (code == PORT_SUCCESS) { 128 if (p_scb->conn_handle) /* Outgoing connection */ 129 { 130 if (port_handle == p_scb->conn_handle) found_handle = true; 131 } else /* Incoming connection */ 132 { 133 for (i = 0; i < BTA_AG_NUM_IDX; i++) { 134 if (port_handle == p_scb->serv_handle[i]) found_handle = true; 135 } 136 } 137 138 if (!found_handle) { 139 APPL_TRACE_ERROR( 140 "bta_ag_mgmt_cback: PORT_SUCCESS, ignoring handle = %d", 141 port_handle); 142 return; 143 } 144 145 event = BTA_AG_RFC_OPEN_EVT; 146 } 147 /* distinguish server close events */ 148 else if (port_handle == p_scb->conn_handle) { 149 event = BTA_AG_RFC_CLOSE_EVT; 150 } else { 151 event = BTA_AG_RFC_SRV_CLOSE_EVT; 152 } 153 154 tBTA_AG_RFC* p_buf = (tBTA_AG_RFC*)osi_malloc(sizeof(tBTA_AG_RFC)); 155 p_buf->hdr.event = event; 156 p_buf->hdr.layer_specific = handle; 157 p_buf->port_handle = port_handle; 158 bta_sys_sendmsg(p_buf); 159 } 160} 161 162/******************************************************************************* 163 * 164 * Function bta_ag_data_cback 165 * 166 * Description RFCOMM data callback 167 * 168 * 169 * Returns void 170 * 171 ******************************************************************************/ 172static int bta_ag_data_cback(UNUSED_ATTR uint16_t port_handle, void* p_data, 173 uint16_t len, uint16_t handle) { 174 /* call data call-out directly */ 175 bta_ag_co_tx_write(handle, (uint8_t*)p_data, len); 176 return 0; 177} 178 179/******************************************************************************* 180 * 181 * Function bta_ag_port_cback_1 to 3 182 * bta_ag_mgmt_cback_1 to 3 183 * 184 * Description RFCOMM callback functions. This is an easy way to 185 * distinguish scb from the callback. 186 * 187 * 188 * Returns void 189 * 190 ******************************************************************************/ 191void bta_ag_mgmt_cback_1(uint32_t code, uint16_t handle) { 192 bta_ag_mgmt_cback(code, handle, 1); 193} 194void bta_ag_mgmt_cback_2(uint32_t code, uint16_t handle) { 195 bta_ag_mgmt_cback(code, handle, 2); 196} 197void bta_ag_mgmt_cback_3(uint32_t code, uint16_t handle) { 198 bta_ag_mgmt_cback(code, handle, 3); 199} 200void bta_ag_port_cback_1(uint32_t code, uint16_t handle) { 201 bta_ag_port_cback(code, handle, 1); 202} 203void bta_ag_port_cback_2(uint32_t code, uint16_t handle) { 204 bta_ag_port_cback(code, handle, 2); 205} 206void bta_ag_port_cback_3(uint32_t code, uint16_t handle) { 207 bta_ag_port_cback(code, handle, 3); 208} 209 210/******************************************************************************* 211 * 212 * Function bta_ag_data_cback_1 to 3 213 * 214 * Description RFCOMM data callback functions. This is an easy way to 215 * distinguish scb from the callback. 216 * 217 * 218 * Returns void 219 * 220 ******************************************************************************/ 221int bta_ag_data_cback_1(uint16_t port_handle, void* p_data, uint16_t len) { 222 return bta_ag_data_cback(port_handle, p_data, len, 1); 223} 224int bta_ag_data_cback_2(uint16_t port_handle, void* p_data, uint16_t len) { 225 return bta_ag_data_cback(port_handle, p_data, len, 2); 226} 227int bta_ag_data_cback_3(uint16_t port_handle, void* p_data, uint16_t len) { 228 return bta_ag_data_cback(port_handle, p_data, len, 3); 229} 230 231/******************************************************************************* 232 * 233 * Function bta_ag_setup_port 234 * 235 * Description Setup RFCOMM port for use by AG. 236 * 237 * 238 * Returns void 239 * 240 ******************************************************************************/ 241void bta_ag_setup_port(tBTA_AG_SCB* p_scb, uint16_t handle) { 242 uint16_t i = bta_ag_scb_to_idx(p_scb) - 1; 243 244 /* set up data callback if using pass through mode */ 245 if (bta_ag_cb.parse_mode == BTA_AG_PASS_THROUGH) { 246 PORT_SetDataCallback(handle, bta_ag_data_cback_tbl[i]); 247 } 248 249 PORT_SetEventMask(handle, BTA_AG_PORT_EV_MASK); 250 PORT_SetEventCallback(handle, bta_ag_port_cback_tbl[i]); 251} 252 253/******************************************************************************* 254 * 255 * Function bta_ag_start_servers 256 * 257 * Description Setup RFCOMM servers for use by AG. 258 * 259 * 260 * Returns void 261 * 262 ******************************************************************************/ 263void bta_ag_start_servers(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK services) { 264 int i; 265 int bta_ag_port_status; 266 267 services >>= BTA_HSP_SERVICE_ID; 268 for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) { 269 /* if service is set in mask */ 270 if (services & 1) { 271 BTM_SetSecurityLevel(false, "", bta_ag_sec_id[i], p_scb->serv_sec_mask, 272 BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 273 bta_ag_cb.profile[i].scn); 274 275 bta_ag_port_status = RFCOMM_CreateConnection( 276 bta_ag_uuid[i], bta_ag_cb.profile[i].scn, true, BTA_AG_MTU, 277 (uint8_t*)bd_addr_any, &(p_scb->serv_handle[i]), 278 bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]); 279 280 if (bta_ag_port_status == PORT_SUCCESS) { 281 bta_ag_setup_port(p_scb, p_scb->serv_handle[i]); 282 } else { 283 /* TODO: CR#137125 to handle to error properly */ 284 APPL_TRACE_DEBUG( 285 "bta_ag_start_servers: RFCOMM_CreateConnection returned error:%d", 286 bta_ag_port_status); 287 } 288 } 289 } 290} 291 292/******************************************************************************* 293 * 294 * Function bta_ag_close_servers 295 * 296 * Description Close RFCOMM servers port for use by AG. 297 * 298 * 299 * Returns void 300 * 301 ******************************************************************************/ 302void bta_ag_close_servers(tBTA_AG_SCB* p_scb, tBTA_SERVICE_MASK services) { 303 int i; 304 305 services >>= BTA_HSP_SERVICE_ID; 306 for (i = 0; i < BTA_AG_NUM_IDX && services != 0; i++, services >>= 1) { 307 /* if service is set in mask */ 308 if (services & 1) { 309 RFCOMM_RemoveServer(p_scb->serv_handle[i]); 310 p_scb->serv_handle[i] = 0; 311 } 312 } 313} 314 315/******************************************************************************* 316 * 317 * Function bta_ag_is_server_closed 318 * 319 * Description Returns true if all servers are closed. 320 * 321 * 322 * Returns true if all servers are closed, false otherwise 323 * 324 ******************************************************************************/ 325bool bta_ag_is_server_closed(tBTA_AG_SCB* p_scb) { 326 uint8_t xx; 327 bool is_closed = true; 328 329 for (xx = 0; xx < BTA_AG_NUM_IDX; xx++) { 330 if (p_scb->serv_handle[xx] != 0) is_closed = false; 331 } 332 333 return is_closed; 334} 335 336/******************************************************************************* 337 * 338 * Function bta_ag_rfc_do_open 339 * 340 * Description Open an RFCOMM connection to the peer device. 341 * 342 * 343 * Returns void 344 * 345 ******************************************************************************/ 346void bta_ag_rfc_do_open(tBTA_AG_SCB* p_scb, tBTA_AG_DATA* p_data) { 347 BTM_SetSecurityLevel(true, "", bta_ag_sec_id[p_scb->conn_service], 348 p_scb->cli_sec_mask, BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, 349 p_scb->peer_scn); 350 351 if (RFCOMM_CreateConnection( 352 bta_ag_uuid[p_scb->conn_service], p_scb->peer_scn, false, BTA_AG_MTU, 353 p_scb->peer_addr, &(p_scb->conn_handle), 354 bta_ag_mgmt_cback_tbl[bta_ag_scb_to_idx(p_scb) - 1]) == 355 PORT_SUCCESS) { 356 bta_ag_setup_port(p_scb, p_scb->conn_handle); 357 APPL_TRACE_DEBUG("bta_ag_rfc_do_open : conn_handle = %d", 358 p_scb->conn_handle); 359 } 360 /* RFCOMM create connection failed; send ourselves RFCOMM close event */ 361 else { 362 bta_ag_sm_execute(p_scb, BTA_AG_RFC_CLOSE_EVT, p_data); 363 } 364} 365 366/******************************************************************************* 367 * 368 * Function bta_ag_rfc_do_close 369 * 370 * Description Close RFCOMM connection. 371 * 372 * 373 * Returns void 374 * 375 ******************************************************************************/ 376void bta_ag_rfc_do_close(tBTA_AG_SCB* p_scb, UNUSED_ATTR tBTA_AG_DATA* p_data) { 377 if (p_scb->conn_handle) { 378 RFCOMM_RemoveConnection(p_scb->conn_handle); 379 } else { 380 /* Close API was called while AG is in Opening state. */ 381 /* Need to trigger the state machine to send callback to the app */ 382 /* and move back to INIT state. */ 383 tBTA_AG_RFC* p_buf = (tBTA_AG_RFC*)osi_malloc(sizeof(tBTA_AG_RFC)); 384 p_buf->hdr.event = BTA_AG_RFC_CLOSE_EVT; 385 p_buf->hdr.layer_specific = bta_ag_scb_to_idx(p_scb); 386 bta_sys_sendmsg(p_buf); 387 388 /* Cancel SDP if it had been started. */ 389 /* 390 if(p_scb->p_disc_db) 391 { 392 (void)SDP_CancelServiceSearch (p_scb->p_disc_db); 393 } 394 */ 395 } 396} 397