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