• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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