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 ******************************************************************************/
57uint8_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 **/
67tGATT_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
95void 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 ******************************************************************************/
112bool 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
123static uint8_t BASE_UUID[16] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
124                                0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
125
126static 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
137static 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
163void 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
170static 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
188static 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 */
199static 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 ******************************************************************************/
221uint16_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
381bool 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 ******************************************************************************/
412bool 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 ******************************************************************************/
457void 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 ******************************************************************************/
489tGATT_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 ******************************************************************************/
554tGATT_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*)&notif);
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 ******************************************************************************/
604tGATT_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 ******************************************************************************/
655tGATT_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
693void 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
711void 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
738void doNothing(uint8_t* data, uint16_t len) {}
739
740void 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 ******************************************************************************/
786tGATT_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 ******************************************************************************/
846tGATT_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 ******************************************************************************/
930tGATT_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 ******************************************************************************/
993tGATT_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 ******************************************************************************/
1040tGATT_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 ******************************************************************************/
1090void 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 ******************************************************************************/
1128tGATT_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 ******************************************************************************/
1177void 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 ******************************************************************************/
1242void 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 ******************************************************************************/
1282bool 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
1289bool 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 ******************************************************************************/
1333bool 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 ******************************************************************************/
1401tGATT_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 ******************************************************************************/
1432bool 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 ******************************************************************************/
1466bool 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