1 /******************************************************************************
2  *
3  *  Copyright (c) 2014 The Android Open Source Project
4  *  Copyright (C) 2004-2012 Broadcom Corporation
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at:
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  ******************************************************************************/
19 
20 /******************************************************************************
21  *
22  *  This file contains the audio gateway functions controlling the RFCOMM
23  *  connections.
24  *
25  ******************************************************************************/
26 
27 #include <string.h>
28 #include "common/bt_defs.h"
29 #include "bta/bta_api.h"
30 #include "bta_hf_client_int.h"
31 #include "stack/port_api.h"
32 #include "osi/allocator.h"
33 
34 #if (BTA_HF_INCLUDED == TRUE)
35 /*******************************************************************************
36 **
37 ** Function         bta_hf_client_port_cback
38 **
39 ** Description      RFCOMM Port callback
40 **
41 **
42 ** Returns          void
43 **
44 *******************************************************************************/
bta_hf_client_port_cback(UINT32 code,UINT16 port_handle)45 static void bta_hf_client_port_cback(UINT32 code, UINT16 port_handle)
46 {
47     BT_HDR      *p_buf;
48     UNUSED(code);
49 
50     /* ignore port events for port handles other than connected handle */
51     if (port_handle != bta_hf_client_cb.scb.conn_handle) {
52         APPL_TRACE_DEBUG("bta_hf_client_port_cback ignoring handle:%d conn_handle = %d",
53                          port_handle, bta_hf_client_cb.scb.conn_handle);
54         return;
55     }
56 
57     if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
58         p_buf->event = BTA_HF_CLIENT_RFC_DATA_EVT;
59         bta_sys_sendmsg(p_buf);
60     }
61 }
62 
63 /*******************************************************************************
64 **
65 ** Function         bta_hf_client_mgmt_cback
66 **
67 ** Description      RFCOMM management callback
68 **
69 **
70 ** Returns          void
71 **
72 *******************************************************************************/
bta_hf_client_mgmt_cback(UINT32 code,UINT16 port_handle,void * data)73 static void bta_hf_client_mgmt_cback(UINT32 code, UINT16 port_handle, void* data)
74 {
75     tBTA_HF_CLIENT_RFC     *p_buf;
76     UINT16                  event;
77 
78     APPL_TRACE_DEBUG("bta_hf_client_mgmt_cback : code = %d, port_handle = %d, conn_handle = %d, serv_handle = %d",
79                      code, port_handle, bta_hf_client_cb.scb.conn_handle, bta_hf_client_cb.scb.serv_handle);
80 
81     /* ignore close event for port handles other than connected handle */
82     if ((code != PORT_SUCCESS) && (port_handle != bta_hf_client_cb.scb.conn_handle)) {
83         APPL_TRACE_DEBUG("bta_hf_client_mgmt_cback ignoring handle:%d", port_handle);
84         return;
85     }
86 
87     if (code == PORT_SUCCESS) {
88         if ((bta_hf_client_cb.scb.conn_handle && (port_handle == bta_hf_client_cb.scb.conn_handle)) || /* outgoing connection */
89                 (port_handle == bta_hf_client_cb.scb.serv_handle)) {                     /* incoming connection */
90             event = BTA_HF_CLIENT_RFC_OPEN_EVT;
91         } else {
92             APPL_TRACE_ERROR ("bta_hf_client_mgmt_cback: PORT_SUCCESS, ignoring handle = %d", port_handle);
93             return;
94         }
95     }
96     /* distinguish server close events */
97     else if (port_handle == bta_hf_client_cb.scb.conn_handle) {
98         event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
99     } else {
100         event = BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT;
101     }
102 
103     if ((p_buf = (tBTA_HF_CLIENT_RFC *) osi_malloc(sizeof(tBTA_HF_CLIENT_RFC))) != NULL) {
104         p_buf->hdr.event = event;
105         p_buf->port_handle = port_handle;
106         bta_sys_sendmsg(p_buf);
107     }
108 }
109 
110 /*******************************************************************************
111 **
112 ** Function         bta_hf_client_setup_port
113 **
114 ** Description      Setup RFCOMM port for use by HF Client.
115 **
116 **
117 ** Returns          void
118 **
119 *******************************************************************************/
bta_hf_client_setup_port(UINT16 handle)120 void bta_hf_client_setup_port(UINT16 handle)
121 {
122     PORT_SetEventMask(handle, PORT_EV_RXCHAR);
123     PORT_SetEventCallback(handle, bta_hf_client_port_cback);
124 }
125 
126 /*******************************************************************************
127 **
128 ** Function         bta_hf_client_start_server
129 **
130 ** Description      Setup RFCOMM server for use by HF Client.
131 **
132 **
133 ** Returns          void
134 **
135 *******************************************************************************/
bta_hf_client_start_server(void)136 void bta_hf_client_start_server(void)
137 {
138     int port_status;
139 
140     if (bta_hf_client_cb.scb.serv_handle > 0) {
141         APPL_TRACE_DEBUG("%s already started, handle: %d", __FUNCTION__, bta_hf_client_cb.scb.serv_handle);
142         return;
143     }
144 
145     BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HF_HANDSFREE, bta_hf_client_cb.scb.serv_sec_mask,
146                          BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scn);
147 
148     port_status =  RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb.scn,
149                                            TRUE, BTA_HF_CLIENT_MTU, (UINT8 *) bd_addr_any, &(bta_hf_client_cb.scb.serv_handle),
150                                            bta_hf_client_mgmt_cback);
151 
152     if (port_status  == PORT_SUCCESS) {
153         bta_hf_client_setup_port(bta_hf_client_cb.scb.serv_handle);
154     } else {
155         /* TODO: can we handle this better? */
156         APPL_TRACE_DEBUG("bta_hf_client_start_server: RFCOMM_CreateConnection returned error:%d", port_status);
157     }
158 
159     APPL_TRACE_DEBUG("bta_hf_client_start_server handle: %d", bta_hf_client_cb.scb.serv_handle);
160 }
161 
162 /*******************************************************************************
163 **
164 ** Function         bta_hf_client_close_server
165 **
166 ** Description      Close RFCOMM server port for use by HF Client.
167 **
168 **
169 ** Returns          void
170 **
171 *******************************************************************************/
bta_hf_client_close_server(void)172 void bta_hf_client_close_server(void)
173 {
174     APPL_TRACE_DEBUG("%s %d", __FUNCTION__, bta_hf_client_cb.scb.serv_handle);
175 
176     if (bta_hf_client_cb.scb.serv_handle == 0) {
177         APPL_TRACE_DEBUG("%s already stopped", __FUNCTION__);
178         return;
179     }
180 
181     RFCOMM_RemoveServer(bta_hf_client_cb.scb.serv_handle);
182     bta_hf_client_cb.scb.serv_handle = 0;
183 }
184 
185 /*******************************************************************************
186 **
187 ** Function         bta_hf_client_rfc_do_open
188 **
189 ** Description      Open an RFCOMM connection to the peer device.
190 **
191 **
192 ** Returns          void
193 **
194 *******************************************************************************/
bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA * p_data)195 void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA *p_data)
196 {
197     BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HF_HANDSFREE,
198                          bta_hf_client_cb.scb.cli_sec_mask, BT_PSM_RFCOMM,
199                          BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scb.peer_scn);
200 
201     if (RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb.scb.peer_scn,
202                                 FALSE, BTA_HF_CLIENT_MTU, bta_hf_client_cb.scb.peer_addr, &(bta_hf_client_cb.scb.conn_handle),
203                                 bta_hf_client_mgmt_cback) == PORT_SUCCESS) {
204         bta_hf_client_setup_port(bta_hf_client_cb.scb.conn_handle);
205         APPL_TRACE_DEBUG("bta_hf_client_rfc_do_open : conn_handle = %d", bta_hf_client_cb.scb.conn_handle);
206     }
207     /* RFCOMM create connection failed; send ourselves RFCOMM close event */
208     else {
209         bta_hf_client_sm_execute(BTA_HF_CLIENT_RFC_CLOSE_EVT, p_data);
210     }
211 }
212 
213 /*******************************************************************************
214 **
215 ** Function         bta_hf_client_rfc_do_close
216 **
217 ** Description      Close RFCOMM connection.
218 **
219 **
220 ** Returns          void
221 **
222 *******************************************************************************/
bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA * p_data)223 void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA *p_data)
224 {
225     tBTA_HF_CLIENT_RFC     *p_buf;
226     UNUSED(p_data);
227 
228     if (bta_hf_client_cb.scb.conn_handle) {
229         RFCOMM_RemoveConnection(bta_hf_client_cb.scb.conn_handle);
230     } else {
231         /* Close API was called while HF Client is in Opening state.        */
232         /* Need to trigger the state machine to send callback to the app    */
233         /* and move back to INIT state.                                     */
234         if ((p_buf = (tBTA_HF_CLIENT_RFC *) osi_malloc(sizeof(tBTA_HF_CLIENT_RFC))) != NULL) {
235             p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
236             bta_sys_sendmsg(p_buf);
237         }
238 
239         /* Cancel SDP if it had been started. */
240         if (bta_hf_client_cb.scb.p_disc_db) {
241             (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db);
242             bta_hf_client_free_db(NULL);
243         }
244     }
245 }
246 #endif /* #if (BTA_HF_INCLUDED == TRUE) */
247