1 /******************************************************************************
2 *
3 * Copyright (C) 1999-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 GATT interface functions
22 *
23 ******************************************************************************/
24 #include "bt_target.h"
25
26 #include <base/bind.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include "bt_common.h"
30 #include "btm_int.h"
31 #include "btu.h"
32 #include "device/include/controller.h"
33 #include "gatt_api.h"
34 #include "gatt_int.h"
35 #include "l2c_api.h"
36
37 /*******************************************************************************
38 *
39 * Function GATT_SetTraceLevel
40 *
41 * Description This function sets the trace level. If called with
42 * a value of 0xFF, it simply returns the current trace level.
43 *
44 * Input Parameters:
45 * level: The level to set the GATT tracing to:
46 * 0xff-returns the current setting.
47 * 0-turns off tracing.
48 * >= 1-Errors.
49 * >= 2-Warnings.
50 * >= 3-APIs.
51 * >= 4-Events.
52 * >= 5-Debug.
53 *
54 * Returns The new or current trace level
55 *
56 ******************************************************************************/
GATT_SetTraceLevel(uint8_t new_level)57 uint8_t GATT_SetTraceLevel(uint8_t new_level) {
58 if (new_level != 0xFF) gatt_cb.trace_level = new_level;
59
60 return (gatt_cb.trace_level);
61 }
62
63 /**
64 * Add an service handle range to the list in decending order of the start
65 * handle. Return reference to the newly added element.
66 **/
gatt_add_an_item_to_list(uint16_t s_handle)67 tGATT_HDL_LIST_ELEM& gatt_add_an_item_to_list(uint16_t s_handle) {
68 auto lst_ptr = gatt_cb.hdl_list_info;
69 auto it = lst_ptr->begin();
70 for (; it != lst_ptr->end(); it++) {
71 if (s_handle > it->asgn_range.s_handle) break;
72 }
73
74 auto rit = lst_ptr->emplace(it);
75 return *rit;
76 }
77
78 /*****************************************************************************
79 *
80 * GATT SERVER API
81 *
82 *****************************************************************************/
83 /*******************************************************************************
84 *
85 * Function GATTS_AddHandleRange
86 *
87 * Description This function add the allocated handles range for the
88 * specified application UUID, service UUID and service
89 * instance
90 *
91 * Parameter p_hndl_range: pointer to allocated handles information
92 *
93 **/
94
GATTS_AddHandleRange(tGATTS_HNDL_RANGE * p_hndl_range)95 void GATTS_AddHandleRange(tGATTS_HNDL_RANGE* p_hndl_range) {
96 gatt_add_an_item_to_list(p_hndl_range->s_handle);
97 }
98
99 /*******************************************************************************
100 *
101 * Function GATTS_NVRegister
102 *
103 * Description Application manager calls this function to register for
104 * NV save callback function. There can be one and only one
105 * NV save callback function.
106 *
107 * Parameter p_cb_info : callback informaiton
108 *
109 * Returns true if registered OK, else false
110 *
111 ******************************************************************************/
GATTS_NVRegister(tGATT_APPL_INFO * p_cb_info)112 bool GATTS_NVRegister(tGATT_APPL_INFO* p_cb_info) {
113 bool status = false;
114 if (p_cb_info) {
115 gatt_cb.cb_info = *p_cb_info;
116 status = true;
117 gatt_init_srv_chg();
118 }
119
120 return status;
121 }
122
123 static uint8_t BASE_UUID[16] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
124 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
125
uuidType(unsigned char * p_uuid)126 static int uuidType(unsigned char* p_uuid) {
127 if (memcmp(p_uuid, BASE_UUID, 12) != 0) return LEN_UUID_128;
128 if (memcmp(p_uuid + 14, BASE_UUID + 14, 2) != 0) return LEN_UUID_32;
129
130 return LEN_UUID_16;
131 }
132
133 /*******************************************************************************
134 * BTIF -> BTA conversion functions
135 ******************************************************************************/
136
btif_to_bta_uuid(tBT_UUID * p_dest,bt_uuid_t * p_src)137 static void btif_to_bta_uuid(tBT_UUID* p_dest, bt_uuid_t* p_src) {
138 char* p_byte = (char*)p_src;
139 int i = 0;
140
141 p_dest->len = uuidType(p_src->uu);
142
143 switch (p_dest->len) {
144 case LEN_UUID_16:
145 p_dest->uu.uuid16 = (p_src->uu[13] << 8) + p_src->uu[12];
146 break;
147
148 case LEN_UUID_32:
149 p_dest->uu.uuid32 = (p_src->uu[15] << 24) + (p_src->uu[14] << 16) +
150 (p_src->uu[13] << 8) + p_src->uu[12];
151 break;
152
153 case LEN_UUID_128:
154 for (i = 0; i != 16; ++i) p_dest->uu.uuid128[i] = p_byte[i];
155 break;
156
157 default:
158 GATT_TRACE_ERROR("%s: Unknown UUID length %d!", __func__, p_dest->len);
159 break;
160 }
161 }
162
uuid_128_from_16(bt_uuid_t * uuid,uint16_t uuid16)163 void uuid_128_from_16(bt_uuid_t* uuid, uint16_t uuid16) {
164 memcpy(uuid, &BASE_UUID, sizeof(bt_uuid_t));
165
166 uuid->uu[13] = (uint8_t)((0xFF00 & uuid16) >> 8);
167 uuid->uu[12] = (uint8_t)(0x00FF & uuid16);
168 }
169
compute_service_size(btgatt_db_element_t * service,int count)170 static uint16_t compute_service_size(btgatt_db_element_t* service, int count) {
171 int db_size = 0;
172 btgatt_db_element_t* el = service;
173
174 for (int i = 0; i < count; i++, el++)
175 if (el->type == BTGATT_DB_PRIMARY_SERVICE ||
176 el->type == BTGATT_DB_SECONDARY_SERVICE ||
177 el->type == BTGATT_DB_DESCRIPTOR ||
178 el->type == BTGATT_DB_INCLUDED_SERVICE)
179 db_size += 1;
180 else if (el->type == BTGATT_DB_CHARACTERISTIC)
181 db_size += 2;
182 else
183 GATT_TRACE_ERROR("%s: Unknown element type: %d", __func__, el->type);
184
185 return db_size;
186 }
187
is_gatt_attr_type(const tBT_UUID & uuid)188 static bool is_gatt_attr_type(const tBT_UUID& uuid) {
189 if (uuid.len == LEN_UUID_16 && (uuid.uu.uuid16 == GATT_UUID_PRI_SERVICE ||
190 uuid.uu.uuid16 == GATT_UUID_SEC_SERVICE ||
191 uuid.uu.uuid16 == GATT_UUID_INCLUDE_SERVICE ||
192 uuid.uu.uuid16 == GATT_UUID_CHAR_DECLARE)) {
193 return true;
194 }
195 return false;
196 }
197
198 /** Update the the last primary info for the service list info */
gatt_update_last_pri_srv_info()199 static void gatt_update_last_pri_srv_info() {
200 gatt_cb.last_primary_s_handle = 0;
201
202 for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info)
203 if (el.is_primary) gatt_cb.last_primary_s_handle = el.s_hdl;
204 }
205
206 /*******************************************************************************
207 *
208 * Function GATTS_AddService
209 *
210 * Description This function is called to add GATT service.
211 *
212 * Parameter gatt_if : application if
213 * service : pseudo-representation of service and it's content
214 * count : size of service
215 *
216 * Returns on success GATT_SERVICE_STARTED is returned, and
217 * attribute_handle field inside service elements are filled.
218 * on error error status is returned.
219 *
220 ******************************************************************************/
GATTS_AddService(tGATT_IF gatt_if,btgatt_db_element_t * service,int count)221 uint16_t GATTS_AddService(tGATT_IF gatt_if, btgatt_db_element_t* service,
222 int count) {
223 uint16_t s_hdl = 0;
224 bool save_hdl = false;
225 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
226 tBT_UUID* p_app_uuid128;
227
228 bool is_pri = (service->type == BTGATT_DB_PRIMARY_SERVICE) ? true : false;
229 tBT_UUID svc_uuid;
230 btif_to_bta_uuid(&svc_uuid, &service->uuid);
231
232 GATT_TRACE_API("%s", __func__);
233
234 if (p_reg == NULL) {
235 GATT_TRACE_ERROR("Inavlid gatt_if=%d", gatt_if);
236 return GATT_INTERNAL_ERROR;
237 }
238
239 p_app_uuid128 = &p_reg->app_uuid128;
240
241 uint16_t num_handles = compute_service_size(service, count);
242
243 if ((svc_uuid.len == LEN_UUID_16) &&
244 (svc_uuid.uu.uuid16 == UUID_SERVCLASS_GATT_SERVER)) {
245 s_hdl = gatt_cb.hdl_cfg.gatt_start_hdl;
246 } else if ((svc_uuid.len == LEN_UUID_16) &&
247 (svc_uuid.uu.uuid16 == UUID_SERVCLASS_GAP_SERVER)) {
248 s_hdl = gatt_cb.hdl_cfg.gap_start_hdl;
249 } else {
250 if (!gatt_cb.hdl_list_info->empty()) {
251 s_hdl = gatt_cb.hdl_list_info->front().asgn_range.e_handle + 1;
252 }
253
254 if (s_hdl < gatt_cb.hdl_cfg.app_start_hdl)
255 s_hdl = gatt_cb.hdl_cfg.app_start_hdl;
256
257 save_hdl = true;
258 }
259
260 /* check for space */
261 if (num_handles > (0xFFFF - s_hdl + 1)) {
262 GATT_TRACE_ERROR("GATTS_ReserveHandles: no handles, s_hdl: %u needed: %u",
263 s_hdl, num_handles);
264 return GATT_INTERNAL_ERROR;
265 }
266
267 tGATT_HDL_LIST_ELEM& list = gatt_add_an_item_to_list(s_hdl);
268 list.asgn_range.app_uuid128 = *p_app_uuid128;
269 list.asgn_range.svc_uuid = svc_uuid;
270 list.asgn_range.s_handle = s_hdl;
271 list.asgn_range.e_handle = s_hdl + num_handles - 1;
272 list.asgn_range.is_primary = is_pri;
273
274 if (save_hdl) {
275 if (gatt_cb.cb_info.p_nv_save_callback)
276 (*gatt_cb.cb_info.p_nv_save_callback)(true, &list.asgn_range);
277 }
278
279 gatts_init_service_db(list.svc_db, &svc_uuid, is_pri, s_hdl, num_handles);
280
281 GATT_TRACE_DEBUG(
282 "%d: handles needed:%u s_hdl=%u e_hdl=%u %s[%x] is_primary=%d", __func__,
283 num_handles, list.asgn_range.s_handle, list.asgn_range.e_handle,
284 ((list.asgn_range.svc_uuid.len == 2) ? "uuid16" : "uuid128"),
285 list.asgn_range.svc_uuid.uu.uuid16, list.asgn_range.is_primary);
286
287 service->attribute_handle = s_hdl;
288
289 btgatt_db_element_t* el = service + 1;
290 for (int i = 0; i < count - 1; i++, el++) {
291 tBT_UUID uuid;
292 btif_to_bta_uuid(&uuid, &el->uuid);
293
294 if (el->type == BTGATT_DB_CHARACTERISTIC) {
295 /* data validity checking */
296 if (((el->properties & GATT_CHAR_PROP_BIT_AUTH) &&
297 !(el->permissions & GATT_WRITE_SIGNED_PERM)) ||
298 ((el->permissions & GATT_WRITE_SIGNED_PERM) &&
299 !(el->properties & GATT_CHAR_PROP_BIT_AUTH))) {
300 GATT_TRACE_DEBUG("Invalid configuration property=0x%02x perm=0x%04x ",
301 el->properties, el->permissions);
302 return GATT_INTERNAL_ERROR;
303 }
304
305 if (is_gatt_attr_type(uuid)) {
306 GATT_TRACE_ERROR(
307 "%s: attept to add characteristic with UUID equal to GATT "
308 "Attribute Type 0x%04x ",
309 __func__, uuid.uu.uuid16);
310 return GATT_INTERNAL_ERROR;
311 }
312
313 el->attribute_handle = gatts_add_characteristic(
314 list.svc_db, el->permissions, el->properties, uuid);
315 } else if (el->type == BTGATT_DB_DESCRIPTOR) {
316 if (is_gatt_attr_type(uuid)) {
317 GATT_TRACE_ERROR(
318 "%s: attept to add descriptor with UUID equal to GATT "
319 "Attribute Type 0x%04x ",
320 __func__, uuid.uu.uuid16);
321 return GATT_INTERNAL_ERROR;
322 }
323
324 el->attribute_handle =
325 gatts_add_char_descr(list.svc_db, el->permissions, uuid);
326 } else if (el->type == BTGATT_DB_INCLUDED_SERVICE) {
327 tGATT_HDL_LIST_ELEM* p_incl_decl;
328 p_incl_decl = gatt_find_hdl_buffer_by_handle(el->attribute_handle);
329 if (p_incl_decl == nullptr) {
330 GATT_TRACE_DEBUG("Included Service not created");
331 return GATT_INTERNAL_ERROR;
332 }
333
334 el->attribute_handle = gatts_add_included_service(
335 list.svc_db, p_incl_decl->asgn_range.s_handle,
336 p_incl_decl->asgn_range.e_handle, p_incl_decl->asgn_range.svc_uuid);
337 }
338 }
339
340 GATT_TRACE_API("%s: service parsed correctly, now starting", __func__);
341
342 /*this is a new application service start */
343
344 // find a place for this service in the list
345 auto lst_ptr = gatt_cb.srv_list_info;
346 auto it = lst_ptr->begin();
347 for (; it != lst_ptr->end(); it++) {
348 if (list.asgn_range.s_handle < it->s_hdl) break;
349 }
350 auto rit = lst_ptr->emplace(it);
351
352 tGATT_SRV_LIST_ELEM& elem = *rit;
353 elem.gatt_if = gatt_if;
354 elem.s_hdl = list.asgn_range.s_handle;
355 elem.e_hdl = list.asgn_range.e_handle;
356 elem.p_db = &list.svc_db;
357 elem.is_primary = list.asgn_range.is_primary;
358
359 memcpy(&elem.app_uuid, &list.asgn_range.app_uuid128, sizeof(tBT_UUID));
360 elem.type = list.asgn_range.is_primary ? GATT_UUID_PRI_SERVICE
361 : GATT_UUID_SEC_SERVICE;
362
363 if (elem.type == GATT_UUID_PRI_SERVICE) {
364 tBT_UUID* p_uuid = gatts_get_service_uuid(elem.p_db);
365 elem.sdp_handle = gatt_add_sdp_record(p_uuid, elem.s_hdl, elem.e_hdl);
366 } else {
367 elem.sdp_handle = 0;
368 }
369
370 gatt_update_last_pri_srv_info();
371
372 GATT_TRACE_DEBUG("%s: allocated el: s_hdl=%d e_hdl=%d type=0x%x sdp_hdl=0x%x",
373 __func__, elem.s_hdl, elem.e_hdl, elem.type,
374 elem.sdp_handle);
375
376 gatt_proc_srv_chg();
377
378 return GATT_SERVICE_STARTED;
379 }
380
is_active_service(tBT_UUID * p_app_uuid128,tBT_UUID * p_svc_uuid,uint16_t start_handle)381 bool is_active_service(tBT_UUID* p_app_uuid128, tBT_UUID* p_svc_uuid,
382 uint16_t start_handle) {
383 for (auto& info : *gatt_cb.srv_list_info) {
384 tBT_UUID* p_this_uuid = gatts_get_service_uuid(info.p_db);
385
386 if (p_this_uuid && gatt_uuid_compare(*p_app_uuid128, info.app_uuid) &&
387 gatt_uuid_compare(*p_svc_uuid, *p_this_uuid) &&
388 (start_handle == info.s_hdl)) {
389 GATT_TRACE_ERROR("Active Service Found ");
390 gatt_dbg_display_uuid(*p_svc_uuid);
391
392 return true;
393 }
394 }
395 return false;
396 }
397
398 /*******************************************************************************
399 *
400 * Function GATTS_DeleteService
401 *
402 * Description This function is called to delete a service.
403 *
404 * Parameter gatt_if : application interface
405 * p_svc_uuid : service UUID
406 * start_handle : start handle of the service
407 *
408 * Returns true if the operation succeeded, false if the handle block
409 * was not found.
410 *
411 ******************************************************************************/
GATTS_DeleteService(tGATT_IF gatt_if,tBT_UUID * p_svc_uuid,uint16_t svc_inst)412 bool GATTS_DeleteService(tGATT_IF gatt_if, tBT_UUID* p_svc_uuid,
413 uint16_t svc_inst) {
414 GATT_TRACE_DEBUG("GATTS_DeleteService");
415
416 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
417 if (p_reg == NULL) {
418 GATT_TRACE_ERROR("Applicaiton not foud");
419 return false;
420 }
421
422 tBT_UUID* p_app_uuid128 = &p_reg->app_uuid128;
423 auto it = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst);
424 if (it == gatt_cb.hdl_list_info->end()) {
425 GATT_TRACE_ERROR("No Service found");
426 return false;
427 }
428
429 gatt_proc_srv_chg();
430
431 if (is_active_service(p_app_uuid128, p_svc_uuid, svc_inst)) {
432 GATTS_StopService(it->asgn_range.s_handle);
433 }
434
435 GATT_TRACE_DEBUG("released handles s_hdl=%u e_hdl=%u",
436 it->asgn_range.s_handle, it->asgn_range.e_handle);
437
438 if ((it->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl) &&
439 gatt_cb.cb_info.p_nv_save_callback)
440 (*gatt_cb.cb_info.p_nv_save_callback)(false, &it->asgn_range);
441
442 gatt_cb.hdl_list_info->erase(it);
443 return true;
444 }
445
446 /*******************************************************************************
447 *
448 * Function GATTS_StopService
449 *
450 * Description This function is called to stop a service
451 *
452 * Parameter service_handle : this is the start handle of a service
453 *
454 * Returns None.
455 *
456 ******************************************************************************/
GATTS_StopService(uint16_t service_handle)457 void GATTS_StopService(uint16_t service_handle) {
458 GATT_TRACE_API("%s: %u", __func__, service_handle);
459
460 auto it = gatt_sr_find_i_rcb_by_handle(service_handle);
461 if (it == gatt_cb.srv_list_info->end()) {
462 GATT_TRACE_ERROR("%s: service_handle: %u is not in use", __func__,
463 service_handle);
464 }
465
466 if (it->sdp_handle) {
467 SDP_DeleteRecord(it->sdp_handle);
468 }
469
470 gatt_cb.srv_list_info->erase(it);
471 gatt_update_last_pri_srv_info();
472 }
473 /*******************************************************************************
474 *
475 * Function GATTs_HandleValueIndication
476 *
477 * Description This function sends a handle value indication to a client.
478 *
479 * Parameter conn_id: connection identifier.
480 * attr_handle: Attribute handle of this handle value
481 * indication.
482 * val_len: Length of the indicated attribute value.
483 * p_val: Pointer to the indicated attribute value data.
484 *
485 * Returns GATT_SUCCESS if sucessfully sent or queued; otherwise error
486 * code.
487 *
488 ******************************************************************************/
GATTS_HandleValueIndication(uint16_t conn_id,uint16_t attr_handle,uint16_t val_len,uint8_t * p_val)489 tGATT_STATUS GATTS_HandleValueIndication(uint16_t conn_id, uint16_t attr_handle,
490 uint16_t val_len, uint8_t* p_val) {
491 tGATT_STATUS cmd_status = GATT_NO_RESOURCES;
492
493 tGATT_VALUE indication;
494 BT_HDR* p_msg;
495 tGATT_VALUE* p_buf;
496 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
497 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
498 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
499 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
500
501 GATT_TRACE_API("GATTS_HandleValueIndication");
502 if ((p_reg == NULL) || (p_tcb == NULL)) {
503 GATT_TRACE_ERROR("GATTS_HandleValueIndication Unknown conn_id: %u ",
504 conn_id);
505 return (tGATT_STATUS)GATT_INVALID_CONN_ID;
506 }
507
508 if (!GATT_HANDLE_IS_VALID(attr_handle)) return GATT_ILLEGAL_PARAMETER;
509
510 indication.conn_id = conn_id;
511 indication.handle = attr_handle;
512 indication.len = val_len;
513 memcpy(indication.value, p_val, val_len);
514 indication.auth_req = GATT_AUTH_REQ_NONE;
515
516 if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle)) {
517 GATT_TRACE_DEBUG("Add a pending indication");
518 p_buf = gatt_add_pending_ind(p_tcb, &indication);
519 if (p_buf != NULL) {
520 cmd_status = GATT_SUCCESS;
521 } else {
522 cmd_status = GATT_NO_RESOURCES;
523 }
524 } else {
525 p_msg = attp_build_sr_msg(p_tcb, GATT_HANDLE_VALUE_IND,
526 (tGATT_SR_MSG*)&indication);
527 if (p_msg != NULL) {
528 cmd_status = attp_send_sr_msg(p_tcb, p_msg);
529
530 if (cmd_status == GATT_SUCCESS || cmd_status == GATT_CONGESTED) {
531 p_tcb->indicate_handle = indication.handle;
532 gatt_start_conf_timer(p_tcb);
533 }
534 }
535 }
536 return cmd_status;
537 }
538
539 /*******************************************************************************
540 *
541 * Function GATTS_HandleValueNotification
542 *
543 * Description This function sends a handle value notification to a client.
544 *
545 * Parameter conn_id: connection identifier.
546 * attr_handle: Attribute handle of this handle value
547 * indication.
548 * val_len: Length of the indicated attribute value.
549 * p_val: Pointer to the indicated attribute value data.
550 *
551 * Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
552 *
553 ******************************************************************************/
GATTS_HandleValueNotification(uint16_t conn_id,uint16_t attr_handle,uint16_t val_len,uint8_t * p_val)554 tGATT_STATUS GATTS_HandleValueNotification(uint16_t conn_id,
555 uint16_t attr_handle,
556 uint16_t val_len, uint8_t* p_val) {
557 tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
558 BT_HDR* p_buf;
559 tGATT_VALUE notif;
560 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
561 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
562 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
563 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
564
565 GATT_TRACE_API("GATTS_HandleValueNotification");
566
567 if ((p_reg == NULL) || (p_tcb == NULL)) {
568 GATT_TRACE_ERROR("GATTS_HandleValueNotification Unknown conn_id: %u ",
569 conn_id);
570 return (tGATT_STATUS)GATT_INVALID_CONN_ID;
571 }
572
573 if (GATT_HANDLE_IS_VALID(attr_handle)) {
574 notif.handle = attr_handle;
575 notif.len = val_len;
576 memcpy(notif.value, p_val, val_len);
577 notif.auth_req = GATT_AUTH_REQ_NONE;
578 ;
579
580 p_buf = attp_build_sr_msg(p_tcb, GATT_HANDLE_VALUE_NOTIF,
581 (tGATT_SR_MSG*)¬if);
582 if (p_buf != NULL) {
583 cmd_sent = attp_send_sr_msg(p_tcb, p_buf);
584 } else
585 cmd_sent = GATT_NO_RESOURCES;
586 }
587 return cmd_sent;
588 }
589
590 /*******************************************************************************
591 *
592 * Function GATTS_SendRsp
593 *
594 * Description This function sends the server response to client.
595 *
596 * Parameter conn_id: connection identifier.
597 * trans_id: transaction id
598 * status: response status
599 * p_msg: pointer to message parameters structure.
600 *
601 * Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
602 *
603 ******************************************************************************/
GATTS_SendRsp(uint16_t conn_id,uint32_t trans_id,tGATT_STATUS status,tGATTS_RSP * p_msg)604 tGATT_STATUS GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id,
605 tGATT_STATUS status, tGATTS_RSP* p_msg) {
606 tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
607 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
608 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
609 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
610 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
611
612 GATT_TRACE_API("GATTS_SendRsp: conn_id: %u trans_id: %u Status: 0x%04x",
613 conn_id, trans_id, status);
614
615 if ((p_reg == NULL) || (p_tcb == NULL)) {
616 GATT_TRACE_ERROR("GATTS_SendRsp Unknown conn_id: %u ", conn_id);
617 return (tGATT_STATUS)GATT_INVALID_CONN_ID;
618 }
619
620 if (p_tcb->sr_cmd.trans_id != trans_id) {
621 GATT_TRACE_ERROR("GATTS_SendRsp conn_id: %u waiting for op_code = %02x",
622 conn_id, p_tcb->sr_cmd.op_code);
623
624 return (GATT_WRONG_STATE);
625 }
626 /* Process App response */
627 cmd_sent = gatt_sr_process_app_rsp(p_tcb, gatt_if, trans_id,
628 p_tcb->sr_cmd.op_code, status, p_msg);
629
630 return cmd_sent;
631 }
632
633 /******************************************************************************/
634 /* GATT Profile Srvr Functions */
635 /******************************************************************************/
636
637 /******************************************************************************/
638 /* */
639 /* GATT CLIENT APIs */
640 /* */
641 /******************************************************************************/
642
643 /*******************************************************************************
644 *
645 * Function GATTC_ConfigureMTU
646 *
647 * Description This function is called to configure the ATT MTU size.
648 *
649 * Parameters conn_id: connection identifier.
650 * mtu - attribute MTU size..
651 *
652 * Returns GATT_SUCCESS if command started successfully.
653 *
654 ******************************************************************************/
GATTC_ConfigureMTU(uint16_t conn_id,uint16_t mtu)655 tGATT_STATUS GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu) {
656 uint8_t ret = GATT_NO_RESOURCES;
657 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
658 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
659 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
660 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
661
662 tGATT_CLCB* p_clcb;
663
664 GATT_TRACE_API("GATTC_ConfigureMTU conn_id=%d mtu=%d", conn_id, mtu);
665
666 if ((p_tcb == NULL) || (p_reg == NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) ||
667 (mtu > GATT_MAX_MTU_SIZE)) {
668 return GATT_ILLEGAL_PARAMETER;
669 }
670
671 /* Validate that the link is BLE, not BR/EDR */
672 if (p_tcb->transport != BT_TRANSPORT_LE) {
673 return GATT_ERROR;
674 }
675
676 if (gatt_is_clcb_allocated(conn_id)) {
677 GATT_TRACE_ERROR("GATTC_ConfigureMTU GATT_BUSY conn_id = %d", conn_id);
678 return GATT_BUSY;
679 }
680
681 p_clcb = gatt_clcb_alloc(conn_id);
682 if (p_clcb != NULL) {
683 p_clcb->p_tcb->payload_size = mtu;
684 p_clcb->operation = GATTC_OPTYPE_CONFIG;
685
686 ret = attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU,
687 (tGATT_CL_MSG*)&mtu);
688 }
689
690 return ret;
691 }
692
read_phy_cb(base::Callback<void (uint8_t tx_phy,uint8_t rx_phy,uint8_t status)> cb,uint8_t * data,uint16_t len)693 void read_phy_cb(
694 base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb,
695 uint8_t* data, uint16_t len) {
696 uint8_t status, tx_phy, rx_phy;
697 uint16_t handle;
698
699 LOG_ASSERT(len == 5) << "Received bad response length: " << len;
700 uint8_t* pp = data;
701 STREAM_TO_UINT8(status, pp);
702 STREAM_TO_UINT16(handle, pp);
703 handle = handle & 0x0FFF;
704 STREAM_TO_UINT8(tx_phy, pp);
705 STREAM_TO_UINT8(rx_phy, pp);
706
707 DVLOG(1) << __func__ << " Received read_phy_cb";
708 cb.Run(tx_phy, rx_phy, status);
709 }
710
GATTC_ReadPHY(uint16_t conn_id,base::Callback<void (uint8_t tx_phy,uint8_t rx_phy,uint8_t status)> cb)711 void GATTC_ReadPHY(
712 uint16_t conn_id,
713 base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb) {
714 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
715 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
716 if (p_tcb == NULL) {
717 GATT_TRACE_ERROR("%s: no p_tcb for conn_id %d", __func__, conn_id);
718 cb.Run(0, 0, GATT_INVALID_HANDLE);
719 return;
720 }
721
722 tACL_CONN* p_lcb = btm_bda_to_acl(p_tcb->peer_bda, BT_TRANSPORT_LE);
723 if (p_lcb == NULL) {
724 GATT_TRACE_ERROR("%s: no p_lcb for conn_id %d", __func__, conn_id);
725 cb.Run(0, 0, GATT_INVALID_HANDLE);
726 return;
727 }
728 uint16_t handle = p_lcb->hci_handle;
729
730 const uint8_t len = 2;
731 uint8_t data[len];
732 uint8_t* pp = data;
733 UINT16_TO_STREAM(pp, handle);
734 btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_LE_READ_PHY, data, len,
735 base::Bind(&read_phy_cb, std::move(cb)));
736 }
737
doNothing(uint8_t * data,uint16_t len)738 void doNothing(uint8_t* data, uint16_t len) {}
739
GATTC_SetPreferredPHY(uint16_t conn_id,uint8_t tx_phy,uint8_t rx_phy,uint16_t phy_options)740 void GATTC_SetPreferredPHY(uint16_t conn_id, uint8_t tx_phy, uint8_t rx_phy,
741 uint16_t phy_options) {
742 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
743 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
744 if (p_tcb == NULL) {
745 GATT_TRACE_ERROR("%s: no p_tcb for conn_id %d", __func__, conn_id);
746 return;
747 }
748
749 tACL_CONN* p_lcb = btm_bda_to_acl(p_tcb->peer_bda, BT_TRANSPORT_LE);
750 if (p_lcb == NULL) {
751 GATT_TRACE_ERROR("%s: no p_lcb for conn_id %d", __func__, conn_id);
752 return;
753 }
754 uint16_t handle = p_lcb->hci_handle;
755
756 uint8_t all_phys = 0;
757 if (tx_phy == 0) all_phys &= 0x01;
758 if (rx_phy == 0) all_phys &= 0x02;
759
760 const uint8_t len = 7;
761 uint8_t data[len];
762 uint8_t* pp = data;
763 UINT16_TO_STREAM(pp, handle);
764 UINT8_TO_STREAM(pp, all_phys);
765 UINT8_TO_STREAM(pp, tx_phy);
766 UINT8_TO_STREAM(pp, rx_phy);
767 UINT16_TO_STREAM(pp, phy_options);
768 btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_LE_SET_PHY, data, len,
769 base::Bind(doNothing));
770 }
771
772 /*******************************************************************************
773 *
774 * Function GATTC_Discover
775 *
776 * Description This function is called to do a discovery procedure on ATT
777 * server.
778 *
779 * Parameters conn_id: connection identifier.
780 * disc_type:discovery type.
781 * p_param: parameters of discovery requirement.
782 *
783 * Returns GATT_SUCCESS if command received/sent successfully.
784 *
785 ******************************************************************************/
GATTC_Discover(uint16_t conn_id,tGATT_DISC_TYPE disc_type,tGATT_DISC_PARAM * p_param)786 tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
787 tGATT_DISC_PARAM* p_param) {
788 tGATT_STATUS status = GATT_SUCCESS;
789 tGATT_CLCB* p_clcb;
790 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
791 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
792 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
793 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
794
795 GATT_TRACE_API("GATTC_Discover conn_id=%d disc_type=%d", conn_id, disc_type);
796
797 if ((p_tcb == NULL) || (p_reg == NULL) || (p_param == NULL) ||
798 (disc_type >= GATT_DISC_MAX)) {
799 GATT_TRACE_ERROR("GATTC_Discover Illegal param: disc_type %d conn_id = %d",
800 disc_type, conn_id);
801 return GATT_ILLEGAL_PARAMETER;
802 }
803
804 if (gatt_is_clcb_allocated(conn_id)) {
805 GATT_TRACE_ERROR("GATTC_Discover GATT_BUSY conn_id = %d", conn_id);
806 return GATT_BUSY;
807 }
808
809 p_clcb = gatt_clcb_alloc(conn_id);
810 if (p_clcb != NULL) {
811 if (!GATT_HANDLE_IS_VALID(p_param->s_handle) ||
812 !GATT_HANDLE_IS_VALID(p_param->e_handle) ||
813 /* search by type does not have a valid UUID param */
814 (disc_type == GATT_DISC_SRVC_BY_UUID && p_param->service.len == 0)) {
815 gatt_clcb_dealloc(p_clcb);
816 return GATT_ILLEGAL_PARAMETER;
817 }
818
819 p_clcb->operation = GATTC_OPTYPE_DISCOVERY;
820 p_clcb->op_subtype = disc_type;
821 p_clcb->s_handle = p_param->s_handle;
822 p_clcb->e_handle = p_param->e_handle;
823 p_clcb->uuid = p_param->service;
824
825 gatt_act_discovery(p_clcb);
826 } else {
827 status = GATT_NO_RESOURCES;
828 }
829 return status;
830 }
831
832 /*******************************************************************************
833 *
834 * Function GATTC_Read
835 *
836 * Description This function is called to read the value of an attribute
837 * from the server.
838 *
839 * Parameters conn_id: connection identifier.
840 * type - attribute read type.
841 * p_read - read operation parameters.
842 *
843 * Returns GATT_SUCCESS if command started successfully.
844 *
845 ******************************************************************************/
GATTC_Read(uint16_t conn_id,tGATT_READ_TYPE type,tGATT_READ_PARAM * p_read)846 tGATT_STATUS GATTC_Read(uint16_t conn_id, tGATT_READ_TYPE type,
847 tGATT_READ_PARAM* p_read) {
848 tGATT_STATUS status = GATT_SUCCESS;
849 tGATT_CLCB* p_clcb;
850 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
851 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
852 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
853 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
854
855 GATT_TRACE_API("GATTC_Read conn_id=%d type=%d", conn_id, type);
856
857 if ((p_tcb == NULL) || (p_reg == NULL) || (p_read == NULL) ||
858 ((type >= GATT_READ_MAX) || (type == 0))) {
859 GATT_TRACE_ERROR("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id,
860 type);
861 return GATT_ILLEGAL_PARAMETER;
862 }
863
864 if (gatt_is_clcb_allocated(conn_id)) {
865 GATT_TRACE_ERROR("GATTC_Read GATT_BUSY conn_id = %d", conn_id);
866 return GATT_BUSY;
867 }
868
869 p_clcb = gatt_clcb_alloc(conn_id);
870 if (p_clcb != NULL) {
871 p_clcb->operation = GATTC_OPTYPE_READ;
872 p_clcb->op_subtype = type;
873 p_clcb->auth_req = p_read->by_handle.auth_req;
874 p_clcb->counter = 0;
875
876 switch (type) {
877 case GATT_READ_BY_TYPE:
878 case GATT_READ_CHAR_VALUE:
879 p_clcb->s_handle = p_read->service.s_handle;
880 p_clcb->e_handle = p_read->service.e_handle;
881 memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID));
882 break;
883 case GATT_READ_MULTIPLE: {
884 p_clcb->s_handle = 0;
885 /* copy multiple handles in CB */
886 tGATT_READ_MULTI* p_read_multi =
887 (tGATT_READ_MULTI*)osi_malloc(sizeof(tGATT_READ_MULTI));
888 p_clcb->p_attr_buf = (uint8_t*)p_read_multi;
889 memcpy(p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI));
890 break;
891 }
892 case GATT_READ_BY_HANDLE:
893 case GATT_READ_PARTIAL:
894 memset(&p_clcb->uuid, 0, sizeof(tBT_UUID));
895 p_clcb->s_handle = p_read->by_handle.handle;
896
897 if (type == GATT_READ_PARTIAL) {
898 p_clcb->counter = p_read->partial.offset;
899 }
900
901 break;
902 default:
903 break;
904 }
905 /* start security check */
906 if (gatt_security_check_start(p_clcb) == false) {
907 status = GATT_NO_RESOURCES;
908 gatt_clcb_dealloc(p_clcb);
909 }
910 } else {
911 status = GATT_NO_RESOURCES;
912 }
913 return status;
914 }
915
916 /*******************************************************************************
917 *
918 * Function GATTC_Write
919 *
920 * Description This function is called to write the value of an attribute
921 * to the server.
922 *
923 * Parameters conn_id: connection identifier.
924 * type - attribute write type.
925 * p_write - write operation parameters.
926 *
927 * Returns GATT_SUCCESS if command started successfully.
928 *
929 ******************************************************************************/
GATTC_Write(uint16_t conn_id,tGATT_WRITE_TYPE type,tGATT_VALUE * p_write)930 tGATT_STATUS GATTC_Write(uint16_t conn_id, tGATT_WRITE_TYPE type,
931 tGATT_VALUE* p_write) {
932 tGATT_STATUS status = GATT_SUCCESS;
933 tGATT_CLCB* p_clcb;
934 tGATT_VALUE* p;
935 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
936 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
937 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
938 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
939
940 if ((p_tcb == NULL) || (p_reg == NULL) || (p_write == NULL) ||
941 ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) &&
942 (type != GATT_WRITE_NO_RSP))) {
943 GATT_TRACE_ERROR("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id,
944 type);
945 return GATT_ILLEGAL_PARAMETER;
946 }
947
948 if (gatt_is_clcb_allocated(conn_id)) {
949 GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
950 return GATT_BUSY;
951 }
952
953 p_clcb = gatt_clcb_alloc(conn_id);
954 if (p_clcb != NULL) {
955 p_clcb->operation = GATTC_OPTYPE_WRITE;
956 p_clcb->op_subtype = type;
957 p_clcb->auth_req = p_write->auth_req;
958
959 p_clcb->p_attr_buf = (uint8_t*)osi_malloc(sizeof(tGATT_VALUE));
960 memcpy(p_clcb->p_attr_buf, (void*)p_write, sizeof(tGATT_VALUE));
961
962 p = (tGATT_VALUE*)p_clcb->p_attr_buf;
963 if (type == GATT_WRITE_PREPARE) {
964 p_clcb->start_offset = p_write->offset;
965 p->offset = 0;
966 }
967
968 if (gatt_security_check_start(p_clcb) == false) {
969 status = GATT_NO_RESOURCES;
970 }
971
972 if (status == GATT_NO_RESOURCES) gatt_clcb_dealloc(p_clcb);
973 } else {
974 status = GATT_NO_RESOURCES;
975 }
976 return status;
977 }
978
979 /*******************************************************************************
980 *
981 * Function GATTC_ExecuteWrite
982 *
983 * Description This function is called to send an Execute write request to
984 * the server.
985 *
986 * Parameters conn_id: connection identifier.
987 * is_execute - to execute or cancel the prepared write
988 * request(s)
989 *
990 * Returns GATT_SUCCESS if command started successfully.
991 *
992 ******************************************************************************/
GATTC_ExecuteWrite(uint16_t conn_id,bool is_execute)993 tGATT_STATUS GATTC_ExecuteWrite(uint16_t conn_id, bool is_execute) {
994 tGATT_STATUS status = GATT_SUCCESS;
995 tGATT_CLCB* p_clcb;
996 tGATT_EXEC_FLAG flag;
997 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
998 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
999 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1000 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
1001
1002 GATT_TRACE_API("GATTC_ExecuteWrite conn_id=%d is_execute=%d", conn_id,
1003 is_execute);
1004
1005 if ((p_tcb == NULL) || (p_reg == NULL)) {
1006 GATT_TRACE_ERROR("GATTC_ExecuteWrite Illegal param: conn_id %d", conn_id);
1007 return GATT_ILLEGAL_PARAMETER;
1008 }
1009
1010 if (gatt_is_clcb_allocated(conn_id)) {
1011 GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
1012 return GATT_BUSY;
1013 }
1014
1015 p_clcb = gatt_clcb_alloc(conn_id);
1016 if (p_clcb != NULL) {
1017 p_clcb->operation = GATTC_OPTYPE_EXE_WRITE;
1018 flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL;
1019 gatt_send_queue_write_cancel(p_clcb->p_tcb, p_clcb, flag);
1020 } else {
1021 GATT_TRACE_ERROR("Unable to allocate client CB for conn_id %d ", conn_id);
1022 status = GATT_NO_RESOURCES;
1023 }
1024 return status;
1025 }
1026
1027 /*******************************************************************************
1028 *
1029 * Function GATTC_SendHandleValueConfirm
1030 *
1031 * Description This function is called to send a handle value confirmation
1032 * as response to a handle value notification from server.
1033 *
1034 * Parameters conn_id: connection identifier.
1035 * handle: the handle of the attribute confirmation.
1036 *
1037 * Returns GATT_SUCCESS if command started successfully.
1038 *
1039 ******************************************************************************/
GATTC_SendHandleValueConfirm(uint16_t conn_id,uint16_t handle)1040 tGATT_STATUS GATTC_SendHandleValueConfirm(uint16_t conn_id, uint16_t handle) {
1041 tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER;
1042 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id));
1043
1044 GATT_TRACE_API("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id,
1045 handle);
1046
1047 if (p_tcb) {
1048 if (p_tcb->ind_count > 0) {
1049 alarm_cancel(p_tcb->ind_ack_timer);
1050
1051 GATT_TRACE_DEBUG("notif_count=%d ", p_tcb->ind_count);
1052 /* send confirmation now */
1053 ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF,
1054 (tGATT_CL_MSG*)&handle);
1055
1056 p_tcb->ind_count = 0;
1057
1058 } else {
1059 GATT_TRACE_DEBUG(
1060 "GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting "
1061 "for indicaiton ack",
1062 conn_id);
1063 ret = GATT_SUCCESS;
1064 }
1065 } else {
1066 GATT_TRACE_ERROR("GATTC_SendHandleValueConfirm - Unknown conn_id: %u",
1067 conn_id);
1068 }
1069 return ret;
1070 }
1071
1072 /******************************************************************************/
1073 /* */
1074 /* GATT APIs */
1075 /* */
1076 /******************************************************************************/
1077 /*******************************************************************************
1078 *
1079 * Function GATT_SetIdleTimeout
1080 *
1081 * Description This function (common to both client and server) sets the
1082 * idle timeout for a tansport connection
1083 *
1084 * Parameter bd_addr: target device bd address.
1085 * idle_tout: timeout value in seconds.
1086 *
1087 * Returns void
1088 *
1089 ******************************************************************************/
GATT_SetIdleTimeout(BD_ADDR bd_addr,uint16_t idle_tout,tBT_TRANSPORT transport)1090 void GATT_SetIdleTimeout(BD_ADDR bd_addr, uint16_t idle_tout,
1091 tBT_TRANSPORT transport) {
1092 tGATT_TCB* p_tcb;
1093 bool status = false;
1094
1095 p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
1096 if (p_tcb != NULL) {
1097 if (p_tcb->att_lcid == L2CAP_ATT_CID) {
1098 status = L2CA_SetFixedChannelTout(bd_addr, L2CAP_ATT_CID, idle_tout);
1099
1100 if (idle_tout == GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP)
1101 L2CA_SetIdleTimeoutByBdAddr(p_tcb->peer_bda,
1102 GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP,
1103 BT_TRANSPORT_LE);
1104 } else {
1105 status = L2CA_SetIdleTimeout(p_tcb->att_lcid, idle_tout, false);
1106 }
1107 }
1108
1109 GATT_TRACE_API(
1110 "GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)",
1111 idle_tout, status);
1112 }
1113
1114 /*******************************************************************************
1115 *
1116 * Function GATT_Register
1117 *
1118 * Description This function is called to register an application
1119 * with GATT
1120 *
1121 * Parameter p_app_uuid128: Application UUID
1122 * p_cb_info: callback functions.
1123 *
1124 * Returns 0 for error, otherwise the index of the client registered
1125 * with GATT
1126 *
1127 ******************************************************************************/
GATT_Register(tBT_UUID * p_app_uuid128,tGATT_CBACK * p_cb_info)1128 tGATT_IF GATT_Register(tBT_UUID* p_app_uuid128, tGATT_CBACK* p_cb_info) {
1129 tGATT_REG* p_reg;
1130 uint8_t i_gatt_if = 0;
1131 tGATT_IF gatt_if = 0;
1132
1133 GATT_TRACE_API("%s", __func__);
1134 gatt_dbg_display_uuid(*p_app_uuid128);
1135
1136 for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS;
1137 i_gatt_if++, p_reg++) {
1138 if (p_reg->in_use &&
1139 !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128,
1140 LEN_UUID_128)) {
1141 GATT_TRACE_ERROR("application already registered.");
1142 return 0;
1143 }
1144 }
1145
1146 for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS;
1147 i_gatt_if++, p_reg++) {
1148 if (!p_reg->in_use) {
1149 memset(p_reg, 0, sizeof(tGATT_REG));
1150 i_gatt_if++; /* one based number */
1151 p_reg->app_uuid128 = *p_app_uuid128;
1152 gatt_if = p_reg->gatt_if = (tGATT_IF)i_gatt_if;
1153 p_reg->app_cb = *p_cb_info;
1154 p_reg->in_use = true;
1155
1156 GATT_TRACE_API("%s: allocated gatt_if=%d", __func__, gatt_if);
1157 return gatt_if;
1158 }
1159 }
1160
1161 GATT_TRACE_ERROR("%s: can't Register GATT client, MAX client %d reached!",
1162 __func__, GATT_MAX_APPS);
1163 return 0;
1164 }
1165
1166 /*******************************************************************************
1167 *
1168 * Function GATT_Deregister
1169 *
1170 * Description This function deregistered the application from GATT.
1171 *
1172 * Parameters gatt_if: applicaiton interface.
1173 *
1174 * Returns None.
1175 *
1176 ******************************************************************************/
GATT_Deregister(tGATT_IF gatt_if)1177 void GATT_Deregister(tGATT_IF gatt_if) {
1178 GATT_TRACE_API("GATT_Deregister gatt_if=%d", gatt_if);
1179
1180 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
1181 /* Index 0 is GAP and is never deregistered */
1182 if ((gatt_if == 0) || (p_reg == NULL)) {
1183 GATT_TRACE_ERROR("GATT_Deregister with invalid gatt_if: %u", gatt_if);
1184 return;
1185 }
1186
1187 /* stop all services */
1188 /* todo an applcaiton can not be deregistered if its services is also used by
1189 other application
1190 deregisteration need to bed performed in an orderly fashion
1191 no check for now */
1192 for (auto& el : *gatt_cb.srv_list_info) {
1193 if (el.gatt_if == gatt_if) {
1194 GATTS_StopService(el.s_hdl);
1195 }
1196 }
1197
1198 /* free all services db buffers if owned by this application */
1199 gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128);
1200
1201 /* When an application deregisters, check remove the link associated with the
1202 * app */
1203 tGATT_TCB* p_tcb;
1204 int i, j;
1205 for (i = 0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++) {
1206 if (p_tcb->in_use) {
1207 if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE) {
1208 gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true);
1209 }
1210
1211 tGATT_CLCB* p_clcb;
1212 for (j = 0, p_clcb = &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB;
1213 j++, p_clcb++) {
1214 if (p_clcb->in_use && (p_clcb->p_reg->gatt_if == gatt_if) &&
1215 (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx)) {
1216 alarm_cancel(p_clcb->gatt_rsp_timer_ent);
1217 gatt_clcb_dealloc(p_clcb);
1218 break;
1219 }
1220 }
1221 }
1222 }
1223
1224 gatt_deregister_bgdev_list(gatt_if);
1225
1226 memset(p_reg, 0, sizeof(tGATT_REG));
1227 }
1228
1229 /*******************************************************************************
1230 *
1231 * Function GATT_StartIf
1232 *
1233 * Description This function is called after registration to start
1234 * receiving callbacks for registered interface. Function may
1235 * call back with connection status and queued notifications
1236 *
1237 * Parameter gatt_if: applicaiton interface.
1238 *
1239 * Returns None.
1240 *
1241 ******************************************************************************/
GATT_StartIf(tGATT_IF gatt_if)1242 void GATT_StartIf(tGATT_IF gatt_if) {
1243 tGATT_REG* p_reg;
1244 tGATT_TCB* p_tcb;
1245 BD_ADDR bda;
1246 uint8_t start_idx, found_idx;
1247 uint16_t conn_id;
1248 tGATT_TRANSPORT transport;
1249
1250 GATT_TRACE_API("GATT_StartIf gatt_if=%d", gatt_if);
1251 p_reg = gatt_get_regcb(gatt_if);
1252 if (p_reg != NULL) {
1253 start_idx = 0;
1254 while (
1255 gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport)) {
1256 p_tcb = gatt_find_tcb_by_addr(bda, transport);
1257 if (p_reg->app_cb.p_conn_cb && p_tcb) {
1258 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1259 (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, true, 0, transport);
1260 }
1261 start_idx = ++found_idx;
1262 }
1263 }
1264 }
1265
1266 /*******************************************************************************
1267 *
1268 * Function GATT_Connect
1269 *
1270 * Description This function initiate a connecttion to a remote device on
1271 * GATT channel.
1272 *
1273 * Parameters gatt_if: applicaiton interface
1274 * bd_addr: peer device address.
1275 * is_direct: is a direct conenection or a background auto
1276 * connection
1277 *
1278 * Returns true if connection started; false if connection start
1279 * failure.
1280 *
1281 ******************************************************************************/
GATT_Connect(tGATT_IF gatt_if,BD_ADDR bd_addr,bool is_direct,tBT_TRANSPORT transport,bool opportunistic)1282 bool GATT_Connect(tGATT_IF gatt_if, BD_ADDR bd_addr, bool is_direct,
1283 tBT_TRANSPORT transport, bool opportunistic) {
1284 uint8_t phy = controller_get_interface()->get_le_all_initiating_phys();
1285 return GATT_Connect(gatt_if, bd_addr, is_direct, transport, opportunistic,
1286 phy);
1287 }
1288
GATT_Connect(tGATT_IF gatt_if,BD_ADDR bd_addr,bool is_direct,tBT_TRANSPORT transport,bool opportunistic,uint8_t initiating_phys)1289 bool GATT_Connect(tGATT_IF gatt_if, BD_ADDR bd_addr, bool is_direct,
1290 tBT_TRANSPORT transport, bool opportunistic,
1291 uint8_t initiating_phys) {
1292 tGATT_REG* p_reg;
1293 bool status = false;
1294
1295 GATT_TRACE_API("GATT_Connect gatt_if=%d", gatt_if);
1296
1297 /* Make sure app is registered */
1298 p_reg = gatt_get_regcb(gatt_if);
1299 if (p_reg == NULL) {
1300 GATT_TRACE_ERROR("GATT_Connect - gatt_if =%d is not registered", gatt_if);
1301 return (false);
1302 }
1303
1304 if (is_direct)
1305 status = gatt_act_connect(p_reg, bd_addr, transport, opportunistic,
1306 initiating_phys);
1307 else {
1308 if (transport == BT_TRANSPORT_LE)
1309 status = gatt_update_auto_connect_dev(gatt_if, true, bd_addr);
1310 else {
1311 GATT_TRACE_ERROR("Unsupported transport for background connection");
1312 }
1313 }
1314
1315 return status;
1316 }
1317
1318 /*******************************************************************************
1319 *
1320 * Function GATT_CancelConnect
1321 *
1322 * Description This function terminate the connection initaition to a
1323 * remote device on GATT channel.
1324 *
1325 * Parameters gatt_if: client interface. If 0 used as unconditionally
1326 * disconnect, typically used for direct connection
1327 * cancellation.
1328 * bd_addr: peer device address.
1329 *
1330 * Returns true if the connection started; false otherwise.
1331 *
1332 ******************************************************************************/
GATT_CancelConnect(tGATT_IF gatt_if,BD_ADDR bd_addr,bool is_direct)1333 bool GATT_CancelConnect(tGATT_IF gatt_if, BD_ADDR bd_addr, bool is_direct) {
1334 tGATT_REG* p_reg;
1335 tGATT_TCB* p_tcb;
1336 bool status = true;
1337 tGATT_IF temp_gatt_if;
1338 uint8_t start_idx, found_idx;
1339
1340 GATT_TRACE_API("GATT_CancelConnect gatt_if=%d", gatt_if);
1341
1342 if (gatt_if != 0) {
1343 p_reg = gatt_get_regcb(gatt_if);
1344 if (p_reg == NULL) {
1345 GATT_TRACE_ERROR("GATT_CancelConnect - gatt_if =%d is not registered",
1346 gatt_if);
1347 return (false);
1348 }
1349 }
1350
1351 if (is_direct) {
1352 if (!gatt_if) {
1353 GATT_TRACE_DEBUG("GATT_CancelConnect - unconditional");
1354 start_idx = 0;
1355 /* only LE connection can be cancelled */
1356 p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
1357 if (p_tcb && gatt_num_apps_hold_link(p_tcb)) {
1358 while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx,
1359 &temp_gatt_if)) {
1360 status = gatt_cancel_open(temp_gatt_if, bd_addr);
1361 start_idx = ++found_idx;
1362 }
1363 } else {
1364 GATT_TRACE_ERROR("GATT_CancelConnect - no app found");
1365 status = false;
1366 }
1367 } else {
1368 status = gatt_cancel_open(gatt_if, bd_addr);
1369 }
1370 } else {
1371 if (!gatt_if) {
1372 if (gatt_get_num_apps_for_bg_dev(bd_addr)) {
1373 while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if))
1374 gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr);
1375 } else {
1376 GATT_TRACE_ERROR(
1377 "GATT_CancelConnect -no app associated with the bg device for "
1378 "unconditional removal");
1379 status = false;
1380 }
1381 } else {
1382 status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
1383 }
1384 }
1385
1386 return status;
1387 }
1388
1389 /*******************************************************************************
1390 *
1391 * Function GATT_Disconnect
1392 *
1393 * Description This function disconnects the GATT channel for this
1394 * registered application.
1395 *
1396 * Parameters conn_id: connection identifier.
1397 *
1398 * Returns GATT_SUCCESS if disconnected.
1399 *
1400 ******************************************************************************/
GATT_Disconnect(uint16_t conn_id)1401 tGATT_STATUS GATT_Disconnect(uint16_t conn_id) {
1402 tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER;
1403 tGATT_TCB* p_tcb = NULL;
1404 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
1405 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
1406
1407 GATT_TRACE_API("GATT_Disconnect conn_id=%d ", conn_id);
1408
1409 p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1410
1411 if (p_tcb) {
1412 gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true);
1413 ret = GATT_SUCCESS;
1414 }
1415 return ret;
1416 }
1417
1418 /*******************************************************************************
1419 *
1420 * Function GATT_GetConnectionInfor
1421 *
1422 * Description This function uses conn_id to find its associated BD address
1423 * and application interface
1424 *
1425 * Parameters conn_id: connection id (input)
1426 * p_gatt_if: applicaiton interface (output)
1427 * bd_addr: peer device address. (output)
1428 *
1429 * Returns true the ligical link information is found for conn_id
1430 *
1431 ******************************************************************************/
GATT_GetConnectionInfor(uint16_t conn_id,tGATT_IF * p_gatt_if,BD_ADDR bd_addr,tBT_TRANSPORT * p_transport)1432 bool GATT_GetConnectionInfor(uint16_t conn_id, tGATT_IF* p_gatt_if,
1433 BD_ADDR bd_addr, tBT_TRANSPORT* p_transport) {
1434 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
1435 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
1436 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
1437 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1438 bool status = false;
1439
1440 GATT_TRACE_API("GATT_GetConnectionInfor conn_id=%d", conn_id);
1441
1442 if (p_tcb && p_reg) {
1443 memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN);
1444 *p_gatt_if = gatt_if;
1445 *p_transport = p_tcb->transport;
1446 status = true;
1447 }
1448 return status;
1449 }
1450
1451 /*******************************************************************************
1452 *
1453 * Function GATT_GetConnIdIfConnected
1454 *
1455 * Description This function find the conn_id if the logical link for BD
1456 * address and applciation interface is connected
1457 *
1458 * Parameters gatt_if: applicaiton interface (input)
1459 * bd_addr: peer device address. (input)
1460 * p_conn_id: connection id (output)
1461 * transport: transport option
1462 *
1463 * Returns true the logical link is connected
1464 *
1465 ******************************************************************************/
GATT_GetConnIdIfConnected(tGATT_IF gatt_if,BD_ADDR bd_addr,uint16_t * p_conn_id,tBT_TRANSPORT transport)1466 bool GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr,
1467 uint16_t* p_conn_id, tBT_TRANSPORT transport) {
1468 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
1469 tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
1470 bool status = false;
1471
1472 if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN)) {
1473 *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1474 status = true;
1475 }
1476
1477 GATT_TRACE_API("GATT_GetConnIdIfConnected status=%d", status);
1478 return status;
1479 }
1480