Home | History | Annotate | Download | only in gap
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2009-2013 Broadcom Corporation
      4  *
      5  *  Licensed under the Apache License, Version 2.0 (the "License");
      6  *  you may not use this file except in compliance with the License.
      7  *  You may obtain a copy of the License at:
      8  *
      9  *  http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  ******************************************************************************/
     18 #include "bt_target.h"
     19 
     20 #if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
     21 
     22 #include "bt_utils.h"
     23 #include <string.h>
     24 #include "gap_int.h"
     25 #include "gap_api.h"
     26 #include "gattdefs.h"
     27 #include "gatt_api.h"
     28 #include "gatt_int.h"
     29 #include "btm_int.h"
     30 #include "hcimsgs.h"
     31 
     32 #define GAP_CHAR_ICON_SIZE          2
     33 #define GAP_CHAR_DEV_NAME_SIZE      248
     34 #define GAP_MAX_NUM_INC_SVR       0
     35 #define GAP_MAX_ATTR_NUM          (2 * GAP_MAX_CHAR_NUM + GAP_MAX_NUM_INC_SVR + 1)
     36 #define GAP_MAX_CHAR_VALUE_SIZE   (30 + GAP_CHAR_DEV_NAME_SIZE)
     37 
     38 
     39 #ifndef GAP_ATTR_DB_SIZE
     40 #define GAP_ATTR_DB_SIZE      GATT_DB_MEM_SIZE(GAP_MAX_NUM_INC_SVR, GAP_MAX_CHAR_NUM, GAP_MAX_CHAR_VALUE_SIZE)
     41 #endif
     42 
     43 static void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE op_code, tGATTS_DATA *p_data);
     44 
     45 /* client connection callback */
     46 static void  gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected,
     47                                             tGATT_DISCONN_REASON reason, tGATT_TRANSPORT transport);
     48 static void  gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
     49 
     50 static tGATT_CBACK gap_cback =
     51 {
     52     gap_ble_c_connect_cback,
     53     gap_ble_c_cmpl_cback,
     54     NULL,
     55     NULL,
     56     gap_ble_s_attr_request_cback,
     57     NULL,
     58     NULL
     59 };
     60 
     61 
     62 
     63 /*******************************************************************************
     64 **
     65 ** Function         gap_find_clcb_by_bd_addr
     66 **
     67 ** Description      The function searches all LCB with macthing bd address
     68 **
     69 ** Returns          total number of clcb found.
     70 **
     71 *******************************************************************************/
     72 tGAP_CLCB *gap_find_clcb_by_bd_addr(BD_ADDR bda)
     73 {
     74     UINT8 i_clcb;
     75     tGAP_CLCB    *p_clcb = NULL;
     76 
     77     for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++)
     78     {
     79         if (p_clcb->in_use && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
     80         {
     81             return p_clcb;
     82         }
     83     }
     84 
     85     return NULL;
     86 }
     87 
     88 /*******************************************************************************
     89 **
     90 ** Function         gap_ble_find_clcb_by_conn_id
     91 **
     92 ** Description      The function searches all LCB with macthing connection ID
     93 **
     94 ** Returns          total number of clcb found.
     95 **
     96 *******************************************************************************/
     97 tGAP_CLCB *gap_ble_find_clcb_by_conn_id(UINT16 conn_id)
     98 {
     99     UINT8 i_clcb;
    100     tGAP_CLCB    *p_clcb = NULL;
    101 
    102     for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++)
    103     {
    104         if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id)
    105         {
    106             return p_clcb;
    107         }
    108     }
    109 
    110     return p_clcb;
    111 }
    112 
    113 /*******************************************************************************
    114 **
    115 ** Function         gap_clcb_alloc
    116 **
    117 ** Description      The function allocates a GAP  connection link control block
    118 **
    119 ** Returns           NULL if not found. Otherwise pointer to the connection link block.
    120 **
    121 *******************************************************************************/
    122 tGAP_CLCB *gap_clcb_alloc (BD_ADDR bda)
    123 {
    124     UINT8         i_clcb = 0;
    125     tGAP_CLCB    *p_clcb = NULL;
    126 
    127     for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++)
    128     {
    129         if (!p_clcb->in_use)
    130         {
    131             fixed_queue_free(p_clcb->pending_req_q, NULL);
    132             memset(p_clcb, 0, sizeof(tGAP_CLCB));
    133             p_clcb->in_use = TRUE;
    134             memcpy (p_clcb->bda, bda, BD_ADDR_LEN);
    135             p_clcb->pending_req_q = fixed_queue_new(SIZE_MAX);
    136             break;
    137         }
    138     }
    139     return p_clcb;
    140 }
    141 
    142 /*******************************************************************************
    143 **
    144 ** Function         gap_ble_dealloc_clcb
    145 **
    146 ** Description      The function clean up the pending request queue in GAP
    147 **
    148 ** Returns          none
    149 **
    150 *******************************************************************************/
    151 void gap_ble_dealloc_clcb(tGAP_CLCB *p_clcb)
    152 {
    153     tGAP_BLE_REQ    *p_q;
    154 
    155     while ((p_q = (tGAP_BLE_REQ *)fixed_queue_try_dequeue(p_clcb->pending_req_q)) != NULL)
    156     {
    157          /* send callback to all pending requests if being removed*/
    158          if (p_q->p_cback != NULL)
    159             (*p_q->p_cback)(FALSE, p_clcb->bda, 0, NULL);
    160 
    161          osi_free(p_q);
    162     }
    163     fixed_queue_free(p_clcb->pending_req_q, NULL);
    164 
    165     memset(p_clcb, 0, sizeof(tGAP_CLCB));
    166 }
    167 
    168 /*******************************************************************************
    169 **
    170 ** Function         gap_ble_enqueue_request
    171 **
    172 ** Description      The function enqueue a GAP client request
    173 **
    174 ** Returns           TRUE is successul; FALSE otherwise
    175 **
    176 *******************************************************************************/
    177 BOOLEAN gap_ble_enqueue_request (tGAP_CLCB *p_clcb, UINT16 uuid, tGAP_BLE_CMPL_CBACK *p_cback)
    178 {
    179     tGAP_BLE_REQ *p_q = (tGAP_BLE_REQ *)osi_malloc(sizeof(tGAP_BLE_REQ));
    180 
    181     p_q->p_cback = p_cback;
    182     p_q->uuid = uuid;
    183     fixed_queue_enqueue(p_clcb->pending_req_q, p_q);
    184 
    185     return TRUE;
    186 }
    187 
    188 /*******************************************************************************
    189 **
    190 ** Function         gap_ble_dequeue_request
    191 **
    192 ** Description      The function dequeue a GAP client request if any
    193 **
    194 ** Returns           TRUE is successul; FALSE otherwise
    195 **
    196 *******************************************************************************/
    197 BOOLEAN gap_ble_dequeue_request (tGAP_CLCB *p_clcb, UINT16 * p_uuid, tGAP_BLE_CMPL_CBACK **p_cback)
    198 {
    199     tGAP_BLE_REQ *p_q = (tGAP_BLE_REQ *)fixed_queue_try_dequeue(p_clcb->pending_req_q);;
    200 
    201     if (p_q != NULL)
    202     {
    203         *p_cback    = p_q->p_cback;
    204         *p_uuid     = p_q->uuid;
    205         osi_free(p_q);
    206         return TRUE;
    207     }
    208 
    209     return FALSE;
    210 }
    211 
    212 /*******************************************************************************
    213 **   GAP Attributes Database Request callback
    214 *******************************************************************************/
    215 tGATT_STATUS gap_read_attr_value (UINT16 handle, tGATT_VALUE *p_value, BOOLEAN is_long)
    216 {
    217     tGAP_ATTR   *p_db_attr = gap_cb.gatt_attr;
    218     UINT8       *p = p_value->value, i;
    219     UINT16      offset = p_value->offset;
    220     UINT8       *p_dev_name = NULL;
    221 
    222     for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++)
    223     {
    224         if (handle == p_db_attr->handle)
    225         {
    226             if (p_db_attr->uuid != GATT_UUID_GAP_DEVICE_NAME &&
    227                 is_long == TRUE)
    228                 return GATT_NOT_LONG;
    229 
    230             switch (p_db_attr->uuid)
    231             {
    232                 case GATT_UUID_GAP_DEVICE_NAME:
    233                     BTM_ReadLocalDeviceName((char **)&p_dev_name);
    234                     if (strlen ((char *)p_dev_name) > GATT_MAX_ATTR_LEN)
    235                         p_value->len = GATT_MAX_ATTR_LEN;
    236                     else
    237                         p_value->len = (UINT16)strlen ((char *)p_dev_name);
    238 
    239                     if (offset > p_value->len)
    240                         return GATT_INVALID_OFFSET;
    241                     else
    242                     {
    243                         p_value->len -= offset;
    244                         p_dev_name += offset;
    245                         ARRAY_TO_STREAM(p, p_dev_name, p_value->len);
    246                         GAP_TRACE_EVENT("GATT_UUID_GAP_DEVICE_NAME len=0x%04x", p_value->len);
    247                     }
    248                     break;
    249 
    250                 case GATT_UUID_GAP_ICON:
    251                     UINT16_TO_STREAM(p, p_db_attr->attr_value.icon);
    252                     p_value->len = 2;
    253                     break;
    254 
    255                 case GATT_UUID_GAP_PREF_CONN_PARAM:
    256                     UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_min); /* int_min */
    257                     UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_max); /* int_max */
    258                     UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.latency); /* latency */
    259                     UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.sp_tout);  /* sp_tout */
    260                     p_value->len =8;
    261                     break;
    262 
    263                 /* address resolution */
    264                 case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
    265                     UINT8_TO_STREAM(p, p_db_attr->attr_value.addr_resolution);
    266                     p_value->len =1;
    267                     break;
    268             }
    269             return GATT_SUCCESS;
    270         }
    271     }
    272     return GATT_NOT_FOUND;
    273 }
    274 
    275 /*******************************************************************************
    276 **   GAP Attributes Database Read/Read Blob Request process
    277 *******************************************************************************/
    278 tGATT_STATUS gap_proc_read (tGATTS_REQ_TYPE type, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp)
    279 {
    280     tGATT_STATUS    status = GATT_NO_RESOURCES;
    281     UNUSED(type);
    282 
    283     if (p_data->is_long)
    284         p_rsp->attr_value.offset = p_data->offset;
    285 
    286     p_rsp->attr_value.handle = p_data->handle;
    287 
    288     status = gap_read_attr_value(p_data->handle, &p_rsp->attr_value, p_data->is_long);
    289 
    290     return status;
    291 }
    292 
    293 /******************************************************************************
    294 **
    295 ** Function         gap_proc_write_req
    296 **
    297 ** Description      GAP ATT server process a write request.
    298 **
    299 ** Returns          void.
    300 **
    301 *******************************************************************************/
    302 UINT8 gap_proc_write_req( tGATTS_REQ_TYPE type, tGATT_WRITE_REQ *p_data)
    303 {
    304     tGAP_ATTR   *p_db_attr = gap_cb.gatt_attr;
    305     UINT8   i;
    306     UNUSED(type);
    307 
    308     for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++)
    309     {
    310         if (p_data-> handle == p_db_attr->handle)
    311         {
    312                 return GATT_WRITE_NOT_PERMIT;
    313         }
    314     }
    315     return GATT_NOT_FOUND;
    316 
    317 }
    318 
    319 /******************************************************************************
    320 **
    321 ** Function         gap_ble_s_attr_request_cback
    322 **
    323 ** Description      GAP ATT server attribute access request callback.
    324 **
    325 ** Returns          void.
    326 **
    327 *******************************************************************************/
    328 void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id,
    329                                    tGATTS_REQ_TYPE type, tGATTS_DATA *p_data)
    330 {
    331     UINT8       status = GATT_INVALID_PDU;
    332     tGATTS_RSP  rsp_msg;
    333     BOOLEAN     ignore = FALSE;
    334 
    335     GAP_TRACE_EVENT("gap_ble_s_attr_request_cback : recv type (0x%02x)", type);
    336 
    337     memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
    338 
    339     switch (type)
    340     {
    341         case GATTS_REQ_TYPE_READ:
    342             status = gap_proc_read(type, &p_data->read_req, &rsp_msg);
    343             break;
    344 
    345         case GATTS_REQ_TYPE_WRITE:
    346             if (!p_data->write_req.need_rsp)
    347                 ignore = TRUE;
    348 
    349             status = gap_proc_write_req(type, &p_data->write_req);
    350             break;
    351 
    352         case GATTS_REQ_TYPE_WRITE_EXEC:
    353             ignore = TRUE;
    354             GAP_TRACE_EVENT("Ignore GATTS_REQ_TYPE_WRITE_EXEC"  );
    355             break;
    356 
    357         case GATTS_REQ_TYPE_MTU:
    358             GAP_TRACE_EVENT("Get MTU exchange new mtu size: %d", p_data->mtu);
    359             ignore = TRUE;
    360             break;
    361 
    362         default:
    363             GAP_TRACE_EVENT("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
    364             break;
    365     }
    366 
    367     if (!ignore)
    368         GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg);
    369 }
    370 
    371 /*******************************************************************************
    372 **
    373 ** Function         btm_ble_att_db_init
    374 **
    375 ** Description      GAP ATT database initalization.
    376 **
    377 ** Returns          void.
    378 **
    379 *******************************************************************************/
    380 void gap_attr_db_init(void)
    381 {
    382     tBT_UUID        app_uuid = {LEN_UUID_128,{0}};
    383     tBT_UUID        uuid     = {LEN_UUID_16,{UUID_SERVCLASS_GAP_SERVER}};
    384     UINT16          service_handle;
    385     tGAP_ATTR       *p_db_attr = &gap_cb.gatt_attr[0];
    386     tGATT_STATUS    status;
    387 
    388     /* Fill our internal UUID with a fixed pattern 0x82 */
    389     memset (&app_uuid.uu.uuid128, 0x82, LEN_UUID_128);
    390     memset(gap_cb.gatt_attr, 0, sizeof(tGAP_ATTR) *GAP_MAX_CHAR_NUM);
    391 
    392     gap_cb.gatt_if = GATT_Register(&app_uuid, &gap_cback);
    393 
    394     GATT_StartIf(gap_cb.gatt_if);
    395 
    396     /* Create a GAP service */
    397     service_handle = GATTS_CreateService (gap_cb.gatt_if, &uuid, 0, GAP_MAX_ATTR_NUM, TRUE);
    398 
    399     GAP_TRACE_EVENT ("gap_attr_db_init service_handle = %d", service_handle);
    400 
    401     /* add Device Name Characteristic
    402     */
    403     uuid.len = LEN_UUID_16;
    404     uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_DEVICE_NAME;
    405     p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid, GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ);
    406     p_db_attr ++;
    407 
    408     /* add Icon characteristic
    409     */
    410     uuid.uu.uuid16   = p_db_attr->uuid = GATT_UUID_GAP_ICON;
    411     p_db_attr->handle = GATTS_AddCharacteristic(service_handle,
    412                                                 &uuid,
    413                                                 GATT_PERM_READ,
    414                                                 GATT_CHAR_PROP_BIT_READ);
    415     p_db_attr ++;
    416 
    417 #if BTM_PERIPHERAL_ENABLED == TRUE       /* Only needed for peripheral testing */
    418     /* add preferred connection parameter characteristic
    419     */
    420     uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_PREF_CONN_PARAM;
    421     p_db_attr->attr_value.conn_param.int_max = GAP_PREFER_CONN_INT_MAX; /* 6 */
    422     p_db_attr->attr_value.conn_param.int_min = GAP_PREFER_CONN_INT_MIN; /* 0 */
    423     p_db_attr->attr_value.conn_param.latency = GAP_PREFER_CONN_LATENCY; /* 0 */
    424     p_db_attr->attr_value.conn_param.sp_tout = GAP_PREFER_CONN_SP_TOUT; /* 2000 */
    425     p_db_attr->handle = GATTS_AddCharacteristic(service_handle,
    426                                                 &uuid,
    427                                                 GATT_PERM_READ,
    428                                                 GATT_CHAR_PROP_BIT_READ);
    429     p_db_attr ++;
    430 #endif
    431 
    432     /* add Central address resolution Characteristic */
    433     uuid.len = LEN_UUID_16;
    434     uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_CENTRAL_ADDR_RESOL;
    435     p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid,
    436                                                 GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ);
    437     p_db_attr->attr_value.addr_resolution = 0;
    438     p_db_attr++;
    439 
    440     /* start service now */
    441     memset (&app_uuid.uu.uuid128, 0x81, LEN_UUID_128);
    442 
    443     status = GATTS_StartService(gap_cb.gatt_if, service_handle, GAP_TRANSPORT_SUPPORTED );
    444 
    445     GAP_TRACE_EVENT ("GAP App gatt_if: %d  s_hdl = %d start_status=%d",
    446                       gap_cb.gatt_if, service_handle, status);
    447 
    448 
    449 
    450 }
    451 
    452 /*******************************************************************************
    453 **
    454 ** Function         GAP_BleAttrDBUpdate
    455 **
    456 ** Description      GAP ATT database update.
    457 **
    458 ** Returns          void.
    459 **
    460 *******************************************************************************/
    461 void GAP_BleAttrDBUpdate(UINT16 attr_uuid, tGAP_BLE_ATTR_VALUE *p_value)
    462 {
    463     tGAP_ATTR  *p_db_attr = gap_cb.gatt_attr;
    464     UINT8       i = 0;
    465 
    466     GAP_TRACE_EVENT("GAP_BleAttrDBUpdate attr_uuid=0x%04x", attr_uuid);
    467 
    468     for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++)
    469     {
    470         if (p_db_attr->uuid == attr_uuid)
    471         {
    472             GAP_TRACE_EVENT("Found attr_uuid=0x%04x", attr_uuid);
    473 
    474             switch (attr_uuid)
    475             {
    476             case GATT_UUID_GAP_ICON:
    477                 p_db_attr->attr_value.icon  =  p_value->icon;
    478                 break;
    479 
    480             case GATT_UUID_GAP_PREF_CONN_PARAM:
    481                 memcpy((void *)&p_db_attr->attr_value.conn_param,
    482                        (const void *)&p_value->conn_param, sizeof(tGAP_BLE_PREF_PARAM));
    483                 break;
    484 
    485             case GATT_UUID_GAP_DEVICE_NAME:
    486                 BTM_SetLocalDeviceName((char *)p_value->p_dev_name);
    487                 break;
    488 
    489             case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
    490                 p_db_attr->attr_value.addr_resolution = p_value->addr_resolution;
    491                 break;
    492 
    493             }
    494             break;
    495         }
    496     }
    497 
    498     return;
    499 }
    500 
    501 /*******************************************************************************
    502 **
    503 ** Function         gap_ble_send_cl_read_request
    504 **
    505 ** Description      utility function to send a read request for a GAP charactersitic
    506 **
    507 ** Returns          TRUE if read started, else FALSE if GAP is busy
    508 **
    509 *******************************************************************************/
    510 BOOLEAN gap_ble_send_cl_read_request(tGAP_CLCB *p_clcb)
    511 {
    512     tGATT_READ_PARAM        param;
    513     UINT16                  uuid = 0;
    514     BOOLEAN                 started = FALSE;
    515 
    516     if (gap_ble_dequeue_request(p_clcb, &uuid, &p_clcb->p_cback))
    517     {
    518         memset(&param, 0, sizeof(tGATT_READ_PARAM));
    519 
    520         param.service.uuid.len       = LEN_UUID_16;
    521         param.service.uuid.uu.uuid16 = uuid;
    522         param.service.s_handle       = 1;
    523         param.service.e_handle       = 0xFFFF;
    524         param.service.auth_req       = 0;
    525 
    526         if (GATTC_Read(p_clcb->conn_id, GATT_READ_BY_TYPE, &param) == GATT_SUCCESS)
    527         {
    528             p_clcb->cl_op_uuid = uuid;
    529             started = TRUE;
    530         }
    531     }
    532 
    533     return started;
    534 }
    535 
    536 /*******************************************************************************
    537 **
    538 ** Function         gap_ble_cl_op_cmpl
    539 **
    540 ** Description      GAP client operation complete callback
    541 **
    542 ** Returns          void
    543 **
    544 *******************************************************************************/
    545 void gap_ble_cl_op_cmpl(tGAP_CLCB *p_clcb, BOOLEAN status, UINT16 len, UINT8 *p_name)
    546 {
    547     tGAP_BLE_CMPL_CBACK *p_cback = p_clcb->p_cback;
    548     UINT16                  op = p_clcb->cl_op_uuid;
    549 
    550     GAP_TRACE_EVENT("gap_ble_cl_op_cmpl status: %d", status);
    551 
    552     p_clcb->cl_op_uuid = 0;
    553     p_clcb->p_cback=NULL;
    554 
    555     if (p_cback && op)
    556     {
    557         GAP_TRACE_EVENT("calling gap_ble_cl_op_cmpl");
    558         (* p_cback)(status, p_clcb->bda, len, (char *)p_name);
    559     }
    560 
    561     /* if no further activity is requested in callback, drop the link */
    562     if (p_clcb->connected)
    563     {
    564         if (!gap_ble_send_cl_read_request(p_clcb))
    565         {
    566             GATT_Disconnect(p_clcb->conn_id);
    567             gap_ble_dealloc_clcb(p_clcb);
    568         }
    569     }
    570 }
    571 
    572 /*******************************************************************************
    573 **
    574 ** Function         gap_ble_c_connect_cback
    575 **
    576 ** Description      Client connection callback.
    577 **
    578 ** Returns          void
    579 **
    580 *******************************************************************************/
    581 static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
    582                                      BOOLEAN connected, tGATT_DISCONN_REASON reason,
    583                                      tGATT_TRANSPORT transport)
    584 {
    585     tGAP_CLCB   *p_clcb = gap_find_clcb_by_bd_addr (bda);
    586 
    587     UNUSED(gatt_if);
    588     UNUSED(transport);
    589 
    590     if (p_clcb != NULL)
    591     {
    592         if (connected)
    593         {
    594             p_clcb->conn_id = conn_id;
    595             p_clcb->connected = TRUE;
    596             /* start operation is pending */
    597             gap_ble_send_cl_read_request(p_clcb);
    598         }
    599         else
    600         {
    601             p_clcb->connected = FALSE;
    602             gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
    603             /* clean up clcb */
    604             gap_ble_dealloc_clcb(p_clcb);
    605         }
    606     }
    607 }
    608 
    609 /*******************************************************************************
    610 **
    611 ** Function         gap_ble_c_cmpl_cback
    612 **
    613 ** Description      Client operation complete callback.
    614 **
    615 ** Returns          void
    616 **
    617 *******************************************************************************/
    618 static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
    619 
    620 {
    621     tGAP_CLCB   *p_clcb = gap_ble_find_clcb_by_conn_id(conn_id);
    622     UINT16      op_type;
    623     UINT16      min, max, latency, tout;
    624     UINT16      len;
    625     UINT8       *pp;
    626 
    627     if (p_clcb == NULL)
    628         return;
    629 
    630     op_type = p_clcb->cl_op_uuid;
    631 
    632     GAP_TRACE_EVENT ("gap_ble_c_cmpl_cback() - op_code: 0x%02x  status: 0x%02x  read_type: 0x%04x", op, status, op_type);
    633     /* Currently we only issue read commands */
    634     if (op != GATTC_OPTYPE_READ)
    635         return;
    636 
    637     if (status != GATT_SUCCESS)
    638     {
    639         gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
    640         return;
    641     }
    642 
    643     pp = p_data->att_value.value;
    644 
    645     switch (op_type)
    646     {
    647         case GATT_UUID_GAP_PREF_CONN_PARAM:
    648             GAP_TRACE_EVENT ("GATT_UUID_GAP_PREF_CONN_PARAM");
    649             /* Extract the peripheral preferred connection parameters and save them */
    650 
    651             STREAM_TO_UINT16 (min, pp);
    652             STREAM_TO_UINT16 (max, pp);
    653             STREAM_TO_UINT16 (latency, pp);
    654             STREAM_TO_UINT16 (tout, pp);
    655 
    656             BTM_BleSetPrefConnParams (p_clcb->bda, min, max, latency, tout);
    657             /* release the connection here */
    658             gap_ble_cl_op_cmpl(p_clcb, TRUE, 0, NULL);
    659             break;
    660 
    661         case GATT_UUID_GAP_DEVICE_NAME:
    662             GAP_TRACE_EVENT ("GATT_UUID_GAP_DEVICE_NAME");
    663             len = (UINT16)strlen((char *)pp);
    664             if (len > GAP_CHAR_DEV_NAME_SIZE)
    665                 len = GAP_CHAR_DEV_NAME_SIZE;
    666             gap_ble_cl_op_cmpl(p_clcb, TRUE, len, pp);
    667             break;
    668 
    669         case GATT_UUID_GAP_CENTRAL_ADDR_RESOL:
    670             gap_ble_cl_op_cmpl(p_clcb, TRUE, 1, pp);
    671             break;
    672     }
    673 }
    674 
    675 
    676 /*******************************************************************************
    677 **
    678 ** Function         gap_ble_accept_cl_operation
    679 **
    680 ** Description      Start a process to read peer address resolution capability
    681 **
    682 ** Returns          TRUE if request accepted
    683 **
    684 *******************************************************************************/
    685 BOOLEAN gap_ble_accept_cl_operation(BD_ADDR peer_bda, UINT16 uuid, tGAP_BLE_CMPL_CBACK *p_cback)
    686 {
    687     tGAP_CLCB *p_clcb;
    688     BOOLEAN started = FALSE;
    689 
    690     if (p_cback == NULL && uuid != GATT_UUID_GAP_PREF_CONN_PARAM)
    691         return(started);
    692 
    693     if ((p_clcb = gap_find_clcb_by_bd_addr (peer_bda)) == NULL)
    694     {
    695         if ((p_clcb = gap_clcb_alloc(peer_bda)) == NULL)
    696         {
    697             GAP_TRACE_ERROR("gap_ble_accept_cl_operation max connection reached");
    698             return started;
    699         }
    700     }
    701 
    702     GAP_TRACE_EVENT ("%s() - BDA: %08x%04x  cl_op_uuid: 0x%04x",
    703                       __FUNCTION__,
    704                       (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
    705                       (peer_bda[4]<<8)+peer_bda[5], uuid);
    706 
    707     if (GATT_GetConnIdIfConnected(gap_cb.gatt_if, peer_bda, &p_clcb->conn_id, BT_TRANSPORT_LE))
    708         p_clcb->connected = TRUE;
    709 
    710     /* hold the link here */
    711     if (!GATT_Connect(gap_cb.gatt_if, p_clcb->bda, TRUE, BT_TRANSPORT_LE))
    712         return started;
    713 
    714     /* enqueue the request */
    715     gap_ble_enqueue_request(p_clcb, uuid, p_cback);
    716 
    717     if (p_clcb->connected && p_clcb->cl_op_uuid == 0)
    718         started = gap_ble_send_cl_read_request(p_clcb);
    719     else /* wait for connection up or pending operation to finish */
    720         started = TRUE;
    721 
    722    return started;
    723 }
    724 /*******************************************************************************
    725 **
    726 ** Function         GAP_BleReadPeerPrefConnParams
    727 **
    728 ** Description      Start a process to read a connected peripheral's preferred
    729 **                  connection parameters
    730 **
    731 ** Returns          TRUE if read started, else FALSE if GAP is busy
    732 **
    733 *******************************************************************************/
    734 BOOLEAN GAP_BleReadPeerPrefConnParams (BD_ADDR peer_bda)
    735 {
    736     return gap_ble_accept_cl_operation (peer_bda, GATT_UUID_GAP_PREF_CONN_PARAM, NULL);
    737 }
    738 
    739 /*******************************************************************************
    740 **
    741 ** Function         GAP_BleReadPeerDevName
    742 **
    743 ** Description      Start a process to read a connected peripheral's device name.
    744 **
    745 ** Returns          TRUE if request accepted
    746 **
    747 *******************************************************************************/
    748 BOOLEAN GAP_BleReadPeerDevName (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback)
    749 {
    750     return gap_ble_accept_cl_operation (peer_bda, GATT_UUID_GAP_DEVICE_NAME, p_cback);
    751 }
    752 
    753 /*******************************************************************************
    754 **
    755 ** Function         GAP_BleReadPeerAddressResolutionCap
    756 **
    757 ** Description      Start a process to read peer address resolution capability
    758 **
    759 ** Returns          TRUE if request accepted
    760 **
    761 *******************************************************************************/
    762 BOOLEAN GAP_BleReadPeerAddressResolutionCap (BD_ADDR peer_bda, tGAP_BLE_CMPL_CBACK *p_cback)
    763 {
    764     return gap_ble_accept_cl_operation(peer_bda, GATT_UUID_GAP_CENTRAL_ADDR_RESOL, p_cback);
    765 }
    766 
    767 /*******************************************************************************
    768 **
    769 ** Function         GAP_BleCancelReadPeerDevName
    770 **
    771 ** Description      Cancel reading a peripheral's device name.
    772 **
    773 ** Returns          TRUE if request accepted
    774 **
    775 *******************************************************************************/
    776 BOOLEAN GAP_BleCancelReadPeerDevName (BD_ADDR peer_bda)
    777 {
    778     tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (peer_bda);
    779 
    780     GAP_TRACE_EVENT ("GAP_BleCancelReadPeerDevName() - BDA: %08x%04x  cl_op_uuid: 0x%04x",
    781                       (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
    782                       (peer_bda[4]<<8)+peer_bda[5], (p_clcb == NULL)? 0 : p_clcb->cl_op_uuid);
    783 
    784     if (p_clcb == NULL)
    785     {
    786         GAP_TRACE_ERROR ("Cannot cancel current op is not get dev name");
    787         return FALSE;
    788     }
    789 
    790     if (!p_clcb->connected)
    791     {
    792         if (!GATT_CancelConnect(gap_cb.gatt_if, peer_bda, TRUE))
    793         {
    794             GAP_TRACE_ERROR ("Cannot cancel where No connection id");
    795             return FALSE;
    796         }
    797     }
    798 
    799     gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
    800 
    801     return(TRUE);
    802 }
    803 
    804 #endif  /* BLE_INCLUDED */
    805 
    806 
    807 
    808 
    809 
    810