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(¶m, 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, ¶m) ==
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