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(&param, 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, &param);
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(&param, 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, &param) != 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