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