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