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