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