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