1 /******************************************************************************
2  *
3  *  Copyright (c) 2014 The Android Open Source Project
4  *  Copyright 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 <bluetooth/log.h>
28 
29 #include <cstddef>
30 #include <cstdint>
31 
32 #include "bta/hf_client/bta_hf_client_int.h"
33 #include "bta/include/bta_sec_api.h"
34 #include "bta_sys.h"
35 #include "osi/include/allocator.h"
36 #include "stack/include/bt_uuid16.h"
37 #include "stack/include/port_api.h"
38 #include "stack/include/sdp_api.h"
39 #include "types/raw_address.h"
40 
41 using namespace bluetooth::legacy::stack::sdp;
42 using namespace bluetooth;
43 
44 /*******************************************************************************
45  *
46  * Function         bta_hf_client_port_cback
47  *
48  * Description      RFCOMM Port callback. The handle in this function is
49  *                  specified by BTA layer via the PORT_SetEventCallback
50  *                  method
51  *
52  * Returns          void
53  *
54  ******************************************************************************/
bta_hf_client_port_cback(uint32_t,uint16_t port_handle)55 static void bta_hf_client_port_cback(uint32_t /* code */, uint16_t port_handle) {
56   /* ignore port events for port handles other than connected handle */
57   tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_rfc_handle(port_handle);
58   if (client_cb == NULL) {
59     log::error("cb not found for handle {}", port_handle);
60     return;
61   }
62 
63   tBTA_HF_CLIENT_RFC* p_buf = (tBTA_HF_CLIENT_RFC*)osi_malloc(sizeof(tBTA_HF_CLIENT_RFC));
64   p_buf->hdr.event = BTA_HF_CLIENT_RFC_DATA_EVT;
65   p_buf->hdr.layer_specific = client_cb->handle;
66   bta_sys_sendmsg(p_buf);
67 }
68 
69 /*******************************************************************************
70  *
71  * Function         bta_hf_client_mgmt_cback
72  *
73  * Description      RFCOMM management callback
74  *
75  *
76  * Returns          void
77  *
78  ******************************************************************************/
bta_hf_client_mgmt_cback(const tPORT_RESULT code,uint16_t port_handle)79 static void bta_hf_client_mgmt_cback(const tPORT_RESULT code, uint16_t port_handle) {
80   tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_rfc_handle(port_handle);
81 
82   log::verbose("code = {}, port_handle = {} serv = {}", code, port_handle,
83                bta_hf_client_cb_arr.serv_handle);
84 
85   /* ignore close event for port handles other than connected handle */
86   if (code != PORT_SUCCESS && client_cb != NULL && port_handle != client_cb->conn_handle) {
87     log::verbose("bta_hf_client_mgmt_cback ignoring handle:{}", port_handle);
88     return;
89   }
90 
91   tBTA_HF_CLIENT_RFC* p_buf = (tBTA_HF_CLIENT_RFC*)osi_malloc(sizeof(tBTA_HF_CLIENT_RFC));
92 
93   if (code == PORT_SUCCESS) {
94     if (client_cb && port_handle == client_cb->conn_handle) { /* out conn */
95       p_buf->hdr.event = BTA_HF_CLIENT_RFC_OPEN_EVT;
96     } else if (port_handle == bta_hf_client_cb_arr.serv_handle) {
97       p_buf->hdr.event = BTA_HF_CLIENT_RFC_OPEN_EVT;
98 
99       log::verbose("allocating a new CB for incoming connection");
100       // Find the BDADDR of the peer device
101       RawAddress peer_addr = RawAddress::kEmpty;
102       uint16_t lcid = 0;
103       int status = PORT_CheckConnection(port_handle, &peer_addr, &lcid);
104       if (status != PORT_SUCCESS) {
105         log::error("PORT_CheckConnection returned {}", status);
106       }
107 
108       // Since we accepted a remote request we should allocate a handle first.
109       uint16_t tmp_handle = -1;
110       bta_hf_client_allocate_handle(peer_addr, &tmp_handle);
111       client_cb = bta_hf_client_find_cb_by_handle(tmp_handle);
112 
113       // If allocation fails then we abort.
114       if (client_cb == NULL) {
115         log::error("error allocating a new handle");
116         p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
117         if (RFCOMM_RemoveConnection(port_handle) != PORT_SUCCESS) {
118           log::warn("Unable to remote RFCOMM server connection handle:{}", port_handle);
119         }
120 
121       } else {
122         // Set the connection fields for this new CB
123         client_cb->conn_handle = port_handle;
124 
125         // Since we have accepted an incoming RFCOMM connection:
126         // a) Release the current server from it duties
127         // b) Start a new server for more new incoming connection
128         bta_hf_client_cb_arr.serv_handle = 0;
129         bta_hf_client_start_server();
130       }
131     } else {
132       log::error("PORT_SUCCESS, ignoring handle = {}", port_handle);
133       osi_free(p_buf);
134       return;
135     }
136   } else if (client_cb != NULL && port_handle == client_cb->conn_handle) { /* code != PORT_SUC */
137     log::error("closing port handle {} dev {}", port_handle, client_cb->peer_addr);
138 
139     if (RFCOMM_RemoveServer(port_handle) != PORT_SUCCESS) {
140       log::warn("Unable to remote RFCOMM server connection handle:{}", port_handle);
141     }
142     p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
143   } else if (client_cb == NULL) {
144     // client_cb is already cleaned due to hfp client disabled.
145     // Assigned a valid event value to header and send this message anyway.
146     p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
147   }
148 
149   p_buf->hdr.layer_specific = client_cb != NULL ? client_cb->handle : 0;
150   bta_sys_sendmsg(p_buf);
151 }
152 
153 /*******************************************************************************
154  *
155  * Function         bta_hf_client_setup_port
156  *
157  * Description      Setup RFCOMM port for use by HF Client.
158  *
159  *
160  * Returns          void
161  *
162  ******************************************************************************/
bta_hf_client_setup_port(uint16_t handle)163 void bta_hf_client_setup_port(uint16_t handle) {
164   if (PORT_SetEventMaskAndCallback(handle, PORT_EV_RXCHAR, bta_hf_client_port_cback) !=
165       PORT_SUCCESS) {
166     log::warn("Unable to set RFCOMM event mask and callbackhandle:{}", handle);
167   }
168 }
169 
170 /*******************************************************************************
171  *
172  * Function         bta_hf_client_start_server
173  *
174  * Description      Setup RFCOMM server for use by HF Client.
175  *
176  *
177  * Returns          void
178  *
179  ******************************************************************************/
bta_hf_client_start_server()180 void bta_hf_client_start_server() {
181   int port_status;
182 
183   if (bta_hf_client_cb_arr.serv_handle > 0) {
184     log::verbose("already started, handle: {}", bta_hf_client_cb_arr.serv_handle);
185     return;
186   }
187 
188   port_status = RFCOMM_CreateConnectionWithSecurity(
189           UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb_arr.scn, true, BTA_HF_CLIENT_MTU,
190           RawAddress::kAny, &(bta_hf_client_cb_arr.serv_handle), bta_hf_client_mgmt_cback,
191           BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
192 
193   log::verbose("started rfcomm server with handle {}", bta_hf_client_cb_arr.serv_handle);
194 
195   if (port_status == PORT_SUCCESS) {
196     bta_hf_client_setup_port(bta_hf_client_cb_arr.serv_handle);
197   } else {
198     log::verbose("RFCOMM_CreateConnection returned error:{}", port_status);
199   }
200 }
201 
202 /*******************************************************************************
203  *
204  * Function         bta_hf_client_close_server
205  *
206  * Description      Close RFCOMM server port for use by HF Client.
207  *
208  *
209  * Returns          void
210  *
211  ******************************************************************************/
bta_hf_client_close_server()212 void bta_hf_client_close_server() {
213   log::verbose("{}", bta_hf_client_cb_arr.serv_handle);
214 
215   if (bta_hf_client_cb_arr.serv_handle == 0) {
216     log::verbose("already stopped");
217     return;
218   }
219 
220   if (RFCOMM_RemoveServer(bta_hf_client_cb_arr.serv_handle) != PORT_SUCCESS) {
221     log::warn("Unable to remove RFCOMM servier handle:{}", bta_hf_client_cb_arr.serv_handle);
222   }
223   bta_hf_client_cb_arr.serv_handle = 0;
224 }
225 
226 /*******************************************************************************
227  *
228  * Function         bta_hf_client_rfc_do_open
229  *
230  * Description      Open an RFCOMM connection to the peer device.
231  *
232  *
233  * Returns          void
234  *
235  ******************************************************************************/
bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA * p_data)236 void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA* p_data) {
237   tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
238   if (client_cb == NULL) {
239     log::error("cb not found for handle {}", p_data->hdr.layer_specific);
240     return;
241   }
242 
243   if (RFCOMM_CreateConnectionWithSecurity(UUID_SERVCLASS_HF_HANDSFREE, client_cb->peer_scn, false,
244                                           BTA_HF_CLIENT_MTU, client_cb->peer_addr,
245                                           &(client_cb->conn_handle), bta_hf_client_mgmt_cback,
246                                           BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT) == PORT_SUCCESS) {
247     bta_hf_client_setup_port(client_cb->conn_handle);
248     log::verbose("bta_hf_client_rfc_do_open : conn_handle = {}", client_cb->conn_handle);
249   } else {
250     /* RFCOMM create connection failed; send ourselves RFCOMM close event */
251     bta_hf_client_sm_execute(BTA_HF_CLIENT_RFC_CLOSE_EVT, p_data);
252   }
253 }
254 
255 /*******************************************************************************
256  *
257  * Function         bta_hf_client_rfc_do_close
258  *
259  * Description      Close RFCOMM connection.
260  *
261  *
262  * Returns          void
263  *
264  ******************************************************************************/
bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA * p_data)265 void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA* p_data) {
266   tBTA_HF_CLIENT_CB* client_cb = bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
267   if (client_cb == NULL) {
268     log::error("cb not found for handle {}", p_data->hdr.layer_specific);
269     return;
270   }
271 
272   if (client_cb->conn_handle) {
273     if (RFCOMM_RemoveConnection(client_cb->conn_handle) != PORT_SUCCESS) {
274       log::warn("Unable to remove RFCOMM connection peer:{} handle:{}", client_cb->peer_addr,
275                 client_cb->conn_handle);
276     }
277   } else {
278     /* Close API was called while HF Client is in Opening state.        */
279     /* Need to trigger the state machine to send callback to the app    */
280     /* and move back to INIT state.                                     */
281     tBTA_HF_CLIENT_RFC* p_buf = (tBTA_HF_CLIENT_RFC*)osi_malloc(sizeof(tBTA_HF_CLIENT_RFC));
282     p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
283     bta_sys_sendmsg(p_buf);
284 
285     /* Cancel SDP if it had been started. */
286     if (client_cb->p_disc_db) {
287       (void)get_legacy_stack_sdp_api()->service.SDP_CancelServiceSearch(client_cb->p_disc_db);
288       osi_free_and_reset((void**)&client_cb->p_disc_db);
289     }
290   }
291 }
292