1 /******************************************************************************
2  *
3  *  Copyright 2014 The Android Open Source Project
4  *  Copyright 2003-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 performing SDP
23  *  operations.
24  *
25  ******************************************************************************/
26 
27 #include <bluetooth/log.h>
28 
29 #include <cstdint>
30 
31 #include "bta/hf_client/bta_hf_client_int.h"
32 #include "bta/include/bta_hf_client_api.h"
33 #include "bta/include/bta_rfcomm_scn.h"
34 #include "bta/sys/bta_sys.h"
35 #include "internal_include/bt_target.h"
36 #include "os/log.h"
37 #include "osi/include/allocator.h"
38 #include "stack/include/bt_types.h"
39 #include "stack/include/bt_uuid16.h"
40 #include "stack/include/sdp_api.h"
41 #include "stack/include/sdpdefs.h"
42 #include "types/bluetooth/uuid.h"
43 
44 using bluetooth::Uuid;
45 using namespace bluetooth::legacy::stack::sdp;
46 using namespace bluetooth;
47 
48 /* Number of protocol elements in protocol element list. */
49 #define BTA_HF_CLIENT_NUM_PROTO_ELEMS 2
50 
51 /* Number of elements in service class id list. */
52 #define BTA_HF_CLIENT_NUM_SVC_ELEMS 2
53 
54 /*******************************************************************************
55  *
56  * Function         bta_hf_client_sdp_cback
57  *
58  * Description      SDP callback function.
59  *
60  *
61  * Returns          void
62  *
63  ******************************************************************************/
bta_hf_client_sdp_cback(tBTA_HF_CLIENT_CB * client_cb,const RawAddress &,tSDP_STATUS status)64 static void bta_hf_client_sdp_cback(tBTA_HF_CLIENT_CB* client_cb,
65                                     const RawAddress& /* bd_addr */,
66                                     tSDP_STATUS status) {
67   uint16_t event;
68   tBTA_HF_CLIENT_DISC_RESULT* p_buf = (tBTA_HF_CLIENT_DISC_RESULT*)osi_malloc(
69       sizeof(tBTA_HF_CLIENT_DISC_RESULT));
70 
71   log::verbose("bta_hf_client_sdp_cback status:0x{:x}", status);
72 
73   /* set event according to int/acp */
74   if (client_cb->role == BTA_HF_CLIENT_ACP)
75     event = BTA_HF_CLIENT_DISC_ACP_RES_EVT;
76   else
77     event = BTA_HF_CLIENT_DISC_INT_RES_EVT;
78 
79   p_buf->hdr.event = event;
80   p_buf->hdr.layer_specific = client_cb->handle;
81   p_buf->status = status;
82 
83   bta_sys_sendmsg(p_buf);
84 }
85 
86 /******************************************************************************
87  *
88  * Function         bta_hf_client_add_record
89  *
90  * Description      This function is called by a server application to add
91  *                  HFP Client information to an SDP record.  Prior to
92  *                  calling this function the application must call
93  *                  get_legacy_stack_sdp_api()->handle.SDP_CreateRecord() to
94  *                  create an SDP record.
95  *
96  * Returns          true if function execution succeeded,
97  *                  false if function execution failed.
98  *
99  *****************************************************************************/
bta_hf_client_add_record(const char * p_service_name,uint8_t scn,tBTA_HF_CLIENT_FEAT features,uint32_t sdp_handle)100 bool bta_hf_client_add_record(const char* p_service_name, uint8_t scn,
101                               tBTA_HF_CLIENT_FEAT features,
102                               uint32_t sdp_handle) {
103   tSDP_PROTOCOL_ELEM proto_elem_list[BTA_HF_CLIENT_NUM_PROTO_ELEMS];
104   uint16_t svc_class_id_list[BTA_HF_CLIENT_NUM_SVC_ELEMS];
105   uint16_t browse_list[] = {UUID_SERVCLASS_PUBLIC_BROWSE_GROUP};
106   uint16_t version;
107   uint16_t profile_uuid;
108   bool result = true;
109   uint8_t buf[2];
110   uint16_t sdp_features = 0;
111 
112   log::verbose("bta_hf_client_add_record");
113   log::info("features: {}", features);
114 
115   memset(proto_elem_list, 0,
116          BTA_HF_CLIENT_NUM_PROTO_ELEMS * sizeof(tSDP_PROTOCOL_ELEM));
117 
118   /* add the protocol element sequence */
119   proto_elem_list[0].protocol_uuid = UUID_PROTOCOL_L2CAP;
120   proto_elem_list[0].num_params = 0;
121   proto_elem_list[1].protocol_uuid = UUID_PROTOCOL_RFCOMM;
122   proto_elem_list[1].num_params = 1;
123   proto_elem_list[1].params[0] = scn;
124   result &= get_legacy_stack_sdp_api()->handle.SDP_AddProtocolList(
125       sdp_handle, BTA_HF_CLIENT_NUM_PROTO_ELEMS, proto_elem_list);
126 
127   /* add service class id list */
128   svc_class_id_list[0] = UUID_SERVCLASS_HF_HANDSFREE;
129   svc_class_id_list[1] = UUID_SERVCLASS_GENERIC_AUDIO;
130   result &= get_legacy_stack_sdp_api()->handle.SDP_AddServiceClassIdList(
131       sdp_handle, BTA_HF_CLIENT_NUM_SVC_ELEMS, svc_class_id_list);
132 
133   /* add profile descriptor list */
134   profile_uuid = UUID_SERVCLASS_HF_HANDSFREE;
135   version = get_default_hfp_version();
136 
137   result &= get_legacy_stack_sdp_api()->handle.SDP_AddProfileDescriptorList(
138       sdp_handle, profile_uuid, version);
139 
140   /* add service name */
141   if (p_service_name != NULL && p_service_name[0] != 0) {
142     result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(
143         sdp_handle, ATTR_ID_SERVICE_NAME, TEXT_STR_DESC_TYPE,
144         (uint32_t)(strlen(p_service_name) + 1), (uint8_t*)p_service_name);
145   }
146 
147   /* add features */
148   if (features & BTA_HF_CLIENT_FEAT_ECNR)
149     sdp_features |= BTA_HF_CLIENT_FEAT_ECNR;
150 
151   if (features & BTA_HF_CLIENT_FEAT_3WAY)
152     sdp_features |= BTA_HF_CLIENT_FEAT_3WAY;
153 
154   if (features & BTA_HF_CLIENT_FEAT_CLI) sdp_features |= BTA_HF_CLIENT_FEAT_CLI;
155 
156   if (features & BTA_HF_CLIENT_FEAT_VREC)
157     sdp_features |= BTA_HF_CLIENT_FEAT_VREC;
158 
159   if (features & BTA_HF_CLIENT_FEAT_VOL) sdp_features |= BTA_HF_CLIENT_FEAT_VOL;
160 
161   /* Codec bit position is different in SDP (bit 5) and in BRSF (bit 7) */
162   if (features & BTA_HF_CLIENT_FEAT_CODEC)
163     sdp_features |= BTA_HF_CLIENT_WBS_SUPPORT;
164 
165   /* Support swb */
166   if (features & BTA_HF_CLIENT_FEAT_SWB)
167     features |= BTA_HF_CLIENT_FEAT_SWB_SUPPORT;
168 
169   UINT16_TO_BE_FIELD(buf, sdp_features);
170   result &= get_legacy_stack_sdp_api()->handle.SDP_AddAttribute(
171       sdp_handle, ATTR_ID_SUPPORTED_FEATURES, UINT_DESC_TYPE, 2, buf);
172 
173   /* add browse group list */
174   result &= get_legacy_stack_sdp_api()->handle.SDP_AddUuidSequence(
175       sdp_handle, ATTR_ID_BROWSE_GROUP_LIST, 1, browse_list);
176 
177   return result;
178 }
179 
180 /*******************************************************************************
181  *
182  * Function         bta_hf_client_create_record
183  *
184  * Description      Create SDP record for registered service.
185  *
186  *
187  * Returns          void
188  *
189  ******************************************************************************/
bta_hf_client_create_record(tBTA_HF_CLIENT_CB_ARR * client_cb_arr,const char * p_service_name)190 void bta_hf_client_create_record(tBTA_HF_CLIENT_CB_ARR* client_cb_arr,
191                                  const char* p_service_name) {
192   /* add sdp record if not already registered */
193   if (client_cb_arr->sdp_handle == 0) {
194     client_cb_arr->sdp_handle =
195         get_legacy_stack_sdp_api()->handle.SDP_CreateRecord();
196     client_cb_arr->scn = BTA_AllocateSCN();
197     bta_hf_client_add_record(p_service_name, client_cb_arr->scn,
198                              client_cb_arr->features,
199                              client_cb_arr->sdp_handle);
200 
201     bta_sys_add_uuid(UUID_SERVCLASS_HF_HANDSFREE);
202   }
203 }
204 
205 /*******************************************************************************
206  *
207  * Function         bta_hf_client_del_record
208  *
209  * Description      Delete SDP record for registered service.
210  *
211  *
212  * Returns          void
213  *
214  ******************************************************************************/
bta_hf_client_del_record(tBTA_HF_CLIENT_CB_ARR * client_cb)215 void bta_hf_client_del_record(tBTA_HF_CLIENT_CB_ARR* client_cb) {
216   log::verbose("");
217 
218   if (client_cb->sdp_handle != 0) {
219     if (get_legacy_stack_sdp_api()->handle.SDP_DeleteRecord(
220             client_cb->sdp_handle)) {
221       log::warn("Unable to delete SDP record handle:{}", client_cb->sdp_handle);
222     }
223     client_cb->sdp_handle = 0;
224     BTA_FreeSCN(client_cb->scn);
225     bta_sys_remove_uuid(UUID_SERVCLASS_HF_HANDSFREE);
226   }
227 }
228 
229 /*******************************************************************************
230  *
231  * Function         bta_hf_client_sdp_find_attr
232  *
233  * Description      Process SDP discovery results to find requested attribute
234  *
235  *
236  * Returns          true if results found, false otherwise.
237  *
238  ******************************************************************************/
bta_hf_client_sdp_find_attr(tBTA_HF_CLIENT_CB * client_cb)239 bool bta_hf_client_sdp_find_attr(tBTA_HF_CLIENT_CB* client_cb) {
240   tSDP_DISC_REC* p_rec = NULL;
241   tSDP_DISC_ATTR* p_attr;
242   tSDP_PROTOCOL_ELEM pe;
243   bool result = false;
244 
245   client_cb->peer_version = HFP_VERSION_1_1; /* Default version */
246 
247   /* loop through all records we found */
248   while (true) {
249     /* get next record; if none found, we're done */
250     p_rec = get_legacy_stack_sdp_api()->db.SDP_FindServiceInDb(
251         client_cb->p_disc_db, UUID_SERVCLASS_AG_HANDSFREE, p_rec);
252     if (p_rec == NULL) {
253       break;
254     }
255 
256     /* get scn from proto desc list if initiator */
257     if (client_cb->role == BTA_HF_CLIENT_INT) {
258       if (get_legacy_stack_sdp_api()->record.SDP_FindProtocolListElemInRec(
259               p_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
260         client_cb->peer_scn = (uint8_t)pe.params[0];
261       } else {
262         continue;
263       }
264     }
265 
266     /* get profile version (if failure, version parameter is not updated) */
267     if (!get_legacy_stack_sdp_api()->record.SDP_FindProfileVersionInRec(
268             p_rec, UUID_SERVCLASS_HF_HANDSFREE, &client_cb->peer_version)) {
269       log::warn("Uable to find HFP profile version in SDP record peer:{}",
270                 p_rec->remote_bd_addr);
271     }
272 
273     /* get features */
274     p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
275         p_rec, ATTR_ID_SUPPORTED_FEATURES);
276     if (p_attr != NULL &&
277         SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE &&
278         SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) {
279       /* Found attribute. Get value. */
280       /* There might be race condition between SDP and BRSF.  */
281       /* Do not update if we already received BRSF.           */
282       if (client_cb->peer_features == 0) {
283         client_cb->peer_features = p_attr->attr_value.v.u16;
284 
285         /* SDP and BRSF WBS bit are different, correct it if set */
286         if (client_cb->peer_features & 0x0020) {
287           client_cb->peer_features &= ~0x0020;
288           client_cb->peer_features |= BTA_HF_CLIENT_PEER_CODEC;
289         }
290 
291         /* get network for ability to reject calls */
292         p_attr = get_legacy_stack_sdp_api()->record.SDP_FindAttributeInRec(
293             p_rec, ATTR_ID_NETWORK);
294         if (p_attr != NULL &&
295             SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UINT_DESC_TYPE &&
296             SDP_DISC_ATTR_LEN(p_attr->attr_len_type) >= 2) {
297           if (p_attr->attr_value.v.u16 == 0x01) {
298             client_cb->peer_features |= BTA_HF_CLIENT_PEER_REJECT;
299           }
300         }
301       }
302     }
303 
304     /* found what we needed */
305     result = true;
306     break;
307   }
308 
309   log::verbose("peer_version=0x{:x} peer_features=0x{:x}",
310                client_cb->peer_version, client_cb->peer_features);
311 
312   return result;
313 }
314 
315 /*******************************************************************************
316  *
317  * Function         bta_hf_client_do_disc
318  *
319  * Description      Do service discovery.
320  *
321  *
322  * Returns          void
323  *
324  ******************************************************************************/
bta_hf_client_do_disc(tBTA_HF_CLIENT_CB * client_cb)325 void bta_hf_client_do_disc(tBTA_HF_CLIENT_CB* client_cb) {
326   Uuid uuid_list[1];
327   uint16_t num_uuid = 1;
328   uint16_t attr_list[4];
329   uint8_t num_attr;
330   bool db_inited = false;
331 
332   /* initiator; get proto list and features */
333   if (client_cb->role == BTA_HF_CLIENT_INT) {
334     attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
335     attr_list[1] = ATTR_ID_PROTOCOL_DESC_LIST;
336     attr_list[2] = ATTR_ID_BT_PROFILE_DESC_LIST;
337     attr_list[3] = ATTR_ID_SUPPORTED_FEATURES;
338     num_attr = 4;
339     uuid_list[0] = Uuid::From16Bit(UUID_SERVCLASS_AG_HANDSFREE);
340   }
341   /* acceptor; get features */
342   else {
343     attr_list[0] = ATTR_ID_SERVICE_CLASS_ID_LIST;
344     attr_list[1] = ATTR_ID_BT_PROFILE_DESC_LIST;
345     attr_list[2] = ATTR_ID_SUPPORTED_FEATURES;
346     num_attr = 3;
347     uuid_list[0] = Uuid::From16Bit(UUID_SERVCLASS_AG_HANDSFREE);
348   }
349 
350   /* allocate buffer for sdp database */
351   client_cb->p_disc_db = (tSDP_DISCOVERY_DB*)osi_malloc(BT_DEFAULT_BUFFER_SIZE);
352 
353   /* set up service discovery database; attr happens to be attr_list len */
354   db_inited = get_legacy_stack_sdp_api()->service.SDP_InitDiscoveryDb(
355       client_cb->p_disc_db, BT_DEFAULT_BUFFER_SIZE, num_uuid, uuid_list,
356       num_attr, attr_list);
357 
358   if (db_inited) {
359     /*Service discovery not initiated */
360     db_inited =
361         get_legacy_stack_sdp_api()->service.SDP_ServiceSearchAttributeRequest2(
362             client_cb->peer_addr, client_cb->p_disc_db,
363             base::BindRepeating(&bta_hf_client_sdp_cback, client_cb));
364   }
365 
366   if (!db_inited) {
367     log::warn("Unable to start SDP service search request peer:{}",
368               client_cb->peer_addr);
369     /*free discover db */
370     osi_free_and_reset((void**)&client_cb->p_disc_db);
371     /* sent failed event */
372     tBTA_HF_CLIENT_DATA msg;
373     msg.hdr.layer_specific = client_cb->handle;
374     bta_hf_client_sm_execute(BTA_HF_CLIENT_DISC_FAIL_EVT, &msg);
375   }
376 }
377 
378 /*******************************************************************************
379  *
380  * Function         bta_hf_client_free_db
381  *
382  * Description      Free discovery database.
383  *
384  *
385  * Returns          void
386  *
387  ******************************************************************************/
bta_hf_client_free_db(tBTA_HF_CLIENT_DATA * p_data)388 void bta_hf_client_free_db(tBTA_HF_CLIENT_DATA* p_data) {
389   log::assert_that(p_data != NULL, "assert failed: p_data != NULL");
390   tBTA_HF_CLIENT_CB* client_cb =
391       bta_hf_client_find_cb_by_handle(p_data->hdr.layer_specific);
392   if (client_cb == NULL) {
393     log::error("cb not found for handle {}", p_data->hdr.layer_specific);
394     return;
395   }
396 
397   osi_free_and_reset((void**)&client_cb->p_disc_db);
398 }
399