1 /******************************************************************************
2 *
3 * Copyright 2008-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /******************************************************************************
20 *
21 * this file contains the main GATT server attributes access request
22 * handling functions.
23 *
24 ******************************************************************************/
25
26 #include <map>
27
28 #include "base/callback.h"
29 #include "bt_target.h"
30 #include "bt_utils.h"
31
32 #include "gatt_api.h"
33 #include "gatt_int.h"
34 #include "osi/include/osi.h"
35
36 using base::StringPrintf;
37 using bluetooth::Uuid;
38
39 #define BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK 0x01
40
41 #define BLE_GATT_CL_SUP_FEAT_CACHING_BITMASK 0x01
42 #define BLE_GATT_CL_SUP_FEAT_EATT_BITMASK 0x02
43
44 using gatt_eatt_support_cb = base::OnceCallback<void(const RawAddress&, bool)>;
45
46 typedef struct {
47 uint16_t op_uuid;
48 gatt_eatt_support_cb cb;
49 } gatt_op_cb_data;
50
51 static std::map<uint16_t, gatt_op_cb_data> OngoingOps;
52
53 static void gatt_request_cback(uint16_t conn_id, uint32_t trans_id,
54 uint8_t op_code, tGATTS_DATA* p_data);
55 static void gatt_connect_cback(UNUSED_ATTR tGATT_IF gatt_if,
56 const RawAddress& bda, uint16_t conn_id,
57 bool connected, tGATT_DISCONN_REASON reason,
58 tBT_TRANSPORT transport);
59 static void gatt_disc_res_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
60 tGATT_DISC_RES* p_data);
61 static void gatt_disc_cmpl_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
62 tGATT_STATUS status);
63 static void gatt_cl_op_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
64 tGATT_STATUS status,
65 tGATT_CL_COMPLETE* p_data);
66
67 static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB* p_clcb);
68
69 static tGATT_CBACK gatt_profile_cback = {gatt_connect_cback,
70 gatt_cl_op_cmpl_cback,
71 gatt_disc_res_cback,
72 gatt_disc_cmpl_cback,
73 gatt_request_cback,
74 NULL,
75 NULL,
76 NULL,
77 NULL};
78
79 /*******************************************************************************
80 *
81 * Function gatt_profile_find_conn_id_by_bd_addr
82 *
83 * Description Find the connection ID by remote address
84 *
85 * Returns Connection ID
86 *
87 ******************************************************************************/
gatt_profile_find_conn_id_by_bd_addr(const RawAddress & remote_bda)88 uint16_t gatt_profile_find_conn_id_by_bd_addr(const RawAddress& remote_bda) {
89 uint16_t conn_id = GATT_INVALID_CONN_ID;
90 GATT_GetConnIdIfConnected(gatt_cb.gatt_if, remote_bda, &conn_id,
91 BT_TRANSPORT_LE);
92 if (conn_id == GATT_INVALID_CONN_ID)
93 GATT_GetConnIdIfConnected(gatt_cb.gatt_if, remote_bda, &conn_id,
94 BT_TRANSPORT_BR_EDR);
95 return conn_id;
96 }
97
98 /*******************************************************************************
99 *
100 * Function gatt_profile_find_clcb_by_conn_id
101 *
102 * Description find clcb by Connection ID
103 *
104 * Returns Pointer to the found link conenction control block.
105 *
106 ******************************************************************************/
gatt_profile_find_clcb_by_conn_id(uint16_t conn_id)107 static tGATT_PROFILE_CLCB* gatt_profile_find_clcb_by_conn_id(uint16_t conn_id) {
108 uint8_t i_clcb;
109 tGATT_PROFILE_CLCB* p_clcb = NULL;
110
111 for (i_clcb = 0, p_clcb = gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS;
112 i_clcb++, p_clcb++) {
113 if (p_clcb->in_use && p_clcb->conn_id == conn_id) return p_clcb;
114 }
115
116 return NULL;
117 }
118
119 /*******************************************************************************
120 *
121 * Function gatt_profile_find_clcb_by_bd_addr
122 *
123 * Description The function searches all LCBs with macthing bd address.
124 *
125 * Returns Pointer to the found link conenction control block.
126 *
127 ******************************************************************************/
gatt_profile_find_clcb_by_bd_addr(const RawAddress & bda,tBT_TRANSPORT transport)128 static tGATT_PROFILE_CLCB* gatt_profile_find_clcb_by_bd_addr(
129 const RawAddress& bda, tBT_TRANSPORT transport) {
130 uint8_t i_clcb;
131 tGATT_PROFILE_CLCB* p_clcb = NULL;
132
133 for (i_clcb = 0, p_clcb = gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS;
134 i_clcb++, p_clcb++) {
135 if (p_clcb->in_use && p_clcb->transport == transport && p_clcb->connected &&
136 p_clcb->bda == bda)
137 return p_clcb;
138 }
139
140 return NULL;
141 }
142
143 /*******************************************************************************
144 *
145 * Function gatt_profile_clcb_alloc
146 *
147 * Description The function allocates a GATT profile connection link
148 * control block
149 *
150 * Returns NULL if not found. Otherwise pointer to the connection link
151 * block.
152 *
153 ******************************************************************************/
gatt_profile_clcb_alloc(uint16_t conn_id,const RawAddress & bda,tBT_TRANSPORT tranport)154 tGATT_PROFILE_CLCB* gatt_profile_clcb_alloc(uint16_t conn_id,
155 const RawAddress& bda,
156 tBT_TRANSPORT tranport) {
157 uint8_t i_clcb = 0;
158 tGATT_PROFILE_CLCB* p_clcb = NULL;
159
160 for (i_clcb = 0, p_clcb = gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS;
161 i_clcb++, p_clcb++) {
162 if (!p_clcb->in_use) {
163 p_clcb->in_use = true;
164 p_clcb->conn_id = conn_id;
165 p_clcb->connected = true;
166 p_clcb->transport = tranport;
167 p_clcb->bda = bda;
168 break;
169 }
170 }
171 if (i_clcb < GATT_MAX_APPS) return p_clcb;
172
173 return NULL;
174 }
175
176 /*******************************************************************************
177 *
178 * Function gatt_profile_clcb_dealloc
179 *
180 * Description The function deallocates a GATT profile connection link
181 * control block
182 *
183 * Returns void
184 *
185 ******************************************************************************/
gatt_profile_clcb_dealloc(tGATT_PROFILE_CLCB * p_clcb)186 void gatt_profile_clcb_dealloc(tGATT_PROFILE_CLCB* p_clcb) {
187 memset(p_clcb, 0, sizeof(tGATT_PROFILE_CLCB));
188 }
189
190 /** GAP Attributes Database Request callback */
read_attr_value(uint16_t handle,tGATT_VALUE * p_value,bool is_long)191 tGATT_STATUS read_attr_value(uint16_t handle, tGATT_VALUE* p_value,
192 bool is_long) {
193 uint8_t* p = p_value->value;
194
195 if (handle == gatt_cb.handle_sr_supported_feat) {
196 /* GATT_UUID_SERVER_SUP_FEAT*/
197 if (is_long) return GATT_NOT_LONG;
198
199 UINT8_TO_STREAM(p, gatt_cb.gatt_svr_supported_feat_mask);
200 p_value->len = sizeof(gatt_cb.gatt_svr_supported_feat_mask);
201 return GATT_SUCCESS;
202 }
203
204 if (handle == gatt_cb.handle_cl_supported_feat) {
205 /*GATT_UUID_CLIENT_SUP_FEAT */
206 if (is_long) return GATT_NOT_LONG;
207
208 /* Here we need to have value per peer device, for now we can always
209 * return 0 and wait for the peer to write it back. We actually don't
210 * care too much as we are also server, so peer knows we do support eatt.
211 */
212 UINT8_TO_STREAM(p, 0);
213 p_value->len = 1;
214 return GATT_SUCCESS;
215 }
216
217 if (handle == gatt_cb.handle_of_h_r) {
218 /* GATT_UUID_GATT_SRV_CHGD */
219 return GATT_READ_NOT_PERMIT;
220 }
221
222 return GATT_NOT_FOUND;
223 }
224
225 /** GAP Attributes Database Read/Read Blob Request process */
proc_read_req(tGATTS_REQ_TYPE,tGATT_READ_REQ * p_data,tGATTS_RSP * p_rsp)226 tGATT_STATUS proc_read_req(tGATTS_REQ_TYPE, tGATT_READ_REQ* p_data,
227 tGATTS_RSP* p_rsp) {
228 if (p_data->is_long) p_rsp->attr_value.offset = p_data->offset;
229
230 p_rsp->attr_value.handle = p_data->handle;
231
232 return read_attr_value(p_data->handle, &p_rsp->attr_value, p_data->is_long);
233 }
234
235 /** GAP ATT server process a write request */
proc_write_req(tGATTS_REQ_TYPE,tGATT_WRITE_REQ * p_data)236 uint8_t proc_write_req(tGATTS_REQ_TYPE, tGATT_WRITE_REQ* p_data) {
237 /* GATT_UUID_SERVER_SUP_FEAT*/
238 if (p_data->handle == gatt_cb.handle_sr_supported_feat)
239 return GATT_WRITE_NOT_PERMIT;
240
241 /* GATT_UUID_CLIENT_SUP_FEAT:
242 * TODO: We should store the value here, but we don't need it for now.
243 * Just acknowledge write success.
244 */
245 if (p_data->handle == gatt_cb.handle_cl_supported_feat) return GATT_SUCCESS;
246
247 /* GATT_UUID_GATT_SRV_CHGD */
248 if (p_data->handle == gatt_cb.handle_of_h_r) return GATT_WRITE_NOT_PERMIT;
249
250 return GATT_NOT_FOUND;
251 }
252
253 /*******************************************************************************
254 *
255 * Function gatt_request_cback
256 *
257 * Description GATT profile attribute access request callback.
258 *
259 * Returns void.
260 *
261 ******************************************************************************/
gatt_request_cback(uint16_t conn_id,uint32_t trans_id,tGATTS_REQ_TYPE type,tGATTS_DATA * p_data)262 static void gatt_request_cback(uint16_t conn_id, uint32_t trans_id,
263 tGATTS_REQ_TYPE type, tGATTS_DATA* p_data) {
264 uint8_t status = GATT_INVALID_PDU;
265 tGATTS_RSP rsp_msg;
266 bool rsp_needed = true;
267
268 memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
269
270 switch (type) {
271 case GATTS_REQ_TYPE_READ_CHARACTERISTIC:
272 case GATTS_REQ_TYPE_READ_DESCRIPTOR:
273 status = proc_read_req(type, &p_data->read_req, &rsp_msg);
274 break;
275
276 case GATTS_REQ_TYPE_WRITE_CHARACTERISTIC:
277 case GATTS_REQ_TYPE_WRITE_DESCRIPTOR:
278 case GATTS_REQ_TYPE_WRITE_EXEC:
279 case GATT_CMD_WRITE:
280 if (!p_data->write_req.need_rsp) rsp_needed = false;
281
282 status = proc_write_req(type, &p_data->write_req);
283 break;
284
285 case GATTS_REQ_TYPE_MTU:
286 VLOG(1) << "Get MTU exchange new mtu size: " << +p_data->mtu;
287 rsp_needed = false;
288 break;
289
290 default:
291 VLOG(1) << "Unknown/unexpected LE GAP ATT request: " << loghex(type);
292 break;
293 }
294
295 if (rsp_needed) GATTS_SendRsp(conn_id, trans_id, status, &rsp_msg);
296 }
297
298 /*******************************************************************************
299 *
300 * Function gatt_connect_cback
301 *
302 * Description Gatt profile connection callback.
303 *
304 * Returns void
305 *
306 ******************************************************************************/
gatt_connect_cback(UNUSED_ATTR tGATT_IF gatt_if,const RawAddress & bda,uint16_t conn_id,bool connected,tGATT_DISCONN_REASON reason,tBT_TRANSPORT transport)307 static void gatt_connect_cback(UNUSED_ATTR tGATT_IF gatt_if,
308 const RawAddress& bda, uint16_t conn_id,
309 bool connected, tGATT_DISCONN_REASON reason,
310 tBT_TRANSPORT transport) {
311 VLOG(1) << __func__ << ": from " << bda << " connected: " << connected
312 << ", conn_id: " << loghex(conn_id) << "reason: " << loghex(reason);
313
314 tGATT_PROFILE_CLCB* p_clcb =
315 gatt_profile_find_clcb_by_bd_addr(bda, transport);
316 if (p_clcb == NULL) return;
317
318 if (connected) {
319 p_clcb->conn_id = conn_id;
320 p_clcb->connected = true;
321
322 if (p_clcb->ccc_stage == GATT_SVC_CHANGED_CONNECTING) {
323 p_clcb->ccc_stage++;
324 gatt_cl_start_config_ccc(p_clcb);
325 }
326 } else {
327 gatt_profile_clcb_dealloc(p_clcb);
328 }
329 }
330
331 /*******************************************************************************
332 *
333 * Function gatt_profile_db_init
334 *
335 * Description Initializa the GATT profile attribute database.
336 *
337 ******************************************************************************/
gatt_profile_db_init(void)338 void gatt_profile_db_init(void) {
339 uint16_t service_handle = 0;
340
341 /* Fill our internal UUID with a fixed pattern 0x81 */
342 std::array<uint8_t, Uuid::kNumBytes128> tmp;
343 tmp.fill(0x81);
344
345 /* Create a GATT profile service */
346 gatt_cb.gatt_if = GATT_Register(Uuid::From128BitBE(tmp), &gatt_profile_cback);
347 GATT_StartIf(gatt_cb.gatt_if);
348
349 Uuid service_uuid = Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER);
350
351 Uuid srv_changed_char_uuid = Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD);
352 Uuid svr_sup_feat_uuid = Uuid::From16Bit(GATT_UUID_SERVER_SUP_FEAT);
353 Uuid cl_sup_feat_uuid = Uuid::From16Bit(GATT_UUID_CLIENT_SUP_FEAT);
354
355 btgatt_db_element_t service[] = {
356 {
357 .uuid = service_uuid,
358 .type = BTGATT_DB_PRIMARY_SERVICE,
359 },
360 {
361 .uuid = srv_changed_char_uuid,
362 .type = BTGATT_DB_CHARACTERISTIC,
363 .properties = GATT_CHAR_PROP_BIT_INDICATE,
364 .permissions = 0,
365 },
366 {
367 .type = BTGATT_DB_CHARACTERISTIC,
368 .uuid = svr_sup_feat_uuid,
369 .properties = GATT_CHAR_PROP_BIT_READ,
370 .permissions = GATT_PERM_READ,
371 },
372 {
373 .type = BTGATT_DB_CHARACTERISTIC,
374 .uuid = cl_sup_feat_uuid,
375 .properties = GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE,
376 .permissions = GATT_PERM_READ | GATT_PERM_WRITE,
377 }};
378
379 GATTS_AddService(gatt_cb.gatt_if, service,
380 sizeof(service) / sizeof(btgatt_db_element_t));
381
382 service_handle = service[0].attribute_handle;
383 gatt_cb.handle_of_h_r = service[1].attribute_handle;
384 gatt_cb.handle_sr_supported_feat = service[2].attribute_handle;
385 gatt_cb.handle_cl_supported_feat = service[3].attribute_handle;
386
387 gatt_cb.gatt_svr_supported_feat_mask |= BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK;
388 gatt_cb.gatt_cl_supported_feat_mask |= BLE_GATT_CL_SUP_FEAT_EATT_BITMASK;
389
390 VLOG(1) << __func__ << ": gatt_if=" << gatt_cb.gatt_if << " EATT supported";
391 }
392
393 /*******************************************************************************
394 *
395 * Function gatt_disc_res_cback
396 *
397 * Description Gatt profile discovery result callback
398 *
399 * Returns void
400 *
401 ******************************************************************************/
gatt_disc_res_cback(uint16_t conn_id,tGATT_DISC_TYPE disc_type,tGATT_DISC_RES * p_data)402 static void gatt_disc_res_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
403 tGATT_DISC_RES* p_data) {
404 tGATT_PROFILE_CLCB* p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
405
406 if (p_clcb == NULL) return;
407
408 switch (disc_type) {
409 case GATT_DISC_SRVC_BY_UUID: /* stage 1 */
410 p_clcb->e_handle = p_data->value.group_value.e_handle;
411 p_clcb->ccc_result++;
412 break;
413
414 case GATT_DISC_CHAR: /* stage 2 */
415 p_clcb->s_handle = p_data->value.dclr_value.val_handle;
416 p_clcb->ccc_result++;
417 break;
418
419 case GATT_DISC_CHAR_DSCPT: /* stage 3 */
420 if (p_data->type == Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG)) {
421 p_clcb->s_handle = p_data->handle;
422 p_clcb->ccc_result++;
423 }
424 break;
425 }
426 }
427
428 /*******************************************************************************
429 *
430 * Function gatt_disc_cmpl_cback
431 *
432 * Description Gatt profile discovery complete callback
433 *
434 * Returns void
435 *
436 ******************************************************************************/
gatt_disc_cmpl_cback(uint16_t conn_id,tGATT_DISC_TYPE disc_type,tGATT_STATUS status)437 static void gatt_disc_cmpl_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
438 tGATT_STATUS status) {
439 tGATT_PROFILE_CLCB* p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
440
441 if (p_clcb == NULL) return;
442
443 if (status != GATT_SUCCESS || p_clcb->ccc_result == 0) {
444 LOG(WARNING) << __func__
445 << ": Unable to register for service changed indication";
446 return;
447 }
448
449 p_clcb->ccc_result = 0;
450 p_clcb->ccc_stage++;
451 gatt_cl_start_config_ccc(p_clcb);
452 }
453
gatt_attr_send_is_eatt_cb(uint16_t conn_id,gatt_op_cb_data * cb,bool eatt_supported)454 static void gatt_attr_send_is_eatt_cb(uint16_t conn_id, gatt_op_cb_data* cb,
455 bool eatt_supported) {
456 tGATT_IF gatt_if;
457 RawAddress bd_addr;
458 tBT_TRANSPORT transport;
459
460 GATT_GetConnectionInfor(conn_id, &gatt_if, bd_addr, &transport);
461
462 std::move(cb->cb).Run(bd_addr, eatt_supported);
463
464 cb->op_uuid = 0;
465 }
466
gatt_svc_read_cl_supp_feat_req(uint16_t conn_id,gatt_op_cb_data * cb)467 static bool gatt_svc_read_cl_supp_feat_req(uint16_t conn_id,
468 gatt_op_cb_data* cb) {
469 tGATT_READ_PARAM param;
470
471 memset(¶m, 0, sizeof(tGATT_READ_PARAM));
472
473 param.service.s_handle = 1;
474 param.service.e_handle = 0xFFFF;
475 param.service.auth_req = 0;
476
477 param.service.uuid = bluetooth::Uuid::From16Bit(GATT_UUID_CLIENT_SUP_FEAT);
478
479 tGATT_STATUS status = GATTC_Read(conn_id, GATT_READ_BY_TYPE, ¶m);
480 if (status != GATT_SUCCESS) {
481 LOG(ERROR) << __func__ << " Read failed. Status: " << loghex(status);
482 return false;
483 }
484
485 cb->op_uuid = GATT_UUID_CLIENT_SUP_FEAT;
486 return true;
487 }
488
gatt_att_write_cl_supp_feat(uint16_t conn_id,uint16_t handle)489 static bool gatt_att_write_cl_supp_feat(uint16_t conn_id, uint16_t handle) {
490 tGATT_VALUE attr;
491
492 memset(&attr, 0, sizeof(tGATT_VALUE));
493
494 attr.conn_id = conn_id;
495 attr.handle = handle;
496 attr.len = 1;
497 attr.value[0] = gatt_cb.gatt_cl_supported_feat_mask;
498
499 tGATT_STATUS status = GATTC_Write(conn_id, GATT_WRITE, &attr);
500 if (status != GATT_SUCCESS) {
501 LOG(ERROR) << __func__ << " Write failed. Status: " << loghex(status);
502 return false;
503 }
504
505 return true;
506 }
507
508 /*******************************************************************************
509 *
510 * Function gatt_cl_op_cmpl_cback
511 *
512 * Description Gatt profile client operation complete callback
513 *
514 * Returns void
515 *
516 ******************************************************************************/
gatt_cl_op_cmpl_cback(uint16_t conn_id,tGATTC_OPTYPE op,tGATT_STATUS status,tGATT_CL_COMPLETE * p_data)517 static void gatt_cl_op_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
518 tGATT_STATUS status,
519 tGATT_CL_COMPLETE* p_data) {
520 auto iter = OngoingOps.find(conn_id);
521
522 VLOG(1) << __func__ << " opcode: " << loghex(op)
523 << " status: " << loghex(status) << " conn id: " << loghex(conn_id);
524
525 if (op != GATTC_OPTYPE_READ) return;
526
527 if (iter == OngoingOps.end()) {
528 LOG(ERROR) << __func__ << " Unexpected read complete";
529 return;
530 }
531
532 gatt_op_cb_data* operation_callback_data = &iter->second;
533 uint16_t cl_op_uuid = operation_callback_data->op_uuid;
534
535 uint8_t* pp = p_data->att_value.value;
536
537 VLOG(1) << __func__ << " cl_op_uuid " << loghex(cl_op_uuid);
538
539 switch (cl_op_uuid) {
540 case GATT_UUID_SERVER_SUP_FEAT: {
541 uint8_t supported_feat_mask = 0;
542
543 /* Check if EATT is supported */
544 if (status == GATT_SUCCESS) {
545 STREAM_TO_UINT8(supported_feat_mask, pp);
546 }
547
548 /* Notify user if eatt is supported */
549 bool eatt_supported =
550 supported_feat_mask & BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK;
551 gatt_attr_send_is_eatt_cb(conn_id, operation_callback_data,
552 eatt_supported);
553
554 /* If server supports EATT lets try to find handle for the
555 * client supported features characteristic, where we could write
556 * our supported features as a client.
557 */
558 if (eatt_supported) {
559 /* If read succeed, return here */
560 if (gatt_svc_read_cl_supp_feat_req(conn_id, operation_callback_data))
561 return;
562 }
563
564 /* Could not read client supported charcteristic or eatt is not
565 * supported. Erase callback data now.
566 */
567 OngoingOps.erase(iter);
568 break;
569 }
570 case GATT_UUID_CLIENT_SUP_FEAT:
571 /*We don't need callback data anymore */
572 OngoingOps.erase(iter);
573
574 if (status != GATT_SUCCESS) {
575 LOG(INFO) << __func__
576 << " Client supported features charcteristic not found";
577 return;
578 }
579
580 /* Write our client supported features to the remote device */
581 gatt_att_write_cl_supp_feat(conn_id, p_data->att_value.handle);
582 break;
583 }
584 }
585
586 /*******************************************************************************
587 *
588 * Function gatt_cl_start_config_ccc
589 *
590 * Description Gatt profile start configure service change CCC
591 *
592 * Returns void
593 *
594 ******************************************************************************/
gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB * p_clcb)595 static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB* p_clcb) {
596
597 VLOG(1) << __func__ << ": stage: " << +p_clcb->ccc_stage;
598
599 switch (p_clcb->ccc_stage) {
600 case GATT_SVC_CHANGED_SERVICE: /* discover GATT service */
601 GATTC_Discover(p_clcb->conn_id, GATT_DISC_SRVC_BY_UUID, 0x0001, 0xffff,
602 Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER));
603 break;
604
605 case GATT_SVC_CHANGED_CHARACTERISTIC: /* discover service change char */
606 GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR, 0x0001, p_clcb->e_handle,
607 Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD));
608 break;
609
610 case GATT_SVC_CHANGED_DESCRIPTOR: /* discover service change ccc */
611 GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR_DSCPT, p_clcb->s_handle,
612 p_clcb->e_handle);
613 break;
614
615 case GATT_SVC_CHANGED_CONFIGURE_CCCD: /* write ccc */
616 {
617 tGATT_VALUE ccc_value;
618 memset(&ccc_value, 0, sizeof(tGATT_VALUE));
619 ccc_value.handle = p_clcb->s_handle;
620 ccc_value.len = 2;
621 ccc_value.value[0] = GATT_CLT_CONFIG_INDICATION;
622 GATTC_Write(p_clcb->conn_id, GATT_WRITE, &ccc_value);
623 break;
624 }
625 }
626 }
627
628 /*******************************************************************************
629 *
630 * Function GATT_ConfigServiceChangeCCC
631 *
632 * Description Configure service change indication on remote device
633 *
634 * Returns none
635 *
636 ******************************************************************************/
GATT_ConfigServiceChangeCCC(const RawAddress & remote_bda,bool enable,tBT_TRANSPORT transport)637 void GATT_ConfigServiceChangeCCC(const RawAddress& remote_bda, bool enable,
638 tBT_TRANSPORT transport) {
639 tGATT_PROFILE_CLCB* p_clcb =
640 gatt_profile_find_clcb_by_bd_addr(remote_bda, transport);
641
642 if (p_clcb == NULL)
643 p_clcb = gatt_profile_clcb_alloc(0, remote_bda, transport);
644
645 if (p_clcb == NULL) return;
646
647 if (GATT_GetConnIdIfConnected(gatt_cb.gatt_if, remote_bda, &p_clcb->conn_id,
648 transport)) {
649 p_clcb->connected = true;
650 }
651 /* hold the link here */
652 GATT_Connect(gatt_cb.gatt_if, remote_bda, true, transport, true);
653 p_clcb->ccc_stage = GATT_SVC_CHANGED_CONNECTING;
654
655 if (!p_clcb->connected) {
656 /* wait for connection */
657 return;
658 }
659
660 p_clcb->ccc_stage++;
661 gatt_cl_start_config_ccc(p_clcb);
662 }
663
664 /*******************************************************************************
665 *
666 * Function gatt_svc_read_supp_feat_req
667 *
668 * Description Read remote device supported GATT feature mask.
669 *
670 * Returns bool
671 *
672 ******************************************************************************/
gatt_svc_read_supp_feat_req(const RawAddress & peer_bda,uint16_t conn_id,base::OnceCallback<void (const RawAddress &,bool)> cb)673 static bool gatt_svc_read_supp_feat_req(
674 const RawAddress& peer_bda, uint16_t conn_id,
675 base::OnceCallback<void(const RawAddress&, bool)> cb) {
676 tGATT_READ_PARAM param;
677 tGATT_PROFILE_CLCB* p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
678
679 if (!p_clcb) {
680 p_clcb = gatt_profile_clcb_alloc(conn_id, peer_bda, BT_TRANSPORT_LE);
681 }
682
683 if (!p_clcb) {
684 VLOG(1) << __func__ << " p_clcb is NULL " << loghex(conn_id);
685 return false;
686 }
687
688 auto it = OngoingOps.find(conn_id);
689 if (it != OngoingOps.end()) {
690 LOG(ERROR) << __func__ << " There is ongoing operation for conn_id: "
691 << loghex(conn_id);
692 return false;
693 }
694
695 memset(¶m, 0, sizeof(tGATT_READ_PARAM));
696
697 param.service.s_handle = 1;
698 param.service.e_handle = 0xFFFF;
699 param.service.auth_req = 0;
700
701 param.service.uuid = bluetooth::Uuid::From16Bit(GATT_UUID_SERVER_SUP_FEAT);
702
703 if (GATTC_Read(conn_id, GATT_READ_BY_TYPE, ¶m) != GATT_SUCCESS) {
704 LOG(ERROR) << __func__ << " Read GATT Support features GATT_Read Failed";
705 return false;
706 }
707
708 gatt_op_cb_data cb_data;
709 cb_data.cb = std::move(cb);
710 cb_data.op_uuid = GATT_UUID_SERVER_SUP_FEAT;
711 OngoingOps[conn_id] = std::move(cb_data);
712
713 return true;
714 }
715
716 /*******************************************************************************
717 *
718 * Function gatt_profile_get_eatt_support
719 *
720 * Description Check if EATT is supported with remote device.
721 *
722 * Returns false in case read could not be sent.
723 *
724 ******************************************************************************/
gatt_profile_get_eatt_support(const RawAddress & remote_bda,base::OnceCallback<void (const RawAddress &,bool)> cb)725 bool gatt_profile_get_eatt_support(
726 const RawAddress& remote_bda,
727 base::OnceCallback<void(const RawAddress&, bool)> cb) {
728 uint16_t conn_id;
729
730 if (!cb) return false;
731
732 VLOG(1) << __func__ << " BDA: " << remote_bda
733 << " read gatt supported features";
734
735 GATT_GetConnIdIfConnected(gatt_cb.gatt_if, remote_bda, &conn_id,
736 BT_TRANSPORT_LE);
737
738 /* This read is important only when connected */
739 if (conn_id == GATT_INVALID_CONN_ID) return false;
740
741 return gatt_svc_read_supp_feat_req(remote_bda, conn_id, std::move(cb));
742 }
743