1 /******************************************************************************
2  *
3  *  Copyright (C) 2009-2013 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 #include "bt_target.h"
19 
20 #include <string.h>
21 #include "bt_utils.h"
22 #include "btcore/include/uuid.h"
23 #include "btm_int.h"
24 #include "gap_api.h"
25 #include "gap_int.h"
26 #include "gatt_api.h"
27 #include "gatt_int.h"
28 #include "gattdefs.h"
29 #include "hcimsgs.h"
30 #include "osi/include/osi.h"
31 
32 #define GAP_CHAR_ICON_SIZE 2
33 #define GAP_CHAR_DEV_NAME_SIZE 248
34 #define GAP_MAX_NUM_INC_SVR 0
35 #define GAP_MAX_ATTR_NUM (2 * GAP_MAX_CHAR_NUM + GAP_MAX_NUM_INC_SVR + 1)
36 #define GAP_MAX_CHAR_VALUE_SIZE (30 + GAP_CHAR_DEV_NAME_SIZE)
37 
38 #ifndef GAP_ATTR_DB_SIZE
39 #define GAP_ATTR_DB_SIZE                                  \
40   GATT_DB_MEM_SIZE(GAP_MAX_NUM_INC_SVR, GAP_MAX_CHAR_NUM, \
41                    GAP_MAX_CHAR_VALUE_SIZE)
42 #endif
43 
44 static void gap_ble_s_attr_request_cback(uint16_t conn_id, uint32_t trans_id,
45                                          tGATTS_REQ_TYPE op_code,
46                                          tGATTS_DATA* p_data);
47 
48 /* client connection callback */
49 static void gap_ble_c_connect_cback(tGATT_IF gatt_if, BD_ADDR bda,
50                                     uint16_t conn_id, bool connected,
51                                     tGATT_DISCONN_REASON reason,
52                                     tGATT_TRANSPORT transport);
53 static void gap_ble_c_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
54                                  tGATT_STATUS status,
55                                  tGATT_CL_COMPLETE* p_data);
56 
57 static tGATT_CBACK gap_cback = {gap_ble_c_connect_cback,
58                                 gap_ble_c_cmpl_cback,
59                                 NULL,
60                                 NULL,
61                                 gap_ble_s_attr_request_cback,
62                                 NULL,
63                                 NULL,
64                                 NULL,
65                                 NULL};
66 
67 /*******************************************************************************
68  *
69  * Function         gap_find_clcb_by_bd_addr
70  *
71  * Description      The function searches all LCB with macthing bd address
72  *
73  * Returns          total number of clcb found.
74  *
75  ******************************************************************************/
gap_find_clcb_by_bd_addr(BD_ADDR bda)76 tGAP_CLCB* gap_find_clcb_by_bd_addr(BD_ADDR bda) {
77   uint8_t i_clcb;
78   tGAP_CLCB* p_clcb = NULL;
79 
80   for (i_clcb = 0, p_clcb = gap_cb.clcb; i_clcb < GAP_MAX_CL;
81        i_clcb++, p_clcb++) {
82     if (p_clcb->in_use && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN)) {
83       return p_clcb;
84     }
85   }
86 
87   return NULL;
88 }
89 
90 /* returns LCB with matching connection ID, or NULL if not found */
gap_ble_find_clcb_by_conn_id(uint16_t conn_id)91 tGAP_CLCB* gap_ble_find_clcb_by_conn_id(uint16_t conn_id) {
92   uint8_t i_clcb;
93   tGAP_CLCB* p_clcb = NULL;
94 
95   for (i_clcb = 0, p_clcb = gap_cb.clcb; i_clcb < GAP_MAX_CL;
96        i_clcb++, p_clcb++) {
97     if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id) {
98       return p_clcb;
99     }
100   }
101 
102   return NULL;
103 }
104 
105 /*******************************************************************************
106  *
107  * Function         gap_clcb_alloc
108  *
109  * Description      The function allocates a GAP  connection link control block
110  *
111  * Returns          NULL if not found. Otherwise pointer to the connection link
112  *                  block.
113  *
114  ******************************************************************************/
gap_clcb_alloc(BD_ADDR bda)115 tGAP_CLCB* gap_clcb_alloc(BD_ADDR bda) {
116   uint8_t i_clcb = 0;
117   tGAP_CLCB* p_clcb = NULL;
118 
119   for (i_clcb = 0, p_clcb = gap_cb.clcb; i_clcb < GAP_MAX_CL;
120        i_clcb++, p_clcb++) {
121     if (!p_clcb->in_use) {
122       fixed_queue_free(p_clcb->pending_req_q, NULL);
123       memset(p_clcb, 0, sizeof(tGAP_CLCB));
124       p_clcb->in_use = true;
125       memcpy(p_clcb->bda, bda, BD_ADDR_LEN);
126       p_clcb->pending_req_q = fixed_queue_new(SIZE_MAX);
127       return p_clcb;
128     }
129   }
130   return NULL;
131 }
132 
133 /*******************************************************************************
134  *
135  * Function         gap_ble_dealloc_clcb
136  *
137  * Description      The function clean up the pending request queue in GAP
138  *
139  * Returns          none
140  *
141  ******************************************************************************/
gap_ble_dealloc_clcb(tGAP_CLCB * p_clcb)142 void gap_ble_dealloc_clcb(tGAP_CLCB* p_clcb) {
143   tGAP_BLE_REQ* p_q;
144 
145   while ((p_q = (tGAP_BLE_REQ*)fixed_queue_try_dequeue(
146               p_clcb->pending_req_q)) != NULL) {
147     /* send callback to all pending requests if being removed*/
148     if (p_q->p_cback != NULL) (*p_q->p_cback)(false, p_clcb->bda, 0, NULL);
149 
150     osi_free(p_q);
151   }
152   fixed_queue_free(p_clcb->pending_req_q, NULL);
153 
154   memset(p_clcb, 0, sizeof(tGAP_CLCB));
155 }
156 
157 /*******************************************************************************
158  *
159  * Function         gap_ble_enqueue_request
160  *
161  * Description      The function enqueue a GAP client request
162  *
163  * Returns           true is successul; false otherwise
164  *
165  ******************************************************************************/
gap_ble_enqueue_request(tGAP_CLCB * p_clcb,uint16_t uuid,tGAP_BLE_CMPL_CBACK * p_cback)166 bool gap_ble_enqueue_request(tGAP_CLCB* p_clcb, uint16_t uuid,
167                              tGAP_BLE_CMPL_CBACK* p_cback) {
168   tGAP_BLE_REQ* p_q = (tGAP_BLE_REQ*)osi_malloc(sizeof(tGAP_BLE_REQ));
169 
170   p_q->p_cback = p_cback;
171   p_q->uuid = uuid;
172   fixed_queue_enqueue(p_clcb->pending_req_q, p_q);
173 
174   return true;
175 }
176 
177 /*******************************************************************************
178  *
179  * Function         gap_ble_dequeue_request
180  *
181  * Description      The function dequeue a GAP client request if any
182  *
183  * Returns           true is successul; false otherwise
184  *
185  ******************************************************************************/
gap_ble_dequeue_request(tGAP_CLCB * p_clcb,uint16_t * p_uuid,tGAP_BLE_CMPL_CBACK ** p_cback)186 bool gap_ble_dequeue_request(tGAP_CLCB* p_clcb, uint16_t* p_uuid,
187                              tGAP_BLE_CMPL_CBACK** p_cback) {
188   tGAP_BLE_REQ* p_q =
189       (tGAP_BLE_REQ*)fixed_queue_try_dequeue(p_clcb->pending_req_q);
190   ;
191 
192   if (p_q != NULL) {
193     *p_cback = p_q->p_cback;
194     *p_uuid = p_q->uuid;
195     osi_free(p_q);
196     return true;
197   }
198 
199   return false;
200 }
201 
202 /*******************************************************************************
203  *   GAP Attributes Database Request callback
204  ******************************************************************************/
gap_read_attr_value(uint16_t handle,tGATT_VALUE * p_value,bool is_long)205 tGATT_STATUS gap_read_attr_value(uint16_t handle, tGATT_VALUE* p_value,
206                                  bool is_long) {
207   tGAP_ATTR* p_db_attr = gap_cb.gatt_attr;
208   uint8_t *p = p_value->value, i;
209   uint16_t offset = p_value->offset;
210   uint8_t* p_dev_name = NULL;
211 
212   for (i = 0; i < GAP_MAX_CHAR_NUM; i++, p_db_attr++) {
213     if (handle == p_db_attr->handle) {
214       if (p_db_attr->uuid != GATT_UUID_GAP_DEVICE_NAME && is_long == true)
215         return GATT_NOT_LONG;
216 
217       switch (p_db_attr->uuid) {
218         case GATT_UUID_GAP_DEVICE_NAME:
219           BTM_ReadLocalDeviceName((char**)&p_dev_name);
220           if (strlen((char*)p_dev_name) > GATT_MAX_ATTR_LEN)
221             p_value->len = GATT_MAX_ATTR_LEN;
222           else
223             p_value->len = (uint16_t)strlen((char*)p_dev_name);
224 
225           if (offset > p_value->len)
226             return GATT_INVALID_OFFSET;
227           else {
228             p_value->len -= offset;
229             p_dev_name += offset;
230             ARRAY_TO_STREAM(p, p_dev_name, p_value->len);
231             GAP_TRACE_EVENT("GATT_UUID_GAP_DEVICE_NAME len=0x%04x",
232                             p_value->len);
233           }
234           break;
235 
236         case GATT_UUID_GAP_ICON:
237           UINT16_TO_STREAM(p, p_db_attr->attr_value.icon);
238           p_value->len = 2;
239           break;
240 
241         case GATT_UUID_GAP_PREF_CONN_PARAM:
242           UINT16_TO_STREAM(
243               p, p_db_attr->attr_value.conn_param.int_min); /* int_min */
244           UINT16_TO_STREAM(
245               p, p_db_attr->attr_value.conn_param.int_max); /* int_max */
246           UINT16_TO_STREAM(
247               p, p_db_attr->attr_value.conn_param.latency); /* latency */
248           UINT16_TO_STREAM(
249               p, p_db_attr->attr_value.conn_param.sp_tout); /* sp_tout */
250           p_value->len = 8;
251           break;
252 
253         /* address resolution */
254         case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
255           UINT8_TO_STREAM(p, p_db_attr->attr_value.addr_resolution);
256           p_value->len = 1;
257           break;
258       }
259       return GATT_SUCCESS;
260     }
261   }
262   return GATT_NOT_FOUND;
263 }
264 
265 /*******************************************************************************
266  *   GAP Attributes Database Read/Read Blob Request process
267  ******************************************************************************/
gap_proc_read(UNUSED_ATTR tGATTS_REQ_TYPE type,tGATT_READ_REQ * p_data,tGATTS_RSP * p_rsp)268 tGATT_STATUS gap_proc_read(UNUSED_ATTR tGATTS_REQ_TYPE type,
269                            tGATT_READ_REQ* p_data, tGATTS_RSP* p_rsp) {
270   tGATT_STATUS status = GATT_NO_RESOURCES;
271 
272   if (p_data->is_long) p_rsp->attr_value.offset = p_data->offset;
273 
274   p_rsp->attr_value.handle = p_data->handle;
275 
276   status =
277       gap_read_attr_value(p_data->handle, &p_rsp->attr_value, p_data->is_long);
278 
279   return status;
280 }
281 
282 /******************************************************************************
283  *
284  * Function         gap_proc_write_req
285  *
286  * Description      GAP ATT server process a write request.
287  *
288  * Returns          void.
289  *
290  ******************************************************************************/
gap_proc_write_req(UNUSED_ATTR tGATTS_REQ_TYPE type,tGATT_WRITE_REQ * p_data)291 uint8_t gap_proc_write_req(UNUSED_ATTR tGATTS_REQ_TYPE type,
292                            tGATT_WRITE_REQ* p_data) {
293   tGAP_ATTR* p_db_attr = gap_cb.gatt_attr;
294   uint8_t i;
295 
296   for (i = 0; i < GAP_MAX_CHAR_NUM; i++, p_db_attr++) {
297     if (p_data->handle == p_db_attr->handle) {
298       return GATT_WRITE_NOT_PERMIT;
299     }
300   }
301   return GATT_NOT_FOUND;
302 }
303 
304 /******************************************************************************
305  *
306  * Function         gap_ble_s_attr_request_cback
307  *
308  * Description      GAP ATT server attribute access request callback.
309  *
310  * Returns          void.
311  *
312  ******************************************************************************/
gap_ble_s_attr_request_cback(uint16_t conn_id,uint32_t trans_id,tGATTS_REQ_TYPE type,tGATTS_DATA * p_data)313 void gap_ble_s_attr_request_cback(uint16_t conn_id, uint32_t trans_id,
314                                   tGATTS_REQ_TYPE type, tGATTS_DATA* p_data) {
315   uint8_t status = GATT_INVALID_PDU;
316   tGATTS_RSP rsp_msg;
317   bool ignore = false;
318 
319   GAP_TRACE_EVENT("gap_ble_s_attr_request_cback : recv type (0x%02x)", type);
320 
321   memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
322 
323   switch (type) {
324     case GATTS_REQ_TYPE_READ_CHARACTERISTIC:
325     case GATTS_REQ_TYPE_READ_DESCRIPTOR:
326       status = gap_proc_read(type, &p_data->read_req, &rsp_msg);
327       break;
328 
329     case GATTS_REQ_TYPE_WRITE_CHARACTERISTIC:
330     case GATTS_REQ_TYPE_WRITE_DESCRIPTOR:
331       if (!p_data->write_req.need_rsp) ignore = true;
332 
333       status = gap_proc_write_req(type, &p_data->write_req);
334       break;
335 
336     case GATTS_REQ_TYPE_WRITE_EXEC:
337       ignore = true;
338       GAP_TRACE_EVENT("Ignore GATTS_REQ_TYPE_WRITE_EXEC");
339       break;
340 
341     case GATTS_REQ_TYPE_MTU:
342       GAP_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
343       ignore = true;
344       break;
345 
346     default:
347       GAP_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
348       break;
349   }
350 
351   if (!ignore) GATTS_SendRsp(conn_id, trans_id, status, &rsp_msg);
352 }
353 
354 /*******************************************************************************
355  *
356  * Function         btm_ble_att_db_init
357  *
358  * Description      GAP ATT database initalization.
359  *
360  * Returns          void.
361  *
362  ******************************************************************************/
gap_attr_db_init(void)363 void gap_attr_db_init(void) {
364   tBT_UUID app_uuid = {LEN_UUID_128, {0}};
365   uint16_t service_handle;
366 
367   /* Fill our internal UUID with a fixed pattern 0x82 */
368   memset(&app_uuid.uu.uuid128, 0x82, LEN_UUID_128);
369   memset(gap_cb.gatt_attr, 0, sizeof(tGAP_ATTR) * GAP_MAX_CHAR_NUM);
370 
371   gap_cb.gatt_if = GATT_Register(&app_uuid, &gap_cback);
372 
373   GATT_StartIf(gap_cb.gatt_if);
374 
375   bt_uuid_t svc_uuid, name_uuid, icon_uuid, pref_uuid, addr_res_uuid;
376   uuid_128_from_16(&svc_uuid, UUID_SERVCLASS_GAP_SERVER);
377   uuid_128_from_16(&name_uuid, GATT_UUID_GAP_DEVICE_NAME);
378   uuid_128_from_16(&icon_uuid, GATT_UUID_GAP_ICON);
379   uuid_128_from_16(&pref_uuid, GATT_UUID_GAP_PREF_CONN_PARAM);
380   uuid_128_from_16(&addr_res_uuid, GATT_UUID_GAP_CENTRAL_ADDR_RESOL);
381 
382   btgatt_db_element_t service[] = {
383     {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = svc_uuid},
384     {.type = BTGATT_DB_CHARACTERISTIC,
385      .uuid = name_uuid,
386      .properties = GATT_CHAR_PROP_BIT_READ,
387      .permissions = GATT_PERM_READ},
388     {.type = BTGATT_DB_CHARACTERISTIC,
389      .uuid = icon_uuid,
390      .properties = GATT_CHAR_PROP_BIT_READ,
391      .permissions = GATT_PERM_READ},
392     {.type = BTGATT_DB_CHARACTERISTIC,
393      .uuid = addr_res_uuid,
394      .properties = GATT_CHAR_PROP_BIT_READ,
395      .permissions = GATT_PERM_READ}
396 #if (BTM_PERIPHERAL_ENABLED == TRUE) /* Only needed for peripheral testing */
397     ,
398     {.type = BTGATT_DB_CHARACTERISTIC,
399      .uuid = pref_uuid,
400      .properties = GATT_CHAR_PROP_BIT_READ,
401      .permissions = GATT_PERM_READ}
402 #endif
403   };
404 
405   /* Add a GAP service */
406   GATTS_AddService(gap_cb.gatt_if, service,
407                    sizeof(service) / sizeof(btgatt_db_element_t));
408   service_handle = service[0].attribute_handle;
409 
410   GAP_TRACE_EVENT("%s: service_handle = %d", __func__, service_handle);
411 
412   gap_cb.gatt_attr[0].uuid = GATT_UUID_GAP_DEVICE_NAME;
413   gap_cb.gatt_attr[0].handle = service[1].attribute_handle;
414 
415   gap_cb.gatt_attr[1].uuid = GATT_UUID_GAP_ICON;
416   gap_cb.gatt_attr[1].handle = service[2].attribute_handle;
417 
418   gap_cb.gatt_attr[2].uuid = GATT_UUID_GAP_CENTRAL_ADDR_RESOL;
419   gap_cb.gatt_attr[2].handle = service[3].attribute_handle;
420   gap_cb.gatt_attr[2].attr_value.addr_resolution = 0;
421 
422 #if (BTM_PERIPHERAL_ENABLED == TRUE) /*  Only needed for peripheral testing */
423 
424   gap_cb.gatt_attr[3].uuid = GATT_UUID_GAP_PREF_CONN_PARAM;
425   gap_cb.gatt_attr[3].attr_value.conn_param.int_max =
426       GAP_PREFER_CONN_INT_MAX; /* 6 */
427   gap_cb.gatt_attr[3].attr_value.conn_param.int_min =
428       GAP_PREFER_CONN_INT_MIN; /* 0 */
429   gap_cb.gatt_attr[3].attr_value.conn_param.latency =
430       GAP_PREFER_CONN_LATENCY; /* 0 */
431   gap_cb.gatt_attr[3].attr_value.conn_param.sp_tout =
432       GAP_PREFER_CONN_SP_TOUT; /* 2000 */
433   gap_cb.gatt_attr[3].handle = service[4].attribute_handle;
434 #endif
435 }
436 
437 /*******************************************************************************
438  *
439  * Function         GAP_BleAttrDBUpdate
440  *
441  * Description      GAP ATT database update.
442  *
443  * Returns          void.
444  *
445  ******************************************************************************/
GAP_BleAttrDBUpdate(uint16_t attr_uuid,tGAP_BLE_ATTR_VALUE * p_value)446 void GAP_BleAttrDBUpdate(uint16_t attr_uuid, tGAP_BLE_ATTR_VALUE* p_value) {
447   tGAP_ATTR* p_db_attr = gap_cb.gatt_attr;
448   uint8_t i = 0;
449 
450   GAP_TRACE_EVENT("GAP_BleAttrDBUpdate attr_uuid=0x%04x", attr_uuid);
451 
452   for (i = 0; i < GAP_MAX_CHAR_NUM; i++, p_db_attr++) {
453     if (p_db_attr->uuid == attr_uuid) {
454       GAP_TRACE_EVENT("Found attr_uuid=0x%04x", attr_uuid);
455 
456       switch (attr_uuid) {
457         case GATT_UUID_GAP_ICON:
458           p_db_attr->attr_value.icon = p_value->icon;
459           break;
460 
461         case GATT_UUID_GAP_PREF_CONN_PARAM:
462           memcpy((void*)&p_db_attr->attr_value.conn_param,
463                  (const void*)&p_value->conn_param,
464                  sizeof(tGAP_BLE_PREF_PARAM));
465           break;
466 
467         case GATT_UUID_GAP_DEVICE_NAME:
468           BTM_SetLocalDeviceName((char*)p_value->p_dev_name);
469           break;
470 
471         case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
472           p_db_attr->attr_value.addr_resolution = p_value->addr_resolution;
473           break;
474       }
475       break;
476     }
477   }
478 
479   return;
480 }
481 
482 /*******************************************************************************
483  *
484  * Function         gap_ble_send_cl_read_request
485  *
486  * Description      utility function to send a read request for a GAP
487  *                  charactersitic
488  *
489  * Returns          true if read started, else false if GAP is busy
490  *
491  ******************************************************************************/
gap_ble_send_cl_read_request(tGAP_CLCB * p_clcb)492 bool gap_ble_send_cl_read_request(tGAP_CLCB* p_clcb) {
493   tGATT_READ_PARAM param;
494   uint16_t uuid = 0;
495   bool started = false;
496 
497   if (gap_ble_dequeue_request(p_clcb, &uuid, &p_clcb->p_cback)) {
498     memset(&param, 0, sizeof(tGATT_READ_PARAM));
499 
500     param.service.uuid.len = LEN_UUID_16;
501     param.service.uuid.uu.uuid16 = uuid;
502     param.service.s_handle = 1;
503     param.service.e_handle = 0xFFFF;
504     param.service.auth_req = 0;
505 
506     if (GATTC_Read(p_clcb->conn_id, GATT_READ_BY_TYPE, &param) ==
507         GATT_SUCCESS) {
508       p_clcb->cl_op_uuid = uuid;
509       started = true;
510     }
511   }
512 
513   return started;
514 }
515 
516 /*******************************************************************************
517  *
518  * Function         gap_ble_cl_op_cmpl
519  *
520  * Description      GAP client operation complete callback
521  *
522  * Returns          void
523  *
524  ******************************************************************************/
gap_ble_cl_op_cmpl(tGAP_CLCB * p_clcb,bool status,uint16_t len,uint8_t * p_name)525 void gap_ble_cl_op_cmpl(tGAP_CLCB* p_clcb, bool status, uint16_t len,
526                         uint8_t* p_name) {
527   tGAP_BLE_CMPL_CBACK* p_cback = p_clcb->p_cback;
528   uint16_t op = p_clcb->cl_op_uuid;
529 
530   GAP_TRACE_EVENT("gap_ble_cl_op_cmpl status: %d", status);
531 
532   p_clcb->cl_op_uuid = 0;
533   p_clcb->p_cback = NULL;
534 
535   if (p_cback && op) {
536     GAP_TRACE_EVENT("calling gap_ble_cl_op_cmpl");
537     (*p_cback)(status, p_clcb->bda, len, (char*)p_name);
538   }
539 
540   /* if no further activity is requested in callback, drop the link */
541   if (p_clcb->connected) {
542     if (!gap_ble_send_cl_read_request(p_clcb)) {
543       GATT_Disconnect(p_clcb->conn_id);
544       gap_ble_dealloc_clcb(p_clcb);
545     }
546   }
547 }
548 
549 /*******************************************************************************
550  *
551  * Function         gap_ble_c_connect_cback
552  *
553  * Description      Client connection callback.
554  *
555  * Returns          void
556  *
557  ******************************************************************************/
gap_ble_c_connect_cback(UNUSED_ATTR tGATT_IF gatt_if,BD_ADDR bda,uint16_t conn_id,bool connected,tGATT_DISCONN_REASON reason,UNUSED_ATTR tGATT_TRANSPORT transport)558 static void gap_ble_c_connect_cback(UNUSED_ATTR tGATT_IF gatt_if, BD_ADDR bda,
559                                     uint16_t conn_id, bool connected,
560                                     tGATT_DISCONN_REASON reason,
561                                     UNUSED_ATTR tGATT_TRANSPORT transport) {
562   tGAP_CLCB* p_clcb = gap_find_clcb_by_bd_addr(bda);
563 
564   if (p_clcb != NULL) {
565     if (connected) {
566       p_clcb->conn_id = conn_id;
567       p_clcb->connected = true;
568       /* start operation is pending */
569       gap_ble_send_cl_read_request(p_clcb);
570     } else {
571       p_clcb->connected = false;
572       gap_ble_cl_op_cmpl(p_clcb, false, 0, NULL);
573       /* clean up clcb */
574       gap_ble_dealloc_clcb(p_clcb);
575     }
576   }
577 }
578 
579 /*******************************************************************************
580  *
581  * Function         gap_ble_c_cmpl_cback
582  *
583  * Description      Client operation complete callback.
584  *
585  * Returns          void
586  *
587  ******************************************************************************/
gap_ble_c_cmpl_cback(uint16_t conn_id,tGATTC_OPTYPE op,tGATT_STATUS status,tGATT_CL_COMPLETE * p_data)588 static void gap_ble_c_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op,
589                                  tGATT_STATUS status, tGATT_CL_COMPLETE* p_data)
590 
591 {
592   tGAP_CLCB* p_clcb = gap_ble_find_clcb_by_conn_id(conn_id);
593   uint16_t op_type;
594   uint16_t min, max, latency, tout;
595   uint16_t len;
596   uint8_t* pp;
597 
598   if (p_clcb == NULL) return;
599 
600   op_type = p_clcb->cl_op_uuid;
601 
602   GAP_TRACE_EVENT(
603       "gap_ble_c_cmpl_cback() - op_code: 0x%02x  status: 0x%02x  read_type: "
604       "0x%04x",
605       op, status, op_type);
606   /* Currently we only issue read commands */
607   if (op != GATTC_OPTYPE_READ) return;
608 
609   if (status != GATT_SUCCESS) {
610     gap_ble_cl_op_cmpl(p_clcb, false, 0, NULL);
611     return;
612   }
613 
614   pp = p_data->att_value.value;
615 
616   switch (op_type) {
617     case GATT_UUID_GAP_PREF_CONN_PARAM:
618       GAP_TRACE_EVENT("GATT_UUID_GAP_PREF_CONN_PARAM");
619       /* Extract the peripheral preferred connection parameters and save them */
620 
621       STREAM_TO_UINT16(min, pp);
622       STREAM_TO_UINT16(max, pp);
623       STREAM_TO_UINT16(latency, pp);
624       STREAM_TO_UINT16(tout, pp);
625 
626       BTM_BleSetPrefConnParams(p_clcb->bda, min, max, latency, tout);
627       /* release the connection here */
628       gap_ble_cl_op_cmpl(p_clcb, true, 0, NULL);
629       break;
630 
631     case GATT_UUID_GAP_DEVICE_NAME:
632       GAP_TRACE_EVENT("GATT_UUID_GAP_DEVICE_NAME");
633       len = (uint16_t)strlen((char*)pp);
634       if (len > GAP_CHAR_DEV_NAME_SIZE) len = GAP_CHAR_DEV_NAME_SIZE;
635       gap_ble_cl_op_cmpl(p_clcb, true, len, pp);
636       break;
637 
638     case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
639       gap_ble_cl_op_cmpl(p_clcb, true, 1, pp);
640       break;
641   }
642 }
643 
644 /*******************************************************************************
645  *
646  * Function         gap_ble_accept_cl_operation
647  *
648  * Description      Start a process to read peer address resolution capability
649  *
650  * Returns          true if request accepted
651  *
652  ******************************************************************************/
gap_ble_accept_cl_operation(BD_ADDR peer_bda,uint16_t uuid,tGAP_BLE_CMPL_CBACK * p_cback)653 bool gap_ble_accept_cl_operation(BD_ADDR peer_bda, uint16_t uuid,
654                                  tGAP_BLE_CMPL_CBACK* p_cback) {
655   tGAP_CLCB* p_clcb;
656   bool started = false;
657 
658   if (p_cback == NULL && uuid != GATT_UUID_GAP_PREF_CONN_PARAM)
659     return (started);
660 
661   p_clcb = gap_find_clcb_by_bd_addr(peer_bda);
662   if (p_clcb == NULL) {
663     p_clcb = gap_clcb_alloc(peer_bda);
664     if (p_clcb == NULL) {
665       GAP_TRACE_ERROR("gap_ble_accept_cl_operation max connection reached");
666       return started;
667     }
668   }
669 
670   GAP_TRACE_EVENT("%s() - BDA: %08x%04x  cl_op_uuid: 0x%04x", __func__,
671                   (peer_bda[0] << 24) + (peer_bda[1] << 16) +
672                       (peer_bda[2] << 8) + peer_bda[3],
673                   (peer_bda[4] << 8) + peer_bda[5], uuid);
674 
675   if (GATT_GetConnIdIfConnected(gap_cb.gatt_if, peer_bda, &p_clcb->conn_id,
676                                 BT_TRANSPORT_LE))
677     p_clcb->connected = true;
678 
679   if (!GATT_Connect(gap_cb.gatt_if, p_clcb->bda, true, BT_TRANSPORT_LE, true))
680     return started;
681 
682   /* enqueue the request */
683   gap_ble_enqueue_request(p_clcb, uuid, p_cback);
684 
685   if (p_clcb->connected && p_clcb->cl_op_uuid == 0)
686     started = gap_ble_send_cl_read_request(p_clcb);
687   else /* wait for connection up or pending operation to finish */
688     started = true;
689 
690   return started;
691 }
692 /*******************************************************************************
693  *
694  * Function         GAP_BleReadPeerPrefConnParams
695  *
696  * Description      Start a process to read a connected peripheral's preferred
697  *                  connection parameters
698  *
699  * Returns          true if read started, else false if GAP is busy
700  *
701  ******************************************************************************/
GAP_BleReadPeerPrefConnParams(BD_ADDR peer_bda)702 bool GAP_BleReadPeerPrefConnParams(BD_ADDR peer_bda) {
703   return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_PREF_CONN_PARAM,
704                                      NULL);
705 }
706 
707 /*******************************************************************************
708  *
709  * Function         GAP_BleReadPeerDevName
710  *
711  * Description      Start a process to read a connected peripheral's device
712  *                  name.
713  *
714  * Returns          true if request accepted
715  *
716  ******************************************************************************/
GAP_BleReadPeerDevName(BD_ADDR peer_bda,tGAP_BLE_CMPL_CBACK * p_cback)717 bool GAP_BleReadPeerDevName(BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK* p_cback) {
718   return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_DEVICE_NAME,
719                                      p_cback);
720 }
721 
722 /*******************************************************************************
723  *
724  * Function         GAP_BleReadPeerAddressResolutionCap
725  *
726  * Description      Start a process to read peer address resolution capability
727  *
728  * Returns          true if request accepted
729  *
730  ******************************************************************************/
GAP_BleReadPeerAddressResolutionCap(BD_ADDR peer_bda,tGAP_BLE_CMPL_CBACK * p_cback)731 bool GAP_BleReadPeerAddressResolutionCap(BD_ADDR peer_bda,
732                                          tGAP_BLE_CMPL_CBACK* p_cback) {
733   return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_CENTRAL_ADDR_RESOL,
734                                      p_cback);
735 }
736 
737 /*******************************************************************************
738  *
739  * Function         GAP_BleCancelReadPeerDevName
740  *
741  * Description      Cancel reading a peripheral's device name.
742  *
743  * Returns          true if request accepted
744  *
745  ******************************************************************************/
GAP_BleCancelReadPeerDevName(BD_ADDR peer_bda)746 bool GAP_BleCancelReadPeerDevName(BD_ADDR peer_bda) {
747   tGAP_CLCB* p_clcb = gap_find_clcb_by_bd_addr(peer_bda);
748 
749   GAP_TRACE_EVENT(
750       "GAP_BleCancelReadPeerDevName() - BDA: %08x%04x  cl_op_uuid: 0x%04x",
751       (peer_bda[0] << 24) + (peer_bda[1] << 16) + (peer_bda[2] << 8) +
752           peer_bda[3],
753       (peer_bda[4] << 8) + peer_bda[5],
754       (p_clcb == NULL) ? 0 : p_clcb->cl_op_uuid);
755 
756   if (p_clcb == NULL) {
757     GAP_TRACE_ERROR("Cannot cancel current op is not get dev name");
758     return false;
759   }
760 
761   if (!p_clcb->connected) {
762     if (!GATT_CancelConnect(gap_cb.gatt_if, peer_bda, true)) {
763       GAP_TRACE_ERROR("Cannot cancel where No connection id");
764       return false;
765     }
766   }
767 
768   gap_ble_cl_op_cmpl(p_clcb, false, 0, NULL);
769 
770   return (true);
771 }
772