1 /******************************************************************************
3 * Copyright 1999-2012 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /******************************************************************************
21 * this file contains GATT interface functions
23 ******************************************************************************/
24 #include "bt_target.h"
26 #include <base/strings/string_number_conversions.h>
29 #include "bt_common.h"
31 #include "device/include/controller.h"
35 #include "stack/gatt/connection_manager.h"
37 using bluetooth::Uuid;
39 extern bool BTM_BackgroundConnectAddressKnown(const RawAddress& address);
41 * Add an service handle range to the list in decending order of the start
42 * handle. Return reference to the newly added element.
44 tGATT_HDL_LIST_ELEM& gatt_add_an_item_to_list(uint16_t s_handle) {
45 auto lst_ptr = gatt_cb.hdl_list_info;
46 auto it = lst_ptr->begin();
47 for (; it != lst_ptr->end(); it++) {
48 if (s_handle > it->asgn_range.s_handle) break;
51 auto rit = lst_ptr->emplace(it);
55 /*****************************************************************************
59 *****************************************************************************/
60 /*******************************************************************************
62 * Function GATTS_AddHandleRange
64 * Description This function add the allocated handles range for the
65 * specified application UUID, service UUID and service
68 * Parameter p_hndl_range: pointer to allocated handles information
72 void GATTS_AddHandleRange(tGATTS_HNDL_RANGE* p_hndl_range) {
73 gatt_add_an_item_to_list(p_hndl_range->s_handle);
76 /*******************************************************************************
78 * Function GATTS_NVRegister
80 * Description Application manager calls this function to register for
81 * NV save callback function. There can be one and only one
82 * NV save callback function.
84 * Parameter p_cb_info : callback informaiton
86 * Returns true if registered OK, else false
88 ******************************************************************************/
89 bool GATTS_NVRegister(tGATT_APPL_INFO* p_cb_info) {
92 gatt_cb.cb_info = *p_cb_info;
100 static uint16_t compute_service_size(btgatt_db_element_t* service, int count) {
102 btgatt_db_element_t* el = service;
104 for (int i = 0; i < count; i++, el++)
105 if (el->type == BTGATT_DB_PRIMARY_SERVICE ||
106 el->type == BTGATT_DB_SECONDARY_SERVICE ||
107 el->type == BTGATT_DB_DESCRIPTOR ||
108 el->type == BTGATT_DB_INCLUDED_SERVICE)
110 else if (el->type == BTGATT_DB_CHARACTERISTIC)
113 LOG(ERROR) << __func__ << ": Unknown element type: " << el->type;
118 static bool is_gatt_attr_type(const Uuid& uuid) {
119 if (uuid == Uuid::From16Bit(GATT_UUID_PRI_SERVICE) ||
120 uuid == Uuid::From16Bit(GATT_UUID_SEC_SERVICE) ||
121 uuid == Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE) ||
122 uuid == Uuid::From16Bit(GATT_UUID_CHAR_DECLARE)) {
128 /** Update the the last service info for the service list info */
129 static void gatt_update_last_srv_info() {
130 gatt_cb.last_service_handle = 0;
132 for (tGATT_SRV_LIST_ELEM& el : *gatt_cb.srv_list_info) {
133 gatt_cb.last_service_handle = el.s_hdl;
137 /*******************************************************************************
139 * Function GATTS_AddService
141 * Description This function is called to add GATT service.
143 * Parameter gatt_if : application if
144 * service : pseudo-representation of service and it's content
145 * count : size of service
147 * Returns on success GATT_SERVICE_STARTED is returned, and
148 * attribute_handle field inside service elements are filled.
149 * on error error status is returned.
151 ******************************************************************************/
152 uint16_t GATTS_AddService(tGATT_IF gatt_if, btgatt_db_element_t* service,
155 bool save_hdl = false;
156 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
158 bool is_pri = (service->type == BTGATT_DB_PRIMARY_SERVICE) ? true : false;
159 Uuid svc_uuid = service->uuid;
161 LOG(INFO) << __func__;
164 LOG(ERROR) << "Inavlid gatt_if=" << +gatt_if;
165 return GATT_INTERNAL_ERROR;
168 uint16_t num_handles = compute_service_size(service, count);
170 if (svc_uuid == Uuid::From16Bit(UUID_SERVCLASS_GATT_SERVER)) {
171 s_hdl = gatt_cb.hdl_cfg.gatt_start_hdl;
172 } else if (svc_uuid == Uuid::From16Bit(UUID_SERVCLASS_GAP_SERVER)) {
173 s_hdl = gatt_cb.hdl_cfg.gap_start_hdl;
175 if (!gatt_cb.hdl_list_info->empty()) {
176 s_hdl = gatt_cb.hdl_list_info->front().asgn_range.e_handle + 1;
179 if (s_hdl < gatt_cb.hdl_cfg.app_start_hdl)
180 s_hdl = gatt_cb.hdl_cfg.app_start_hdl;
185 /* check for space */
186 if (num_handles > (0xFFFF - s_hdl + 1)) {
187 LOG(ERROR) << __func__ << ": no handles, s_hdl=" << +s_hdl
188 << " needed=" << num_handles;
189 return GATT_INTERNAL_ERROR;
192 tGATT_HDL_LIST_ELEM& list = gatt_add_an_item_to_list(s_hdl);
193 list.asgn_range.app_uuid128 = p_reg->app_uuid128;
194 list.asgn_range.svc_uuid = svc_uuid;
195 list.asgn_range.s_handle = s_hdl;
196 list.asgn_range.e_handle = s_hdl + num_handles - 1;
197 list.asgn_range.is_primary = is_pri;
200 if (gatt_cb.cb_info.p_nv_save_callback)
201 (*gatt_cb.cb_info.p_nv_save_callback)(true, &list.asgn_range);
204 gatts_init_service_db(list.svc_db, svc_uuid, is_pri, s_hdl, num_handles);
206 VLOG(1) << __func__ << ": handles needed=" << num_handles
207 << ", s_hdl=" << loghex(list.asgn_range.s_handle)
208 << ", e_hdl=" << loghex(list.asgn_range.e_handle)
209 << ", uuid=" << list.asgn_range.svc_uuid
210 << ", is_primary=" << +list.asgn_range.is_primary;
212 service->attribute_handle = s_hdl;
214 btgatt_db_element_t* el = service + 1;
215 for (int i = 0; i < count - 1; i++, el++) {
216 const Uuid& uuid = el->uuid;
218 if (el->type == BTGATT_DB_CHARACTERISTIC) {
219 /* data validity checking */
220 if (((el->properties & GATT_CHAR_PROP_BIT_AUTH) &&
221 !(el->permissions & GATT_WRITE_SIGNED_PERM)) ||
222 ((el->permissions & GATT_WRITE_SIGNED_PERM) &&
223 !(el->properties & GATT_CHAR_PROP_BIT_AUTH))) {
224 VLOG(1) << "Invalid configuration property=" << loghex(el->properties)
225 << ", perm=" << loghex(el->permissions);
226 return GATT_INTERNAL_ERROR;
229 if (is_gatt_attr_type(uuid)) {
230 LOG(ERROR) << __func__
231 << ": attept to add characteristic with UUID equal to GATT "
234 return GATT_INTERNAL_ERROR;
237 el->attribute_handle = gatts_add_characteristic(
238 list.svc_db, el->permissions, el->properties, uuid);
239 } else if (el->type == BTGATT_DB_DESCRIPTOR) {
240 if (is_gatt_attr_type(uuid)) {
241 LOG(ERROR) << __func__
242 << ": attept to add descriptor with UUID equal to GATT "
245 return GATT_INTERNAL_ERROR;
248 el->attribute_handle =
249 gatts_add_char_descr(list.svc_db, el->permissions, uuid);
250 } else if (el->type == BTGATT_DB_INCLUDED_SERVICE) {
251 tGATT_HDL_LIST_ELEM* p_incl_decl;
252 p_incl_decl = gatt_find_hdl_buffer_by_handle(el->attribute_handle);
253 if (p_incl_decl == nullptr) {
254 VLOG(1) << "Included Service not created";
255 return GATT_INTERNAL_ERROR;
258 el->attribute_handle = gatts_add_included_service(
259 list.svc_db, p_incl_decl->asgn_range.s_handle,
260 p_incl_decl->asgn_range.e_handle, p_incl_decl->asgn_range.svc_uuid);
264 LOG(INFO) << __func__ << ": service parsed correctly, now starting";
266 /*this is a new application service start */
268 // find a place for this service in the list
269 auto lst_ptr = gatt_cb.srv_list_info;
270 auto it = lst_ptr->begin();
271 for (; it != lst_ptr->end(); it++) {
272 if (list.asgn_range.s_handle < it->s_hdl) break;
274 auto rit = lst_ptr->emplace(it);
276 tGATT_SRV_LIST_ELEM& elem = *rit;
277 elem.gatt_if = gatt_if;
278 elem.s_hdl = list.asgn_range.s_handle;
279 elem.e_hdl = list.asgn_range.e_handle;
280 elem.p_db = &list.svc_db;
281 elem.is_primary = list.asgn_range.is_primary;
283 elem.app_uuid = list.asgn_range.app_uuid128;
284 elem.type = list.asgn_range.is_primary ? GATT_UUID_PRI_SERVICE
285 : GATT_UUID_SEC_SERVICE;
287 if (elem.type == GATT_UUID_PRI_SERVICE) {
288 Uuid* p_uuid = gatts_get_service_uuid(elem.p_db);
289 elem.sdp_handle = gatt_add_sdp_record(*p_uuid, elem.s_hdl, elem.e_hdl);
294 gatt_update_last_srv_info();
296 VLOG(1) << __func__ << ": allocated el s_hdl=" << loghex(elem.s_hdl)
297 << ", e_hdl=" << loghex(elem.e_hdl) << ", type=" << loghex(elem.type)
298 << ", sdp_hdl=" << loghex(elem.sdp_handle);
302 return GATT_SERVICE_STARTED;
305 bool is_active_service(const Uuid& app_uuid128, Uuid* p_svc_uuid,
306 uint16_t start_handle) {
307 for (auto& info : *gatt_cb.srv_list_info) {
308 Uuid* p_this_uuid = gatts_get_service_uuid(info.p_db);
310 if (p_this_uuid && app_uuid128 == info.app_uuid &&
311 *p_svc_uuid == *p_this_uuid && (start_handle == info.s_hdl)) {
312 LOG(ERROR) << "Active Service Found: " << *p_svc_uuid;
319 /*******************************************************************************
321 * Function GATTS_DeleteService
323 * Description This function is called to delete a service.
325 * Parameter gatt_if : application interface
326 * p_svc_uuid : service UUID
327 * start_handle : start handle of the service
329 * Returns true if the operation succeeded, false if the handle block
332 ******************************************************************************/
333 bool GATTS_DeleteService(tGATT_IF gatt_if, Uuid* p_svc_uuid,
337 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
339 LOG(ERROR) << "Applicaiton not foud";
344 gatt_find_hdl_buffer_by_app_id(p_reg->app_uuid128, p_svc_uuid, svc_inst);
345 if (it == gatt_cb.hdl_list_info->end()) {
346 LOG(ERROR) << "No Service found";
352 if (is_active_service(p_reg->app_uuid128, p_svc_uuid, svc_inst)) {
353 GATTS_StopService(it->asgn_range.s_handle);
356 VLOG(1) << "released handles s_hdl=" << loghex(it->asgn_range.s_handle)
357 << ", e_hdl=" << loghex(it->asgn_range.e_handle);
359 if ((it->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl) &&
360 gatt_cb.cb_info.p_nv_save_callback)
361 (*gatt_cb.cb_info.p_nv_save_callback)(false, &it->asgn_range);
363 gatt_cb.hdl_list_info->erase(it);
367 /*******************************************************************************
369 * Function GATTS_StopService
371 * Description This function is called to stop a service
373 * Parameter service_handle : this is the start handle of a service
377 ******************************************************************************/
378 void GATTS_StopService(uint16_t service_handle) {
379 LOG(INFO) << __func__ << ": " << loghex(service_handle);
381 auto it = gatt_sr_find_i_rcb_by_handle(service_handle);
382 if (it == gatt_cb.srv_list_info->end()) {
383 LOG(ERROR) << __func__ << ": service_handle=" << loghex(service_handle)
388 if (it->sdp_handle) {
389 SDP_DeleteRecord(it->sdp_handle);
392 gatt_cb.srv_list_info->erase(it);
393 gatt_update_last_srv_info();
395 /*******************************************************************************
397 * Function GATTs_HandleValueIndication
399 * Description This function sends a handle value indication to a client.
401 * Parameter conn_id: connection identifier.
402 * attr_handle: Attribute handle of this handle value
404 * val_len: Length of the indicated attribute value.
405 * p_val: Pointer to the indicated attribute value data.
407 * Returns GATT_SUCCESS if sucessfully sent or queued; otherwise error
410 ******************************************************************************/
411 tGATT_STATUS GATTS_HandleValueIndication(uint16_t conn_id, uint16_t attr_handle,
412 uint16_t val_len, uint8_t* p_val) {
413 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
414 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
415 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
416 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
419 if ((p_reg == NULL) || (p_tcb == NULL)) {
420 LOG(ERROR) << __func__ << ": Unknown conn_id=" << loghex(conn_id);
421 return (tGATT_STATUS)GATT_INVALID_CONN_ID;
424 if (!GATT_HANDLE_IS_VALID(attr_handle)) return GATT_ILLEGAL_PARAMETER;
426 tGATT_VALUE indication;
427 indication.conn_id = conn_id;
428 indication.handle = attr_handle;
429 indication.len = val_len;
430 memcpy(indication.value, p_val, val_len);
431 indication.auth_req = GATT_AUTH_REQ_NONE;
433 if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle)) {
434 VLOG(1) << "Add a pending indication";
435 gatt_add_pending_ind(p_tcb, &indication);
439 tGATT_SR_MSG gatt_sr_msg;
440 gatt_sr_msg.attr_value = indication;
442 attp_build_sr_msg(*p_tcb, GATT_HANDLE_VALUE_IND, &gatt_sr_msg);
443 if (!p_msg) return GATT_NO_RESOURCES;
445 tGATT_STATUS cmd_status = attp_send_sr_msg(*p_tcb, p_msg);
446 if (cmd_status == GATT_SUCCESS || cmd_status == GATT_CONGESTED) {
447 p_tcb->indicate_handle = indication.handle;
448 gatt_start_conf_timer(p_tcb);
453 /*******************************************************************************
455 * Function GATTS_HandleValueNotification
457 * Description This function sends a handle value notification to a client.
459 * Parameter conn_id: connection identifier.
460 * attr_handle: Attribute handle of this handle value
462 * val_len: Length of the indicated attribute value.
463 * p_val: Pointer to the indicated attribute value data.
465 * Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
467 ******************************************************************************/
468 tGATT_STATUS GATTS_HandleValueNotification(uint16_t conn_id,
469 uint16_t attr_handle,
470 uint16_t val_len, uint8_t* p_val) {
472 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
473 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
474 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
475 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
479 if ((p_reg == NULL) || (p_tcb == NULL)) {
480 LOG(ERROR) << __func__ << "Unknown conn_id: " << conn_id;
481 return (tGATT_STATUS)GATT_INVALID_CONN_ID;
484 if (!GATT_HANDLE_IS_VALID(attr_handle)) {
485 return GATT_ILLEGAL_PARAMETER;
488 notif.handle = attr_handle;
490 memcpy(notif.value, p_val, val_len);
491 notif.auth_req = GATT_AUTH_REQ_NONE;
493 tGATT_STATUS cmd_sent;
494 tGATT_SR_MSG gatt_sr_msg;
495 gatt_sr_msg.attr_value = notif;
497 attp_build_sr_msg(*p_tcb, GATT_HANDLE_VALUE_NOTIF, &gatt_sr_msg);
499 cmd_sent = attp_send_sr_msg(*p_tcb, p_buf);
501 cmd_sent = GATT_NO_RESOURCES;
505 /*******************************************************************************
507 * Function GATTS_SendRsp
509 * Description This function sends the server response to client.
511 * Parameter conn_id: connection identifier.
512 * trans_id: transaction id
513 * status: response status
514 * p_msg: pointer to message parameters structure.
516 * Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
518 ******************************************************************************/
519 tGATT_STATUS GATTS_SendRsp(uint16_t conn_id, uint32_t trans_id,
520 tGATT_STATUS status, tGATTS_RSP* p_msg) {
521 tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
522 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
523 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
524 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
525 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
527 VLOG(1) << __func__ << ": conn_id=" << loghex(conn_id)
528 << ", trans_id=" << loghex(trans_id) << ", status=" << loghex(status);
530 if ((p_reg == NULL) || (p_tcb == NULL)) {
531 LOG(ERROR) << "Unknown conn_id=" << loghex(conn_id);
532 return (tGATT_STATUS)GATT_INVALID_CONN_ID;
535 if (p_tcb->sr_cmd.trans_id != trans_id) {
536 LOG(ERROR) << "conn_id=" << loghex(conn_id)
537 << " waiting for op_code=" << loghex(p_tcb->sr_cmd.op_code);
538 return (GATT_WRONG_STATE);
540 /* Process App response */
541 cmd_sent = gatt_sr_process_app_rsp(*p_tcb, gatt_if, trans_id,
542 p_tcb->sr_cmd.op_code, status, p_msg);
547 /******************************************************************************/
548 /* GATT Profile Srvr Functions */
549 /******************************************************************************/
551 /******************************************************************************/
553 /* GATT CLIENT APIs */
555 /******************************************************************************/
557 /*******************************************************************************
559 * Function GATTC_ConfigureMTU
561 * Description This function is called to configure the ATT MTU size.
563 * Parameters conn_id: connection identifier.
564 * mtu - attribute MTU size..
566 * Returns GATT_SUCCESS if command started successfully.
568 ******************************************************************************/
569 tGATT_STATUS GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu) {
570 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
571 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
572 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
573 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
575 VLOG(1) << __func__ << ": conn_id=" << loghex(conn_id) << ", mtu=" << +mtu;
577 if ((p_tcb == NULL) || (p_reg == NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) ||
578 (mtu > GATT_MAX_MTU_SIZE)) {
579 return GATT_ILLEGAL_PARAMETER;
582 /* Validate that the link is BLE, not BR/EDR */
583 if (p_tcb->transport != BT_TRANSPORT_LE) {
587 if (gatt_is_clcb_allocated(conn_id)) {
588 LOG(ERROR) << "GATT_BUSY conn_id = " << +conn_id;
592 tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id);
593 if (!p_clcb) return GATT_NO_RESOURCES;
595 p_clcb->p_tcb->payload_size = mtu;
596 p_clcb->operation = GATTC_OPTYPE_CONFIG;
597 tGATT_CL_MSG gatt_cl_msg;
598 gatt_cl_msg.mtu = mtu;
599 return attp_send_cl_msg(*p_clcb->p_tcb, p_clcb, GATT_REQ_MTU, &gatt_cl_msg);
602 /*******************************************************************************
604 * Function GATTC_Discover
606 * Description This function is called to do a discovery procedure on ATT
609 * Parameters conn_id: connection identifier.
610 * disc_type:discovery type.
611 * start_handle and end_handle: range of handles for discovery
612 * uuid: uuid to discovery. set to Uuid::kEmpty for requests
615 * Returns GATT_SUCCESS if command received/sent successfully.
617 ******************************************************************************/
618 tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
619 uint16_t start_handle, uint16_t end_handle,
621 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
622 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
623 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
624 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
626 if ((p_tcb == NULL) || (p_reg == NULL) || (disc_type >= GATT_DISC_MAX)) {
627 LOG(ERROR) << __func__ << " Illegal param: disc_type=" << +disc_type
628 << " conn_id=" << loghex(conn_id);
629 return GATT_ILLEGAL_PARAMETER;
632 LOG(INFO) << __func__ << " conn_id=" << loghex(conn_id)
633 << ", disc_type=" << +disc_type
634 << ", s_handle=" << loghex(start_handle)
635 << ", e_handle=" << loghex(end_handle);
637 if (!GATT_HANDLE_IS_VALID(start_handle) ||
638 !GATT_HANDLE_IS_VALID(end_handle) ||
639 /* search by type does not have a valid UUID param */
640 (disc_type == GATT_DISC_SRVC_BY_UUID && uuid.IsEmpty())) {
641 return GATT_ILLEGAL_PARAMETER;
644 if (gatt_is_clcb_allocated(conn_id)) {
645 LOG(ERROR) << __func__ << "GATT_BUSY conn_id = " << +conn_id;
649 tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id);
650 if (!p_clcb) return GATT_NO_RESOURCES;
652 p_clcb->operation = GATTC_OPTYPE_DISCOVERY;
653 p_clcb->op_subtype = disc_type;
654 p_clcb->s_handle = start_handle;
655 p_clcb->e_handle = end_handle;
658 gatt_act_discovery(p_clcb);
662 tGATT_STATUS GATTC_Discover(uint16_t conn_id, tGATT_DISC_TYPE disc_type,
663 uint16_t start_handle, uint16_t end_handle) {
664 return GATTC_Discover(conn_id, disc_type, start_handle, end_handle,
668 /*******************************************************************************
670 * Function GATTC_Read
672 * Description This function is called to read the value of an attribute
675 * Parameters conn_id: connection identifier.
676 * type - attribute read type.
677 * p_read - read operation parameters.
679 * Returns GATT_SUCCESS if command started successfully.
681 ******************************************************************************/
682 tGATT_STATUS GATTC_Read(uint16_t conn_id, tGATT_READ_TYPE type,
683 tGATT_READ_PARAM* p_read) {
684 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
685 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
686 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
687 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
689 VLOG(1) << __func__ << ": conn_id=" << loghex(conn_id)
690 << ", type=" << loghex(type);
692 if ((p_tcb == NULL) || (p_reg == NULL) || (p_read == NULL) ||
693 ((type >= GATT_READ_MAX) || (type == 0))) {
694 LOG(ERROR) << ": illegal param: conn_id=" << loghex(conn_id)
695 << "type=" << loghex(type);
696 return GATT_ILLEGAL_PARAMETER;
699 if (gatt_is_clcb_allocated(conn_id)) {
700 LOG(ERROR) << "GATT_BUSY conn_id=" << loghex(conn_id);
704 tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id);
705 if (!p_clcb) return GATT_NO_RESOURCES;
707 p_clcb->operation = GATTC_OPTYPE_READ;
708 p_clcb->op_subtype = type;
709 p_clcb->auth_req = p_read->by_handle.auth_req;
713 case GATT_READ_BY_TYPE:
714 case GATT_READ_CHAR_VALUE:
715 p_clcb->s_handle = p_read->service.s_handle;
716 p_clcb->e_handle = p_read->service.e_handle;
717 p_clcb->uuid = p_read->service.uuid;
719 case GATT_READ_MULTIPLE: {
720 p_clcb->s_handle = 0;
721 /* copy multiple handles in CB */
722 tGATT_READ_MULTI* p_read_multi =
723 (tGATT_READ_MULTI*)osi_malloc(sizeof(tGATT_READ_MULTI));
724 p_clcb->p_attr_buf = (uint8_t*)p_read_multi;
725 memcpy(p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI));
728 case GATT_READ_BY_HANDLE:
729 case GATT_READ_PARTIAL:
730 p_clcb->uuid = Uuid::kEmpty;
731 p_clcb->s_handle = p_read->by_handle.handle;
733 if (type == GATT_READ_PARTIAL) {
734 p_clcb->counter = p_read->partial.offset;
742 /* start security check */
743 if (gatt_security_check_start(p_clcb)) p_tcb->pending_enc_clcb.push(p_clcb);
747 /*******************************************************************************
749 * Function GATTC_Write
751 * Description This function is called to write the value of an attribute
754 * Parameters conn_id: connection identifier.
755 * type - attribute write type.
756 * p_write - write operation parameters.
758 * Returns GATT_SUCCESS if command started successfully.
760 ******************************************************************************/
761 tGATT_STATUS GATTC_Write(uint16_t conn_id, tGATT_WRITE_TYPE type,
762 tGATT_VALUE* p_write) {
763 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
764 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
765 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
766 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
768 if ((p_tcb == NULL) || (p_reg == NULL) || (p_write == NULL) ||
769 ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) &&
770 (type != GATT_WRITE_NO_RSP))) {
771 LOG(ERROR) << __func__ << " Illegal param: conn_id=" << loghex(conn_id)
772 << ", type=" << loghex(type);
773 return GATT_ILLEGAL_PARAMETER;
776 if (gatt_is_clcb_allocated(conn_id)) {
777 LOG(ERROR) << "GATT_BUSY conn_id=" << loghex(conn_id);
781 tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id);
782 if (!p_clcb) return GATT_NO_RESOURCES;
784 p_clcb->operation = GATTC_OPTYPE_WRITE;
785 p_clcb->op_subtype = type;
786 p_clcb->auth_req = p_write->auth_req;
788 p_clcb->p_attr_buf = (uint8_t*)osi_malloc(sizeof(tGATT_VALUE));
789 memcpy(p_clcb->p_attr_buf, (void*)p_write, sizeof(tGATT_VALUE));
791 tGATT_VALUE* p = (tGATT_VALUE*)p_clcb->p_attr_buf;
792 if (type == GATT_WRITE_PREPARE) {
793 p_clcb->start_offset = p_write->offset;
797 if (gatt_security_check_start(p_clcb)) p_tcb->pending_enc_clcb.push(p_clcb);
801 /*******************************************************************************
803 * Function GATTC_ExecuteWrite
805 * Description This function is called to send an Execute write request to
808 * Parameters conn_id: connection identifier.
809 * is_execute - to execute or cancel the prepared write
812 * Returns GATT_SUCCESS if command started successfully.
814 ******************************************************************************/
815 tGATT_STATUS GATTC_ExecuteWrite(uint16_t conn_id, bool is_execute) {
816 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
817 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
818 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
819 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
821 VLOG(1) << __func__ << ": conn_id=" << loghex(conn_id)
822 << ", is_execute=" << +is_execute;
824 if ((p_tcb == NULL) || (p_reg == NULL)) {
825 LOG(ERROR) << " Illegal param: conn_id=" << loghex(conn_id);
826 return GATT_ILLEGAL_PARAMETER;
829 if (gatt_is_clcb_allocated(conn_id)) {
830 LOG(ERROR) << " GATT_BUSY conn_id=" << loghex(conn_id);
834 tGATT_CLCB* p_clcb = gatt_clcb_alloc(conn_id);
835 if (!p_clcb) return GATT_NO_RESOURCES;
837 p_clcb->operation = GATTC_OPTYPE_EXE_WRITE;
838 tGATT_EXEC_FLAG flag =
839 is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL;
840 gatt_send_queue_write_cancel(*p_clcb->p_tcb, p_clcb, flag);
844 /*******************************************************************************
846 * Function GATTC_SendHandleValueConfirm
848 * Description This function is called to send a handle value confirmation
849 * as response to a handle value notification from server.
851 * Parameters conn_id: connection identifier.
852 * handle: the handle of the attribute confirmation.
854 * Returns GATT_SUCCESS if command started successfully.
856 ******************************************************************************/
857 tGATT_STATUS GATTC_SendHandleValueConfirm(uint16_t conn_id, uint16_t handle) {
858 VLOG(1) << __func__ << " conn_id=" << loghex(conn_id)
859 << ", handle=" << loghex(handle);
861 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id));
863 LOG(ERROR) << "Unknown conn_id=" << loghex(conn_id);
864 return GATT_ILLEGAL_PARAMETER;
867 if (p_tcb->ind_count == 0) {
868 VLOG(1) << " conn_id: " << loghex(conn_id)
869 << " ignored not waiting for indicaiton ack";
873 alarm_cancel(p_tcb->ind_ack_timer);
875 VLOG(1) << "notif_count= " << p_tcb->ind_count;
876 /* send confirmation now */
877 tGATT_CL_MSG gatt_cl_msg;
878 gatt_cl_msg.handle = handle;
880 attp_send_cl_msg(*p_tcb, nullptr, GATT_HANDLE_VALUE_CONF, &gatt_cl_msg);
882 p_tcb->ind_count = 0;
887 /******************************************************************************/
891 /******************************************************************************/
892 /*******************************************************************************
894 * Function GATT_SetIdleTimeout
896 * Description This function (common to both client and server) sets the
897 * idle timeout for a tansport connection
899 * Parameter bd_addr: target device bd address.
900 * idle_tout: timeout value in seconds.
904 ******************************************************************************/
905 void GATT_SetIdleTimeout(const RawAddress& bd_addr, uint16_t idle_tout,
906 tBT_TRANSPORT transport) {
909 tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
911 if (p_tcb->att_lcid == L2CAP_ATT_CID) {
912 status = L2CA_SetFixedChannelTout(bd_addr, L2CAP_ATT_CID, idle_tout);
914 if (idle_tout == GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP)
915 L2CA_SetIdleTimeoutByBdAddr(p_tcb->peer_bda,
916 GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP,
919 status = L2CA_SetIdleTimeout(p_tcb->att_lcid, idle_tout, false);
923 VLOG(1) << __func__ << " idle_tout=" << idle_tout << ", status=" << +status
924 << " (1-OK 0-not performed)";
927 /*******************************************************************************
929 * Function GATT_Register
931 * Description This function is called to register an application
934 * Parameter p_app_uuid128: Application UUID
935 * p_cb_info: callback functions.
937 * Returns 0 for error, otherwise the index of the client registered
940 ******************************************************************************/
941 tGATT_IF GATT_Register(const Uuid& app_uuid128, tGATT_CBACK* p_cb_info) {
943 uint8_t i_gatt_if = 0;
944 tGATT_IF gatt_if = 0;
946 LOG(INFO) << __func__ << " " << app_uuid128;
948 for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS;
949 i_gatt_if++, p_reg++) {
950 if (p_reg->in_use && p_reg->app_uuid128 == app_uuid128) {
951 LOG(ERROR) << "application already registered.";
956 for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS;
957 i_gatt_if++, p_reg++) {
958 if (!p_reg->in_use) {
959 memset(p_reg, 0, sizeof(tGATT_REG));
960 i_gatt_if++; /* one based number */
961 p_reg->app_uuid128 = app_uuid128;
962 gatt_if = p_reg->gatt_if = (tGATT_IF)i_gatt_if;
963 p_reg->app_cb = *p_cb_info;
964 p_reg->in_use = true;
966 LOG(INFO) << "allocated gatt_if=" << +gatt_if;
971 LOG(ERROR) << "can't Register GATT client, MAX client reached: "
976 /*******************************************************************************
978 * Function GATT_Deregister
980 * Description This function deregistered the application from GATT.
982 * Parameters gatt_if: applicaiton interface.
986 ******************************************************************************/
987 void GATT_Deregister(tGATT_IF gatt_if) {
988 VLOG(1) << __func__ << " gatt_if=" << +gatt_if;
990 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
991 /* Index 0 is GAP and is never deregistered */
992 if ((gatt_if == 0) || (p_reg == NULL)) {
993 LOG(ERROR) << "invalid gatt_if=" << +gatt_if;
997 /* stop all services */
998 /* todo an applcaiton can not be deregistered if its services is also used by
1000 deregisteration need to bed performed in an orderly fashion
1002 for (auto it = gatt_cb.srv_list_info->begin();
1003 it != gatt_cb.srv_list_info->end();) {
1004 if (it->gatt_if == gatt_if) {
1005 GATTS_StopService(it++->s_hdl);
1011 /* free all services db buffers if owned by this application */
1012 gatt_free_srvc_db_buffer_app_id(p_reg->app_uuid128);
1014 /* When an application deregisters, check remove the link associated with the
1018 for (i = 0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++) {
1019 if (!p_tcb->in_use) continue;
1021 if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE) {
1022 gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true);
1026 for (j = 0, p_clcb = &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++) {
1027 if (p_clcb->in_use && (p_clcb->p_reg->gatt_if == gatt_if) &&
1028 (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx)) {
1029 alarm_cancel(p_clcb->gatt_rsp_timer_ent);
1030 gatt_clcb_dealloc(p_clcb);
1036 connection_manager::on_app_deregistered(gatt_if);
1038 memset(p_reg, 0, sizeof(tGATT_REG));
1041 /*******************************************************************************
1043 * Function GATT_StartIf
1045 * Description This function is called after registration to start
1046 * receiving callbacks for registered interface. Function may
1047 * call back with connection status and queued notifications
1049 * Parameter gatt_if: applicaiton interface.
1053 ******************************************************************************/
1054 void GATT_StartIf(tGATT_IF gatt_if) {
1058 uint8_t start_idx, found_idx;
1060 tGATT_TRANSPORT transport;
1062 VLOG(1) << __func__ << " gatt_if=" << +gatt_if;
1063 p_reg = gatt_get_regcb(gatt_if);
1064 if (p_reg != NULL) {
1067 gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport)) {
1068 p_tcb = gatt_find_tcb_by_addr(bda, transport);
1069 if (p_reg->app_cb.p_conn_cb && p_tcb) {
1070 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1071 (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, true, 0, transport);
1073 start_idx = ++found_idx;
1078 /*******************************************************************************
1080 * Function GATT_Connect
1082 * Description This function initiate a connecttion to a remote device on
1085 * Parameters gatt_if: applicaiton interface
1086 * bd_addr: peer device address.
1087 * is_direct: is a direct conenection or a background auto
1090 * Returns true if connection started; false if connection start
1093 ******************************************************************************/
1094 bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_direct,
1095 tBT_TRANSPORT transport, bool opportunistic) {
1096 uint8_t phy = controller_get_interface()->get_le_all_initiating_phys();
1097 return GATT_Connect(gatt_if, bd_addr, is_direct, transport, opportunistic,
1101 bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_direct,
1102 tBT_TRANSPORT transport, bool opportunistic,
1103 uint8_t initiating_phys) {
1104 LOG(INFO) << __func__ << "gatt_if=" << +gatt_if << ", address=" << bd_addr;
1106 /* Make sure app is registered */
1107 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
1109 LOG(ERROR) << "gatt_if = " << +gatt_if << " is not registered";
1113 if (!is_direct && transport != BT_TRANSPORT_LE) {
1114 LOG(ERROR) << "Unsupported transport for background connection";
1118 if (opportunistic) {
1119 LOG(INFO) << __func__ << " opportunistic connection";
1125 ret = gatt_act_connect(p_reg, bd_addr, transport, initiating_phys);
1127 if (!BTM_BackgroundConnectAddressKnown(bd_addr)) {
1128 // RPA can rotate, causing address to "expire" in the background
1129 // connection list. RPA is allowed for direct connect, as such request
1130 // times out after 30 seconds
1131 LOG(INFO) << "Can't add RPA to background connection.";
1134 ret = connection_manager::background_connect_add(gatt_if, bd_addr);
1138 tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
1139 // background connections don't necessarily create tcb
1141 gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, true, !is_direct);
1146 /*******************************************************************************
1148 * Function GATT_CancelConnect
1150 * Description This function terminate the connection initaition to a
1151 * remote device on GATT channel.
1153 * Parameters gatt_if: client interface. If 0 used as unconditionally
1154 * disconnect, typically used for direct connection
1156 * bd_addr: peer device address.
1158 * Returns true if the connection started; false otherwise.
1160 ******************************************************************************/
1161 bool GATT_CancelConnect(tGATT_IF gatt_if, const RawAddress& bd_addr,
1163 LOG(INFO) << __func__ << ": gatt_if:" << +gatt_if << ", address: " << bd_addr
1164 << ", direct:" << is_direct;
1168 p_reg = gatt_get_regcb(gatt_if);
1170 LOG(ERROR) << "gatt_if=" << +gatt_if << " is not registered";
1175 return gatt_cancel_open(gatt_if, bd_addr);
1177 return gatt_auto_connect_dev_remove(p_reg->gatt_if, bd_addr);
1180 VLOG(1) << " unconditional";
1182 /* only LE connection can be cancelled */
1183 tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
1184 if (p_tcb && !p_tcb->app_hold_link.empty()) {
1185 for (auto it = p_tcb->app_hold_link.begin();
1186 it != p_tcb->app_hold_link.end();) {
1187 auto next = std::next(it);
1188 // gatt_cancel_open modifies the app_hold_link.
1189 gatt_cancel_open(*it, bd_addr);
1195 if (!connection_manager::remove_unconditional(bd_addr)) {
1198 << ": no app associated with the bg device for unconditional removal";
1205 /*******************************************************************************
1207 * Function GATT_Disconnect
1209 * Description This function disconnects the GATT channel for this
1210 * registered application.
1212 * Parameters conn_id: connection identifier.
1214 * Returns GATT_SUCCESS if disconnected.
1216 ******************************************************************************/
1217 tGATT_STATUS GATT_Disconnect(uint16_t conn_id) {
1218 LOG(INFO) << __func__ << " conn_id=" << loghex(conn_id);
1220 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
1221 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1222 if (!p_tcb) return GATT_ILLEGAL_PARAMETER;
1224 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
1225 gatt_update_app_use_link_flag(gatt_if, p_tcb, false, true);
1226 return GATT_SUCCESS;
1229 /*******************************************************************************
1231 * Function GATT_GetConnectionInfor
1233 * Description This function uses conn_id to find its associated BD address
1234 * and application interface
1236 * Parameters conn_id: connection id (input)
1237 * p_gatt_if: applicaiton interface (output)
1238 * bd_addr: peer device address. (output)
1240 * Returns true the ligical link information is found for conn_id
1242 ******************************************************************************/
1243 bool GATT_GetConnectionInfor(uint16_t conn_id, tGATT_IF* p_gatt_if,
1244 RawAddress& bd_addr, tBT_TRANSPORT* p_transport) {
1245 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
1246 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
1247 uint8_t tcb_idx = GATT_GET_TCB_IDX(conn_id);
1248 tGATT_TCB* p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1250 VLOG(1) << __func__ << " conn_id=" << loghex(conn_id);
1252 if (!p_tcb || !p_reg) return false;
1254 bd_addr = p_tcb->peer_bda;
1255 *p_gatt_if = gatt_if;
1256 *p_transport = p_tcb->transport;
1260 /*******************************************************************************
1262 * Function GATT_GetConnIdIfConnected
1264 * Description This function find the conn_id if the logical link for BD
1265 * address and applciation interface is connected
1267 * Parameters gatt_if: applicaiton interface (input)
1268 * bd_addr: peer device address. (input)
1269 * p_conn_id: connection id (output)
1270 * transport: transport option
1272 * Returns true the logical link is connected
1274 ******************************************************************************/
1275 bool GATT_GetConnIdIfConnected(tGATT_IF gatt_if, const RawAddress& bd_addr,
1276 uint16_t* p_conn_id, tBT_TRANSPORT transport) {
1277 tGATT_REG* p_reg = gatt_get_regcb(gatt_if);
1278 tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
1279 bool status = false;
1281 if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN)) {
1282 *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1286 VLOG(1) << __func__ << " status= " << +status;