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