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 <bluetooth/log.h>
27
28 #include <deque>
29 #include <map>
30
31 #include "base/functional/callback.h"
32 #include "btif/include/btif_storage.h"
33 #include "eatt/eatt.h"
34 #include "gatt_api.h"
35 #include "gatt_int.h"
36 #include "internal_include/bt_target.h"
37 #include "stack/include/bt_types.h"
38 #include "stack/include/bt_uuid16.h"
39 #include "stack/include/btm_sec_api.h"
40 #include "types/bluetooth/uuid.h"
41 #include "types/raw_address.h"
42
43 using base::StringPrintf;
44 using bluetooth::Uuid;
45 using namespace bluetooth;
46
47 #define BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK 0x01
48
49 #define BLE_GATT_CL_SUP_FEAT_CACHING_BITMASK 0x01
50 #define BLE_GATT_CL_SUP_FEAT_EATT_BITMASK 0x02
51 #define BLE_GATT_CL_SUP_FEAT_MULTI_NOTIF_BITMASK 0x04
52
53 #define BLE_GATT_CL_ANDROID_SUP_FEAT \
54 (BLE_GATT_CL_SUP_FEAT_EATT_BITMASK | BLE_GATT_CL_SUP_FEAT_MULTI_NOTIF_BITMASK)
55
56 using gatt_sr_supported_feat_cb =
57 base::OnceCallback<void(const RawAddress&, uint8_t)>;
58 using gatt_sirk_cb = base::OnceCallback<void(
59 tGATT_STATUS status, const RawAddress&, uint8_t sirk_type, Octet16& sirk)>;
60
61 typedef struct {
62 uint16_t op_uuid;
63 gatt_sr_supported_feat_cb cb;
64 gatt_sirk_cb sirk_cb;
65 } gatt_op_cb_data;
66
67 static std::map<uint16_t, std::deque<gatt_op_cb_data>> OngoingOps;
68
69 static void gatt_request_cback(uint16_t conn_id, uint32_t trans_id,
70 uint8_t op_code, tGATTS_DATA* p_data);
71 static void gatt_connect_cback(tGATT_IF /* gatt_if */, const RawAddress& bda,
72 uint16_t conn_id, bool connected,
73 tGATT_DISCONN_REASON reason,
74 tBT_TRANSPORT transport);
75 static void gatt_disc_res_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
76 tGATT_DISC_RES* p_data);
77 static void gatt_disc_cmpl_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
78 tGATT_STATUS status);
79 static void gatt_cl_op_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
80 tGATT_STATUS status,
81 tGATT_CL_COMPLETE* p_data);
82
83 static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB* p_clcb);
84
85 static bool gatt_sr_is_robust_caching_enabled();
86
87 static bool read_sr_supported_feat_req(
88 uint16_t conn_id, base::OnceCallback<void(const RawAddress&, uint8_t)> cb);
89 static bool read_sr_sirk_req(
90 uint16_t conn_id,
91 base::OnceCallback<void(tGATT_STATUS status, const RawAddress&,
92 uint8_t sirk_type, Octet16& sirk)>
93 cb);
94
95 static tGATT_STATUS gatt_sr_read_db_hash(uint16_t conn_id,
96 tGATT_VALUE* p_value);
97 static tGATT_STATUS gatt_sr_read_cl_supp_feat(uint16_t conn_id,
98 tGATT_VALUE* p_value);
99 static tGATT_STATUS gatt_sr_write_cl_supp_feat(uint16_t conn_id,
100 tGATT_WRITE_REQ* p_data);
101
102 static tGATT_CBACK gatt_profile_cback = {
103 .p_conn_cb = gatt_connect_cback,
104 .p_cmpl_cb = gatt_cl_op_cmpl_cback,
105 .p_disc_res_cb = gatt_disc_res_cback,
106 .p_disc_cmpl_cb = gatt_disc_cmpl_cback,
107 .p_req_cb = gatt_request_cback,
108 .p_enc_cmpl_cb = nullptr,
109 .p_congestion_cb = nullptr,
110 .p_phy_update_cb = nullptr,
111 .p_conn_update_cb = nullptr,
112 .p_subrate_chg_cb = nullptr,
113 };
114
115 /*******************************************************************************
116 *
117 * Function gatt_profile_find_conn_id_by_bd_addr
118 *
119 * Description Find the connection ID by remote address
120 *
121 * Returns Connection ID
122 *
123 ******************************************************************************/
gatt_profile_find_conn_id_by_bd_addr(const RawAddress & remote_bda)124 uint16_t gatt_profile_find_conn_id_by_bd_addr(const RawAddress& remote_bda) {
125 uint16_t conn_id = GATT_INVALID_CONN_ID;
126 if (!GATT_GetConnIdIfConnected(gatt_cb.gatt_if, remote_bda, &conn_id,
127 BT_TRANSPORT_LE)) {
128 log::warn(
129 "Unable to get GATT connection id if connected peer:{} gatt_if:{} "
130 "transport:{}",
131 remote_bda, gatt_cb.gatt_if, bt_transport_text(BT_TRANSPORT_LE));
132 }
133 if (conn_id == GATT_INVALID_CONN_ID) {
134 if (!GATT_GetConnIdIfConnected(gatt_cb.gatt_if, remote_bda, &conn_id,
135 BT_TRANSPORT_BR_EDR)) {
136 log::warn(
137 "Unable to get GATT connection id if connected peer:{} gatt_if:{} "
138 "transport:{}",
139 remote_bda, gatt_cb.gatt_if, bt_transport_text(BT_TRANSPORT_BR_EDR));
140 }
141 }
142 return conn_id;
143 }
144
145 /*******************************************************************************
146 *
147 * Function gatt_profile_find_clcb_by_conn_id
148 *
149 * Description find clcb by Connection ID
150 *
151 * Returns Pointer to the found link conenction control block.
152 *
153 ******************************************************************************/
gatt_profile_find_clcb_by_conn_id(uint16_t conn_id)154 static tGATT_PROFILE_CLCB* gatt_profile_find_clcb_by_conn_id(uint16_t conn_id) {
155 uint8_t i_clcb;
156 tGATT_PROFILE_CLCB* p_clcb = NULL;
157
158 for (i_clcb = 0, p_clcb = gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS;
159 i_clcb++, p_clcb++) {
160 if (p_clcb->in_use && p_clcb->conn_id == conn_id) return p_clcb;
161 }
162
163 return NULL;
164 }
165
166 /*******************************************************************************
167 *
168 * Function gatt_profile_find_clcb_by_bd_addr
169 *
170 * Description The function searches all LCBs with macthing bd address.
171 *
172 * Returns Pointer to the found link conenction control block.
173 *
174 ******************************************************************************/
gatt_profile_find_clcb_by_bd_addr(const RawAddress & bda,tBT_TRANSPORT transport)175 static tGATT_PROFILE_CLCB* gatt_profile_find_clcb_by_bd_addr(
176 const RawAddress& bda, tBT_TRANSPORT transport) {
177 uint8_t i_clcb;
178 tGATT_PROFILE_CLCB* p_clcb = NULL;
179
180 for (i_clcb = 0, p_clcb = gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS;
181 i_clcb++, p_clcb++) {
182 if (p_clcb->in_use && p_clcb->transport == transport && p_clcb->connected &&
183 p_clcb->bda == bda)
184 return p_clcb;
185 }
186
187 return NULL;
188 }
189
190 /*******************************************************************************
191 *
192 * Function gatt_profile_clcb_alloc
193 *
194 * Description The function allocates a GATT profile connection link
195 * control block
196 *
197 * Returns NULL if not found. Otherwise pointer to the connection link
198 * block.
199 *
200 ******************************************************************************/
gatt_profile_clcb_alloc(uint16_t conn_id,const RawAddress & bda,tBT_TRANSPORT tranport)201 tGATT_PROFILE_CLCB* gatt_profile_clcb_alloc(uint16_t conn_id,
202 const RawAddress& bda,
203 tBT_TRANSPORT tranport) {
204 uint8_t i_clcb = 0;
205 tGATT_PROFILE_CLCB* p_clcb = NULL;
206
207 for (i_clcb = 0, p_clcb = gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS;
208 i_clcb++, p_clcb++) {
209 if (!p_clcb->in_use) {
210 p_clcb->in_use = true;
211 p_clcb->conn_id = conn_id;
212 p_clcb->connected = true;
213 p_clcb->transport = tranport;
214 p_clcb->bda = bda;
215 break;
216 }
217 }
218 if (i_clcb < GATT_MAX_APPS) return p_clcb;
219
220 return NULL;
221 }
222
223 /*******************************************************************************
224 *
225 * Function gatt_profile_clcb_dealloc
226 *
227 * Description The function deallocates a GATT profile connection link
228 * control block
229 *
230 * Returns void
231 *
232 ******************************************************************************/
gatt_profile_clcb_dealloc(tGATT_PROFILE_CLCB * p_clcb)233 void gatt_profile_clcb_dealloc(tGATT_PROFILE_CLCB* p_clcb) {
234 memset(p_clcb, 0, sizeof(tGATT_PROFILE_CLCB));
235 }
236
237 /** GAP Attributes Database Request callback */
read_attr_value(uint16_t conn_id,uint16_t handle,tGATT_VALUE * p_value,bool is_long)238 tGATT_STATUS read_attr_value(uint16_t conn_id, uint16_t handle,
239 tGATT_VALUE* p_value, bool is_long) {
240 uint8_t* p = p_value->value;
241
242 if (handle == gatt_cb.handle_sr_supported_feat) {
243 /* GATT_UUID_SERVER_SUP_FEAT*/
244 if (is_long) return GATT_NOT_LONG;
245
246 UINT8_TO_STREAM(p, gatt_cb.gatt_svr_supported_feat_mask);
247 p_value->len = sizeof(gatt_cb.gatt_svr_supported_feat_mask);
248 return GATT_SUCCESS;
249 }
250
251 if (handle == gatt_cb.handle_cl_supported_feat) {
252 /*GATT_UUID_CLIENT_SUP_FEAT */
253 if (is_long) return GATT_NOT_LONG;
254
255 return gatt_sr_read_cl_supp_feat(conn_id, p_value);
256 }
257
258 if (handle == gatt_cb.handle_of_database_hash) {
259 /* GATT_UUID_DATABASE_HASH */
260 if (is_long) return GATT_NOT_LONG;
261
262 return gatt_sr_read_db_hash(conn_id, p_value);
263 }
264
265 if (handle == gatt_cb.handle_of_h_r) {
266 /* GATT_UUID_GATT_SRV_CHGD */
267 return GATT_READ_NOT_PERMIT;
268 }
269
270 return GATT_NOT_FOUND;
271 }
272
273 /** GAP Attributes Database Read/Read Blob Request process */
proc_read_req(uint16_t conn_id,tGATTS_REQ_TYPE,tGATT_READ_REQ * p_data,tGATTS_RSP * p_rsp)274 tGATT_STATUS proc_read_req(uint16_t conn_id, tGATTS_REQ_TYPE,
275 tGATT_READ_REQ* p_data, tGATTS_RSP* p_rsp) {
276 if (p_data->is_long) p_rsp->attr_value.offset = p_data->offset;
277
278 p_rsp->attr_value.handle = p_data->handle;
279
280 return read_attr_value(conn_id, p_data->handle, &p_rsp->attr_value,
281 p_data->is_long);
282 }
283
284 /** GAP ATT server process a write request */
proc_write_req(uint16_t conn_id,tGATTS_REQ_TYPE,tGATT_WRITE_REQ * p_data)285 tGATT_STATUS proc_write_req(uint16_t conn_id, tGATTS_REQ_TYPE,
286 tGATT_WRITE_REQ* p_data) {
287 uint16_t handle = p_data->handle;
288
289 /* GATT_UUID_SERVER_SUP_FEAT*/
290 if (handle == gatt_cb.handle_sr_supported_feat) return GATT_WRITE_NOT_PERMIT;
291
292 /* GATT_UUID_CLIENT_SUP_FEAT*/
293 if (handle == gatt_cb.handle_cl_supported_feat)
294 return gatt_sr_write_cl_supp_feat(conn_id, p_data);
295
296 /* GATT_UUID_DATABASE_HASH */
297 if (handle == gatt_cb.handle_of_database_hash) return GATT_WRITE_NOT_PERMIT;
298
299 /* GATT_UUID_GATT_SRV_CHGD */
300 if (handle == gatt_cb.handle_of_h_r) return GATT_WRITE_NOT_PERMIT;
301
302 return GATT_NOT_FOUND;
303 }
304
305 /*******************************************************************************
306 *
307 * Function gatt_request_cback
308 *
309 * Description GATT profile attribute access request callback.
310 *
311 * Returns void.
312 *
313 ******************************************************************************/
gatt_request_cback(uint16_t conn_id,uint32_t trans_id,tGATTS_REQ_TYPE type,tGATTS_DATA * p_data)314 static void gatt_request_cback(uint16_t conn_id, uint32_t trans_id,
315 tGATTS_REQ_TYPE type, tGATTS_DATA* p_data) {
316 tGATT_STATUS status = GATT_INVALID_PDU;
317 tGATTS_RSP rsp_msg;
318 bool rsp_needed = true;
319
320 memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
321
322 switch (type) {
323 case GATTS_REQ_TYPE_READ_CHARACTERISTIC:
324 case GATTS_REQ_TYPE_READ_DESCRIPTOR:
325 status = proc_read_req(conn_id, type, &p_data->read_req, &rsp_msg);
326 break;
327
328 case GATTS_REQ_TYPE_WRITE_CHARACTERISTIC:
329 case GATTS_REQ_TYPE_WRITE_DESCRIPTOR:
330 case GATTS_REQ_TYPE_WRITE_EXEC:
331 case GATT_CMD_WRITE:
332 if (!p_data->write_req.need_rsp) rsp_needed = false;
333
334 status = proc_write_req(conn_id, type, &p_data->write_req);
335 break;
336
337 case GATTS_REQ_TYPE_MTU:
338 log::verbose("Get MTU exchange new mtu size: {}", p_data->mtu);
339 rsp_needed = false;
340 break;
341
342 default:
343 log::verbose("Unknown/unexpected LE GAP ATT request: 0x{:x}", type);
344 break;
345 }
346
347 if (rsp_needed) {
348 if (GATTS_SendRsp(conn_id, trans_id, status, &rsp_msg) != GATT_SUCCESS) {
349 log::warn("Unable to send GATT server response conn_id:{}", conn_id);
350 }
351 }
352 }
353
354 /*******************************************************************************
355 *
356 * Function gatt_connect_cback
357 *
358 * Description Gatt profile connection callback.
359 *
360 * Returns void
361 *
362 ******************************************************************************/
gatt_connect_cback(tGATT_IF,const RawAddress & bda,uint16_t conn_id,bool connected,tGATT_DISCONN_REASON,tBT_TRANSPORT transport)363 static void gatt_connect_cback(tGATT_IF /* gatt_if */, const RawAddress& bda,
364 uint16_t conn_id, bool connected,
365 tGATT_DISCONN_REASON /* reason */,
366 tBT_TRANSPORT transport) {
367 log::verbose("from {} connected: {}, conn_id: 0x{:x}", bda, connected,
368 conn_id);
369
370 // if the device is not trusted, remove data when the link is disconnected
371 if (!connected && !btm_sec_is_a_bonded_dev(bda)) {
372 log::info("remove untrusted client status, bda={}", bda);
373 btif_storage_remove_gatt_cl_supp_feat(bda);
374 btif_storage_remove_gatt_cl_db_hash(bda);
375 }
376
377 tGATT_PROFILE_CLCB* p_clcb =
378 gatt_profile_find_clcb_by_bd_addr(bda, transport);
379 if (p_clcb == NULL) return;
380
381 if (connected) {
382 p_clcb->conn_id = conn_id;
383 p_clcb->connected = true;
384
385 if (p_clcb->ccc_stage == GATT_SVC_CHANGED_CONNECTING) {
386 p_clcb->ccc_stage++;
387 gatt_cl_start_config_ccc(p_clcb);
388 }
389 } else {
390 gatt_profile_clcb_dealloc(p_clcb);
391 }
392 }
393
394 /*******************************************************************************
395 *
396 * Function gatt_profile_db_init
397 *
398 * Description Initializa the GATT profile attribute database.
399 *
400 ******************************************************************************/
gatt_profile_db_init(void)401 void gatt_profile_db_init(void) {
402 /* Fill our internal UUID with a fixed pattern 0x81 */
403 std::array<uint8_t, Uuid::kNumBytes128> tmp;
404 tmp.fill(0x81);
405
406 OngoingOps.clear();
407
408 /* Create a GATT profile service */
409 gatt_cb.gatt_if = GATT_Register(Uuid::From128BitBE(tmp), "GattProfileDb",
410 &gatt_profile_cback, false);
411 GATT_StartIf(gatt_cb.gatt_if);
412
413 Uuid service_uuid = Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER);
414
415 Uuid srv_changed_char_uuid = Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD);
416 Uuid svr_sup_feat_uuid = Uuid::From16Bit(GATT_UUID_SERVER_SUP_FEAT);
417 Uuid cl_sup_feat_uuid = Uuid::From16Bit(GATT_UUID_CLIENT_SUP_FEAT);
418 Uuid database_hash_uuid = Uuid::From16Bit(GATT_UUID_DATABASE_HASH);
419
420 btgatt_db_element_t service[] = {
421 {
422 .uuid = service_uuid,
423 .type = BTGATT_DB_PRIMARY_SERVICE,
424 },
425 {
426 .uuid = srv_changed_char_uuid,
427 .type = BTGATT_DB_CHARACTERISTIC,
428 .properties = GATT_CHAR_PROP_BIT_INDICATE,
429 .permissions = 0,
430 },
431 {
432 .uuid = svr_sup_feat_uuid,
433 .type = BTGATT_DB_CHARACTERISTIC,
434 .properties = GATT_CHAR_PROP_BIT_READ,
435 .permissions = GATT_PERM_READ,
436 },
437 {
438 .uuid = cl_sup_feat_uuid,
439 .type = BTGATT_DB_CHARACTERISTIC,
440 .properties = GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_WRITE,
441 .permissions = GATT_PERM_READ | GATT_PERM_WRITE,
442 },
443 {
444 .uuid = database_hash_uuid,
445 .type = BTGATT_DB_CHARACTERISTIC,
446 .properties = GATT_CHAR_PROP_BIT_READ,
447 .permissions = GATT_PERM_READ,
448 }};
449
450 if (GATTS_AddService(gatt_cb.gatt_if, service,
451 sizeof(service) / sizeof(btgatt_db_element_t)) !=
452 GATT_SERVICE_STARTED) {
453 log::warn("Unable to add GATT server service gatt_if:{}", gatt_cb.gatt_if);
454 }
455
456 gatt_cb.handle_of_h_r = service[1].attribute_handle;
457 gatt_cb.handle_sr_supported_feat = service[2].attribute_handle;
458 gatt_cb.handle_cl_supported_feat = service[3].attribute_handle;
459 gatt_cb.handle_of_database_hash = service[4].attribute_handle;
460
461 gatt_cb.gatt_svr_supported_feat_mask |= BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK;
462 gatt_cb.gatt_cl_supported_feat_mask |= BLE_GATT_CL_ANDROID_SUP_FEAT;
463 gatt_cb.gatt_cl_supported_feat_mask |= BLE_GATT_CL_SUP_FEAT_CACHING_BITMASK;
464
465 log::verbose("gatt_if={} EATT supported", gatt_cb.gatt_if);
466 }
467
468 /*******************************************************************************
469 *
470 * Function gatt_disc_res_cback
471 *
472 * Description Gatt profile discovery result callback
473 *
474 * Returns void
475 *
476 ******************************************************************************/
gatt_disc_res_cback(uint16_t conn_id,tGATT_DISC_TYPE disc_type,tGATT_DISC_RES * p_data)477 static void gatt_disc_res_cback(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
478 tGATT_DISC_RES* p_data) {
479 tGATT_PROFILE_CLCB* p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
480
481 if (p_clcb == NULL) return;
482
483 switch (disc_type) {
484 case GATT_DISC_SRVC_BY_UUID: /* stage 1 */
485 p_clcb->e_handle = p_data->value.group_value.e_handle;
486 p_clcb->ccc_result++;
487 break;
488
489 case GATT_DISC_CHAR: /* stage 2 */
490 p_clcb->s_handle = p_data->value.dclr_value.val_handle;
491 p_clcb->ccc_result++;
492 break;
493
494 case GATT_DISC_CHAR_DSCPT: /* stage 3 */
495 if (p_data->type == Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG)) {
496 p_clcb->s_handle = p_data->handle;
497 p_clcb->ccc_result++;
498 }
499 break;
500
501 case GATT_DISC_SRVC_ALL:
502 case GATT_DISC_INC_SRVC:
503 case GATT_DISC_MAX:
504 log::error("Illegal discovery item handled");
505 break;
506 }
507 }
508
509 /*******************************************************************************
510 *
511 * Function gatt_disc_cmpl_cback
512 *
513 * Description Gatt profile discovery complete callback
514 *
515 * Returns void
516 *
517 ******************************************************************************/
gatt_disc_cmpl_cback(uint16_t conn_id,tGATT_DISC_TYPE,tGATT_STATUS status)518 static void gatt_disc_cmpl_cback(uint16_t conn_id,
519 tGATT_DISC_TYPE /* disc_type */,
520 tGATT_STATUS status) {
521 tGATT_PROFILE_CLCB* p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
522 if (p_clcb == NULL) {
523 log::warn("Unable to find gatt profile after discovery complete");
524 return;
525 }
526
527 if (status != GATT_SUCCESS) {
528 log::warn("Gatt discovery completed with errors status:{}", status);
529 return;
530 }
531 if (p_clcb->ccc_result == 0) {
532 log::warn("Gatt discovery completed but connection was idle id:{}",
533 conn_id);
534 return;
535 }
536
537 p_clcb->ccc_result = 0;
538 p_clcb->ccc_stage++;
539 gatt_cl_start_config_ccc(p_clcb);
540 }
541
gatt_svc_read_cl_supp_feat_req(uint16_t conn_id)542 static bool gatt_svc_read_cl_supp_feat_req(uint16_t conn_id) {
543 tGATT_READ_PARAM param;
544
545 memset(¶m, 0, sizeof(tGATT_READ_PARAM));
546
547 param.service.s_handle = 1;
548 param.service.e_handle = 0xFFFF;
549 param.service.auth_req = 0;
550
551 param.service.uuid = bluetooth::Uuid::From16Bit(GATT_UUID_CLIENT_SUP_FEAT);
552
553 tGATT_STATUS status = GATTC_Read(conn_id, GATT_READ_BY_TYPE, ¶m);
554 if (status != GATT_SUCCESS) {
555 log::error("Read failed. Status: 0x{:x}", static_cast<uint8_t>(status));
556 return false;
557 }
558
559 gatt_op_cb_data cb_data;
560
561 cb_data.cb = base::BindOnce(
562 [](const RawAddress& /* bdaddr */, uint8_t /* support */) { return; });
563 cb_data.op_uuid = GATT_UUID_CLIENT_SUP_FEAT;
564 OngoingOps[conn_id].emplace_back(std::move(cb_data));
565
566 return true;
567 }
568
gatt_att_write_cl_supp_feat(uint16_t conn_id,uint16_t handle)569 static bool gatt_att_write_cl_supp_feat(uint16_t conn_id, uint16_t handle) {
570 tGATT_VALUE attr;
571
572 memset(&attr, 0, sizeof(tGATT_VALUE));
573
574 attr.conn_id = conn_id;
575 attr.handle = handle;
576 attr.len = 1;
577 attr.value[0] = gatt_cb.gatt_cl_supported_feat_mask;
578
579 tGATT_STATUS status = GATTC_Write(conn_id, GATT_WRITE, &attr);
580 if (status != GATT_SUCCESS) {
581 log::error("Write failed. Status: 0x{:x}", static_cast<uint8_t>(status));
582 return false;
583 }
584
585 return true;
586 }
587
588 /*******************************************************************************
589 *
590 * Function gatt_cl_op_cmpl_cback
591 *
592 * Description Gatt profile client operation complete callback
593 *
594 * Returns void
595 *
596 ******************************************************************************/
gatt_cl_op_cmpl_cback(uint16_t conn_id,tGATTC_OPTYPE op,tGATT_STATUS status,tGATT_CL_COMPLETE * p_data)597 static void gatt_cl_op_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
598 tGATT_STATUS status,
599 tGATT_CL_COMPLETE* p_data) {
600 auto iter = OngoingOps.find(conn_id);
601
602 log::verbose("opcode: 0x{:x} status: {} conn id: 0x{:x}",
603 static_cast<uint8_t>(op), status, static_cast<uint8_t>(conn_id));
604
605 if (op != GATTC_OPTYPE_READ && op != GATTC_OPTYPE_WRITE) {
606 log::verbose("Not interested in opcode {}", op);
607 return;
608 }
609
610 if (iter == OngoingOps.end() || (iter->second.size() == 0)) {
611 /* If OngoingOps is empty it means we are not interested in the result here.
612 */
613 log::debug("Unexpected read complete");
614 return;
615 }
616
617 uint16_t cl_op_uuid = iter->second.front().op_uuid;
618
619 if (op == GATTC_OPTYPE_WRITE) {
620 if (cl_op_uuid == GATT_UUID_GATT_SRV_CHGD) {
621 log::debug("Write response from Service Changed CCC");
622 iter->second.pop_front();
623 /* Read server supported features here supported */
624 read_sr_supported_feat_req(
625 conn_id, base::BindOnce([](const RawAddress& /* bdaddr */,
626 uint8_t /* support */) { return; }));
627 } else {
628 log::debug("Not interested in that write response");
629 }
630 return;
631 }
632
633 /* Handle Read operations */
634 uint8_t* pp = p_data->att_value.value;
635
636 log::verbose("cl_op_uuid 0x{:x}", cl_op_uuid);
637
638 switch (cl_op_uuid) {
639 case GATT_UUID_SERVER_SUP_FEAT: {
640 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
641 tGATT_TCB& tcb = gatt_cb.tcb[tcb_idx];
642
643 auto operation_callback_data = std::move(iter->second.front());
644 iter->second.pop_front();
645
646 /* Check if EATT is supported */
647 if (status == GATT_SUCCESS) {
648 STREAM_TO_UINT8(tcb.sr_supp_feat, pp);
649 btif_storage_set_gatt_sr_supp_feat(tcb.peer_bda, tcb.sr_supp_feat);
650 }
651
652 /* Notify user about the supported features */
653 std::move(operation_callback_data.cb).Run(tcb.peer_bda, tcb.sr_supp_feat);
654
655 /* If server supports EATT lets try to find handle for the
656 * client supported features characteristic, where we could write
657 * our supported features as a client.
658 */
659 if (tcb.sr_supp_feat & BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK) {
660 gatt_svc_read_cl_supp_feat_req(conn_id);
661 }
662
663 break;
664 }
665 case GATT_UUID_CSIS_SIRK: {
666 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
667 tGATT_TCB& tcb = gatt_cb.tcb[tcb_idx];
668
669 auto operation_callback_data = std::move(iter->second.front());
670 iter->second.pop_front();
671 tcb.gatt_status = status;
672
673 if (status == GATT_SUCCESS) {
674 STREAM_TO_UINT8(tcb.sirk_type, pp);
675 STREAM_TO_ARRAY(tcb.sirk.data(), pp, 16);
676 }
677
678 std::move(operation_callback_data.sirk_cb)
679 .Run(tcb.gatt_status, tcb.peer_bda, tcb.sirk_type, tcb.sirk);
680
681 break;
682 }
683 case GATT_UUID_CLIENT_SUP_FEAT:
684 /*We don't need callback data anymore */
685 iter->second.pop_front();
686
687 if (status != GATT_SUCCESS) {
688 log::info("Client supported features charcteristic not found");
689 return;
690 }
691
692 /* Write our client supported features to the remote device */
693 gatt_att_write_cl_supp_feat(conn_id, p_data->att_value.handle);
694 break;
695 }
696 }
697
698 /*******************************************************************************
699 *
700 * Function gatt_cl_start_config_ccc
701 *
702 * Description Gatt profile start configure service change CCC
703 *
704 * Returns void
705 *
706 ******************************************************************************/
gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB * p_clcb)707 static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB* p_clcb) {
708 log::verbose("stage: {}", p_clcb->ccc_stage);
709
710 switch (p_clcb->ccc_stage) {
711 case GATT_SVC_CHANGED_SERVICE: /* discover GATT service */
712 if (GATTC_Discover(p_clcb->conn_id, GATT_DISC_SRVC_BY_UUID, 0x0001,
713 0xffff, Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER)) !=
714 GATT_SUCCESS) {
715 log::warn("Unable to discovery GATT client conn_id:{}",
716 p_clcb->conn_id);
717 }
718 break;
719
720 case GATT_SVC_CHANGED_CHARACTERISTIC: /* discover service change char */
721 if (GATTC_Discover(
722 p_clcb->conn_id, GATT_DISC_CHAR, 0x0001, p_clcb->e_handle,
723 Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD)) != GATT_SUCCESS) {
724 log::warn("Unable to discovery GATT client conn_id:{}",
725 p_clcb->conn_id);
726 }
727 break;
728
729 case GATT_SVC_CHANGED_DESCRIPTOR: /* discover service change ccc */
730 if (GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR_DSCPT,
731 p_clcb->s_handle, p_clcb->e_handle) != GATT_SUCCESS) {
732 log::warn("Unable to discovery GATT client conn_id:{}",
733 p_clcb->conn_id);
734 }
735 break;
736
737 case GATT_SVC_CHANGED_CONFIGURE_CCCD: /* write ccc */
738 {
739 tGATT_VALUE ccc_value;
740 memset(&ccc_value, 0, sizeof(tGATT_VALUE));
741 ccc_value.handle = p_clcb->s_handle;
742 ccc_value.len = 2;
743 ccc_value.value[0] = GATT_CLT_CONFIG_INDICATION;
744 if (GATTC_Write(p_clcb->conn_id, GATT_WRITE, &ccc_value) !=
745 GATT_SUCCESS) {
746 log::warn("Unable to write GATT client data conn_id:{}",
747 p_clcb->conn_id);
748 }
749
750 gatt_op_cb_data cb_data;
751 cb_data.cb = base::BindOnce([](const RawAddress& /* bdaddr */,
752 uint8_t /* support */) { return; });
753 cb_data.op_uuid = GATT_UUID_GATT_SRV_CHGD;
754 OngoingOps[p_clcb->conn_id].emplace_back(std::move(cb_data));
755
756 break;
757 }
758 }
759 }
760
761 /*******************************************************************************
762 *
763 * Function GATT_ConfigServiceChangeCCC
764 *
765 * Description Configure service change indication on remote device
766 *
767 * Returns none
768 *
769 ******************************************************************************/
GATT_ConfigServiceChangeCCC(const RawAddress & remote_bda,bool,tBT_TRANSPORT transport)770 void GATT_ConfigServiceChangeCCC(const RawAddress& remote_bda,
771 bool /* enable */, tBT_TRANSPORT transport) {
772 tGATT_PROFILE_CLCB* p_clcb =
773 gatt_profile_find_clcb_by_bd_addr(remote_bda, transport);
774
775 if (p_clcb == NULL)
776 p_clcb = gatt_profile_clcb_alloc(0, remote_bda, transport);
777
778 if (p_clcb == NULL) return;
779
780 if (GATT_GetConnIdIfConnected(gatt_cb.gatt_if, remote_bda, &p_clcb->conn_id,
781 transport)) {
782 p_clcb->connected = true;
783 } else {
784 log::warn(
785 "Unable to get GATT connection id if connected peer:{} gatt_if:{} "
786 "transport:{}",
787 remote_bda, gatt_cb.gatt_if, bt_transport_text(BT_TRANSPORT_LE));
788 }
789
790 /* hold the link here */
791 if (!GATT_Connect(gatt_cb.gatt_if, remote_bda, BTM_BLE_DIRECT_CONNECTION,
792 transport, true)) {
793 log::warn(
794 "Unable to connect GATT client gatt_if:{} peer:{} transport:{} "
795 "connection_tyoe:{} opporunistic:{}",
796 gatt_cb.gatt_if, remote_bda, bt_transport_text(transport),
797 "BTM_BLE_DIRECT_CONNECTION", true);
798 }
799 p_clcb->ccc_stage = GATT_SVC_CHANGED_CONNECTING;
800
801 if (!p_clcb->connected) {
802 /* wait for connection */
803 return;
804 }
805
806 p_clcb->ccc_stage++;
807 gatt_cl_start_config_ccc(p_clcb);
808 }
809
810 /*******************************************************************************
811 *
812 * Function gatt_cl_init_sr_status
813 *
814 * Description Restore status for trusted GATT Server device
815 *
816 * Returns none
817 *
818 ******************************************************************************/
gatt_cl_init_sr_status(tGATT_TCB & tcb)819 void gatt_cl_init_sr_status(tGATT_TCB& tcb) {
820 tcb.sr_supp_feat = btif_storage_get_sr_supp_feat(tcb.peer_bda);
821
822 if (tcb.sr_supp_feat & BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK)
823 bluetooth::eatt::EattExtension::AddFromStorage(tcb.peer_bda);
824 }
825
read_sr_supported_feat_req(uint16_t conn_id,base::OnceCallback<void (const RawAddress &,uint8_t)> cb)826 static bool read_sr_supported_feat_req(
827 uint16_t conn_id, base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
828 tGATT_READ_PARAM param = {};
829
830 param.service.s_handle = 1;
831 param.service.e_handle = 0xFFFF;
832 param.service.auth_req = 0;
833
834 param.service.uuid = bluetooth::Uuid::From16Bit(GATT_UUID_SERVER_SUP_FEAT);
835
836 if (GATTC_Read(conn_id, GATT_READ_BY_TYPE, ¶m) != GATT_SUCCESS) {
837 log::error("Read GATT Support features GATT_Read Failed");
838 return false;
839 }
840
841 gatt_op_cb_data cb_data;
842
843 cb_data.cb = std::move(cb);
844 cb_data.op_uuid = GATT_UUID_SERVER_SUP_FEAT;
845 OngoingOps[conn_id].emplace_back(std::move(cb_data));
846
847 return true;
848 }
849
read_sr_sirk_req(uint16_t conn_id,base::OnceCallback<void (tGATT_STATUS status,const RawAddress &,uint8_t sirk_type,Octet16 & sirk)> cb)850 static bool read_sr_sirk_req(
851 uint16_t conn_id,
852 base::OnceCallback<void(tGATT_STATUS status, const RawAddress&,
853 uint8_t sirk_type, Octet16& sirk)>
854 cb) {
855 tGATT_READ_PARAM param = {};
856
857 param.service.s_handle = 1;
858 param.service.e_handle = 0xFFFF;
859 param.service.auth_req = 0;
860
861 param.service.uuid = bluetooth::Uuid::From16Bit(GATT_UUID_CSIS_SIRK);
862
863 if (GATTC_Read(conn_id, GATT_READ_BY_TYPE, ¶m) != GATT_SUCCESS) {
864 log::error("Read GATT Support features GATT_Read Failed, conn_id: {}",
865 static_cast<int>(conn_id));
866 return false;
867 }
868
869 gatt_op_cb_data cb_data;
870
871 cb_data.sirk_cb = std::move(cb);
872 cb_data.op_uuid = GATT_UUID_CSIS_SIRK;
873 OngoingOps[conn_id].emplace_back(std::move(cb_data));
874
875 return true;
876 }
877
878 /*******************************************************************************
879 *
880 * Function gatt_cl_read_sr_supp_feat_req
881 *
882 * Description Read remote device supported GATT feature mask.
883 *
884 * Returns bool
885 *
886 ******************************************************************************/
gatt_cl_read_sr_supp_feat_req(const RawAddress & peer_bda,base::OnceCallback<void (const RawAddress &,uint8_t)> cb)887 bool gatt_cl_read_sr_supp_feat_req(
888 const RawAddress& peer_bda,
889 base::OnceCallback<void(const RawAddress&, uint8_t)> cb) {
890 tGATT_PROFILE_CLCB* p_clcb;
891 uint16_t conn_id;
892
893 if (!cb) return false;
894
895 log::verbose("BDA: {} read gatt supported features", peer_bda);
896
897 if (!GATT_GetConnIdIfConnected(gatt_cb.gatt_if, peer_bda, &conn_id,
898 BT_TRANSPORT_LE)) {
899 log::warn(
900 "Unable to get GATT connection id if connected peer:{} gatt_if:{} "
901 "transport:{}",
902 peer_bda, gatt_cb.gatt_if, bt_transport_text(BT_TRANSPORT_LE));
903 }
904
905 if (conn_id == GATT_INVALID_CONN_ID) return false;
906
907 p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
908 if (!p_clcb) {
909 p_clcb = gatt_profile_clcb_alloc(conn_id, peer_bda, BT_TRANSPORT_LE);
910 }
911
912 if (!p_clcb) {
913 log::verbose("p_clcb is NULL 0x{:x}", conn_id);
914 return false;
915 }
916
917 auto it = OngoingOps.find(conn_id);
918 if (it == OngoingOps.end()) {
919 OngoingOps[conn_id] = std::deque<gatt_op_cb_data>();
920 }
921
922 return read_sr_supported_feat_req(conn_id, std::move(cb));
923 }
924
925 /*******************************************************************************
926 *
927 * Function gatt_cl_read_sirk_req
928 *
929 * Description Read remote SIRK if it's a set member device.
930 *
931 * Returns bool
932 *
933 ******************************************************************************/
gatt_cl_read_sirk_req(const RawAddress & peer_bda,base::OnceCallback<void (tGATT_STATUS status,const RawAddress &,uint8_t sirk_type,Octet16 & sirk)> cb)934 bool gatt_cl_read_sirk_req(
935 const RawAddress& peer_bda,
936 base::OnceCallback<void(tGATT_STATUS status, const RawAddress&,
937 uint8_t sirk_type, Octet16& sirk)>
938 cb) {
939 tGATT_PROFILE_CLCB* p_clcb;
940 uint16_t conn_id;
941
942 if (!cb) return false;
943
944 log::debug("BDA: {}, read SIRK", peer_bda);
945
946 if (!GATT_GetConnIdIfConnected(gatt_cb.gatt_if, peer_bda, &conn_id,
947 BT_TRANSPORT_LE)) {
948 log::warn(
949 "Unable to get GATT connection id if connected peer:{} gatt_if:{} "
950 "transport:{}",
951 peer_bda, gatt_cb.gatt_if, bt_transport_text(BT_TRANSPORT_LE));
952 }
953 if (conn_id == GATT_INVALID_CONN_ID) return false;
954
955 p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);
956 if (!p_clcb) {
957 p_clcb = gatt_profile_clcb_alloc(conn_id, peer_bda, BT_TRANSPORT_LE);
958 }
959
960 if (!p_clcb) {
961 log::verbose("p_clcb is NULL, conn_id: {:04x}", conn_id);
962 return false;
963 }
964
965 auto it = OngoingOps.find(conn_id);
966
967 if (it == OngoingOps.end()) {
968 OngoingOps[conn_id] = std::deque<gatt_op_cb_data>();
969 }
970
971 return read_sr_sirk_req(conn_id, std::move(cb));
972 }
973
974 /*******************************************************************************
975 *
976 * Function gatt_profile_get_eatt_support
977 *
978 * Description Check if EATT is supported with remote device.
979 *
980 * Returns if EATT is supported.
981 *
982 ******************************************************************************/
gatt_profile_get_eatt_support(const RawAddress & remote_bda)983 bool gatt_profile_get_eatt_support(const RawAddress& remote_bda) {
984 uint16_t conn_id;
985
986 log::verbose("BDA: {} read GATT support", remote_bda);
987
988 if (!GATT_GetConnIdIfConnected(gatt_cb.gatt_if, remote_bda, &conn_id,
989 BT_TRANSPORT_LE)) {
990 log::warn(
991 "Unable to get GATT connection id if connected peer:{} gatt_if:{} "
992 "transport:{}",
993 remote_bda, gatt_cb.gatt_if, bt_transport_text(BT_TRANSPORT_LE));
994 }
995
996 /* This read is important only when connected */
997 if (conn_id == GATT_INVALID_CONN_ID) return false;
998
999 /* Get tcb info */
1000 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
1001 tGATT_TCB& tcb = gatt_cb.tcb[tcb_idx];
1002 return tcb.sr_supp_feat & BLE_GATT_SVR_SUP_FEAT_EATT_BITMASK;
1003 }
1004
1005 /*******************************************************************************
1006 *
1007 * Function gatt_sr_is_robust_caching_enabled
1008 *
1009 * Description Check if Robust Caching is enabled on server side.
1010 *
1011 * Returns true if enabled in gd flag, otherwise false
1012 *
1013 ******************************************************************************/
gatt_sr_is_robust_caching_enabled()1014 static bool gatt_sr_is_robust_caching_enabled() {
1015 return bluetooth::common::init_flags::gatt_robust_caching_server_is_enabled();
1016 }
1017
1018 /*******************************************************************************
1019 *
1020 * Function gatt_sr_is_cl_robust_caching_supported
1021 *
1022 * Description Check if Robust Caching is supported for the connection
1023 *
1024 * Returns true if enabled by client side, otherwise false
1025 *
1026 ******************************************************************************/
gatt_sr_is_cl_robust_caching_supported(tGATT_TCB & tcb)1027 static bool gatt_sr_is_cl_robust_caching_supported(tGATT_TCB& tcb) {
1028 // if robust caching is not enabled, should always return false
1029 if (!gatt_sr_is_robust_caching_enabled()) return false;
1030 return (tcb.cl_supp_feat & BLE_GATT_CL_SUP_FEAT_CACHING_BITMASK);
1031 }
1032
1033 /*******************************************************************************
1034 *
1035 * Function gatt_sr_is_cl_multi_variable_len_notif_supported
1036 *
1037 * Description Check if Multiple Variable Length Notifications
1038 * supported for the connection
1039 *
1040 * Returns true if enabled by client side, otherwise false
1041 *
1042 ******************************************************************************/
gatt_sr_is_cl_multi_variable_len_notif_supported(tGATT_TCB & tcb)1043 bool gatt_sr_is_cl_multi_variable_len_notif_supported(tGATT_TCB& tcb) {
1044 return (tcb.cl_supp_feat & BLE_GATT_CL_SUP_FEAT_MULTI_NOTIF_BITMASK);
1045 }
1046
1047 /*******************************************************************************
1048 *
1049 * Function gatt_sr_is_cl_change_aware
1050 *
1051 * Description Check if the connection is change-aware
1052 *
1053 * Returns true if change aware, otherwise false
1054 *
1055 ******************************************************************************/
gatt_sr_is_cl_change_aware(tGATT_TCB & tcb)1056 bool gatt_sr_is_cl_change_aware(tGATT_TCB& tcb) {
1057 // if robust caching is not supported, should always return true by default
1058 if (!gatt_sr_is_cl_robust_caching_supported(tcb)) return true;
1059 return tcb.is_robust_cache_change_aware;
1060 }
1061
1062 /*******************************************************************************
1063 *
1064 * Function gatt_sr_init_cl_status
1065 *
1066 * Description Restore status for trusted device
1067 *
1068 * Returns none
1069 *
1070 ******************************************************************************/
gatt_sr_init_cl_status(tGATT_TCB & tcb)1071 void gatt_sr_init_cl_status(tGATT_TCB& tcb) {
1072 tcb.cl_supp_feat = btif_storage_get_gatt_cl_supp_feat(tcb.peer_bda);
1073 // This is used to reset bit when robust caching is disabled
1074 if (!gatt_sr_is_robust_caching_enabled()) {
1075 tcb.cl_supp_feat &= ~BLE_GATT_CL_SUP_FEAT_CACHING_BITMASK;
1076 }
1077
1078 if (gatt_sr_is_cl_robust_caching_supported(tcb)) {
1079 Octet16 stored_hash = btif_storage_get_gatt_cl_db_hash(tcb.peer_bda);
1080 tcb.is_robust_cache_change_aware = (stored_hash == gatt_cb.database_hash);
1081 } else {
1082 // set default value for untrusted device
1083 tcb.is_robust_cache_change_aware = true;
1084 }
1085
1086 log::info("bda={}, cl_supp_feat=0x{:x}, aware={}", tcb.peer_bda,
1087 tcb.cl_supp_feat, tcb.is_robust_cache_change_aware);
1088 }
1089
1090 /*******************************************************************************
1091 *
1092 * Function gatt_sr_update_cl_status
1093 *
1094 * Description Update change-aware status for the remote device
1095 *
1096 * Returns none
1097 *
1098 ******************************************************************************/
gatt_sr_update_cl_status(tGATT_TCB & tcb,bool chg_aware)1099 void gatt_sr_update_cl_status(tGATT_TCB& tcb, bool chg_aware) {
1100 // if robust caching is not supported, do nothing
1101 if (!gatt_sr_is_cl_robust_caching_supported(tcb)) return;
1102
1103 // only when client status is changed from change-unaware to change-aware, we
1104 // can then store database hash into btif_storage
1105 if (!tcb.is_robust_cache_change_aware && chg_aware) {
1106 btif_storage_set_gatt_cl_db_hash(tcb.peer_bda, gatt_cb.database_hash);
1107 }
1108
1109 // only when the status is changed, print the log
1110 if (tcb.is_robust_cache_change_aware != chg_aware) {
1111 log::info("bda={}, chg_aware={}", tcb.peer_bda, chg_aware);
1112 }
1113
1114 tcb.is_robust_cache_change_aware = chg_aware;
1115 }
1116
1117 /* handle request for reading database hash */
gatt_sr_read_db_hash(uint16_t conn_id,tGATT_VALUE * p_value)1118 static tGATT_STATUS gatt_sr_read_db_hash(uint16_t conn_id,
1119 tGATT_VALUE* p_value) {
1120 log::info("conn_id=0x{:x}", conn_id);
1121
1122 uint8_t* p = p_value->value;
1123 Octet16& db_hash = gatt_cb.database_hash;
1124 ARRAY_TO_STREAM(p, db_hash.data(), (uint16_t)db_hash.size());
1125 p_value->len = (uint16_t)db_hash.size();
1126
1127 // Every time when database hash is requested, reset flag.
1128 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
1129 gatt_sr_update_cl_status(gatt_cb.tcb[tcb_idx], /* chg_aware= */ true);
1130 return GATT_SUCCESS;
1131 }
1132
1133 /* handle request for reading client supported features */
gatt_sr_read_cl_supp_feat(uint16_t conn_id,tGATT_VALUE * p_value)1134 static tGATT_STATUS gatt_sr_read_cl_supp_feat(uint16_t conn_id,
1135 tGATT_VALUE* p_value) {
1136 // Get tcb info
1137 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
1138 tGATT_TCB& tcb = gatt_cb.tcb[tcb_idx];
1139
1140 uint8_t* p = p_value->value;
1141 UINT8_TO_STREAM(p, tcb.cl_supp_feat);
1142 p_value->len = 1;
1143
1144 return GATT_SUCCESS;
1145 }
1146
1147 /* handle request for writing client supported features */
gatt_sr_write_cl_supp_feat(uint16_t conn_id,tGATT_WRITE_REQ * p_data)1148 static tGATT_STATUS gatt_sr_write_cl_supp_feat(uint16_t conn_id,
1149 tGATT_WRITE_REQ* p_data) {
1150 std::list<uint8_t> tmp;
1151 uint16_t len = p_data->len;
1152 uint8_t value, *p = p_data->value;
1153 // Read all octets into list
1154 while (len > 0) {
1155 STREAM_TO_UINT8(value, p);
1156 tmp.push_back(value);
1157 len--;
1158 }
1159 // Remove trailing zero octets
1160 while (!tmp.empty()) {
1161 if (tmp.back() != 0x00) break;
1162 tmp.pop_back();
1163 }
1164
1165 // Get tcb info
1166 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
1167 tGATT_TCB& tcb = gatt_cb.tcb[tcb_idx];
1168
1169 std::list<uint8_t> feature_list;
1170 feature_list.push_back(tcb.cl_supp_feat);
1171
1172 // If input length is zero, return value_not_allowed
1173 if (tmp.empty()) {
1174 log::info("zero length, conn_id=0x{:x}, bda={}", conn_id, tcb.peer_bda);
1175 return GATT_VALUE_NOT_ALLOWED;
1176 }
1177 // if original length is longer than new one, it must be the bit reset case.
1178 if (feature_list.size() > tmp.size()) {
1179 log::info("shorter length, conn_id=0x{:x}, bda={}", conn_id, tcb.peer_bda);
1180 return GATT_VALUE_NOT_ALLOWED;
1181 }
1182 // new length is longer or equals to the original, need to check bits
1183 // one by one. Here we use bit-wise operation.
1184 // 1. Use XOR to locate the change bit, val_xor is the change bit mask
1185 // 2. Use AND for val_xor and *it_new to get val_and
1186 // 3. If val_and != val_xor, it means the change is from 1 to 0
1187 auto it_old = feature_list.cbegin();
1188 auto it_new = tmp.cbegin();
1189 for (; it_old != feature_list.cend(); it_old++, it_new++) {
1190 uint8_t val_xor = *it_old ^ *it_new;
1191 uint8_t val_and = val_xor & *it_new;
1192 if (val_and != val_xor) {
1193 log::info("bit cannot be reset, conn_id=0x{:x}, bda={}", conn_id,
1194 tcb.peer_bda);
1195 return GATT_VALUE_NOT_ALLOWED;
1196 }
1197 }
1198
1199 // get current robust caching status before setting new one
1200 bool curr_caching_state = gatt_sr_is_cl_robust_caching_supported(tcb);
1201
1202 tcb.cl_supp_feat = tmp.front();
1203 if (!gatt_sr_is_robust_caching_enabled()) {
1204 // remove robust caching bit
1205 tcb.cl_supp_feat &= ~BLE_GATT_CL_SUP_FEAT_CACHING_BITMASK;
1206 log::info("reset robust caching bit, conn_id=0x{:x}, bda={}", conn_id,
1207 tcb.peer_bda);
1208 }
1209 // TODO(hylo): save data as byte array
1210 btif_storage_set_gatt_cl_supp_feat(tcb.peer_bda, tcb.cl_supp_feat);
1211
1212 // get new robust caching status after setting new one
1213 bool new_caching_state = gatt_sr_is_cl_robust_caching_supported(tcb);
1214 // only when the first time robust caching request, print the log
1215 if (!curr_caching_state && new_caching_state) {
1216 log::info("robust caching enabled by client, conn_id=0x{:x}", conn_id);
1217 }
1218
1219 return GATT_SUCCESS;
1220 }
1221