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 
     19 #include "bt_target.h"
     20 
     21 #if (defined BLE_INCLUDED && BLE_INCLUDED == TRUE)
     22 
     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_BLE_PRIVACY_FLAG_SIZE    1
     35 
     36 #define GAP_MAX_NUM_INC_SVR       0
     37 #define GAP_MAX_ATTR_NUM          (2 * GAP_MAX_CHAR_NUM + GAP_MAX_NUM_INC_SVR + 1)
     38 #define GAP_MAX_CHAR_VALUE_SIZE   (30 + GAP_CHAR_DEV_NAME_SIZE)
     39 
     40 
     41 #ifndef GAP_ATTR_DB_SIZE
     42 #define GAP_ATTR_DB_SIZE      GATT_DB_MEM_SIZE(GAP_MAX_NUM_INC_SVR, GAP_MAX_CHAR_NUM, GAP_MAX_CHAR_VALUE_SIZE)
     43 #endif
     44 
     45 /* privacy flag readable and writable with encryption on */
     46 #ifndef GAP_BLE_PRIVACY_FLAG_PERM
     47 #define GAP_BLE_PRIVACY_FLAG_PERM       (GATT_PERM_READ|GATT_PERM_WRITE)
     48 #endif
     49 
     50 #define GATT_READ_GAP_PRIVACY_FLAG      1
     51 #define GATT_SET_GAP_PRIVACY_FLAG       2
     52 #define GATT_READ_GAP_REMOTE_NAME       3
     53 #define GATT_UPDATE_RECONN_ADDR         4
     54 
     55 #define GAP_BLE_PRIVACY_UNKNOWN         0xff
     56 
     57 static void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE op_code, tGATTS_DATA *p_data);
     58 
     59 /* client connection callback */
     60 static void  gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason);
     61 static void  gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
     62 
     63 static tGATT_CBACK gap_cback =
     64 {
     65     gap_ble_c_connect_cback,
     66     gap_ble_c_cmpl_cback,
     67     NULL,
     68     NULL,
     69     gap_ble_s_attr_request_cback
     70 };
     71 
     72 
     73 
     74 /*******************************************************************************
     75 **
     76 ** Function         gap_find_clcb_by_bd_addr
     77 **
     78 ** Description      The function searches all LCB with macthing bd address
     79 **
     80 ** Returns          total number of clcb found.
     81 **
     82 *******************************************************************************/
     83 tGAP_CLCB *gap_find_clcb_by_bd_addr(BD_ADDR bda)
     84 {
     85     UINT8 i_clcb;
     86     tGAP_CLCB    *p_clcb = NULL;
     87 
     88     for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++)
     89     {
     90         if (p_clcb->in_use && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
     91         {
     92             return p_clcb;
     93         }
     94     }
     95 
     96     return NULL;
     97 }
     98 
     99 /*******************************************************************************
    100 **
    101 ** Function         gap_ble_find_clcb_by_conn_id
    102 **
    103 ** Description      The function searches all LCB with macthing connection ID
    104 **
    105 ** Returns          total number of clcb found.
    106 **
    107 *******************************************************************************/
    108 tGAP_CLCB *gap_ble_find_clcb_by_conn_id(UINT16 conn_id)
    109 {
    110     UINT8 i_clcb;
    111     tGAP_CLCB    *p_clcb = NULL;
    112 
    113     for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++)
    114     {
    115         if (p_clcb->in_use && p_clcb->connected && p_clcb->conn_id == conn_id)
    116         {
    117             return p_clcb;
    118         }
    119     }
    120 
    121     return p_clcb;
    122 }
    123 
    124 /*******************************************************************************
    125 **
    126 ** Function         gap_clcb_alloc
    127 **
    128 ** Description      The function allocates a GAP  connection link control block
    129 **
    130 ** Returns           NULL if not found. Otherwise pointer to the connection link block.
    131 **
    132 *******************************************************************************/
    133 tGAP_CLCB *gap_clcb_alloc (UINT16 conn_id, BD_ADDR bda)
    134 {
    135     UINT8         i_clcb = 0;
    136     tGAP_CLCB    *p_clcb = NULL;
    137 
    138     for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++)
    139     {
    140         if (!p_clcb->in_use)
    141         {
    142             p_clcb->in_use      = TRUE;
    143             p_clcb->conn_id     = conn_id;
    144             p_clcb->connected   = TRUE;
    145             memcpy (p_clcb->bda, bda, BD_ADDR_LEN);
    146             break;
    147         }
    148     }
    149     return p_clcb;
    150 }
    151 
    152 /*******************************************************************************
    153 **
    154 ** Function         gap_find_alloc_clcb
    155 **
    156 ** Description      The function find or allocates a GAP  connection link control block
    157 **
    158 ** Returns           NULL if not found. Otherwise pointer to the connection link block.
    159 **
    160 *******************************************************************************/
    161 tGAP_CLCB *gap_find_alloc_clcb (UINT16 conn_id, BD_ADDR bda)
    162 {
    163     UINT8         i_clcb = 0;
    164     tGAP_CLCB    *p_clcb = NULL;
    165 
    166     for (i_clcb = 0, p_clcb= gap_cb.clcb; i_clcb < GAP_MAX_CL; i_clcb++, p_clcb++)
    167     {
    168         if (!p_clcb->in_use)
    169         {
    170             p_clcb->in_use      = TRUE;
    171             p_clcb->conn_id     = conn_id;
    172             p_clcb->connected   = TRUE;
    173             memcpy (p_clcb->bda, bda, BD_ADDR_LEN);
    174             break;
    175         }
    176     }
    177     return p_clcb;
    178 }
    179 
    180 /*******************************************************************************
    181 **
    182 ** Function         gap_get_conn_id_if_connected
    183 **
    184 ** Description      This function returns a connecttion handle to a ATT server
    185 **                  if the server is already connected
    186 **
    187 ** Parameters       client_if: client interface.
    188 **                  bd_addr: peer device address.
    189 **
    190 ** Returns          Connection handle or invalid handle value
    191 **
    192 *******************************************************************************/
    193 UINT16 gap_get_conn_id_if_connected (BD_ADDR bd_addr)
    194 {
    195     tGAP_CLCB       *p_clcb;
    196     UINT16          i;
    197 
    198     GAP_TRACE_EVENT2 ("gap_get_conn_id_if_connected() - BDA: %08x%04x ",
    199                       (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
    200                       (bd_addr[4]<<8)+bd_addr[5]);
    201 
    202     for (i = 0, p_clcb = gap_cb.clcb; i < GAP_MAX_CL; i++, p_clcb++)
    203     {
    204         if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bd_addr,  BD_ADDR_LEN) )
    205         {
    206             return(p_clcb->conn_id);
    207         }
    208     }
    209 
    210     /* If here, failed to allocate a client control block */
    211     GATT_TRACE_DEBUG0 ("gap_get_conn_id_if_connected: not connected");
    212     return(GATT_INVALID_CONN_ID);
    213 }
    214 
    215 /*******************************************************************************
    216 **
    217 ** Function         gap_ble_enqueue_op
    218 **
    219 ** Description      enqueue a GAP operation when GAP client is busy
    220 **
    221 ** Returns          void
    222 **
    223 *******************************************************************************/
    224 void gap_ble_enqueue_op( tGAP_CLCB * p_clcb, UINT8 op, BD_ADDR reconn_addr, UINT8 privacy_flag, void *p_cback)
    225 {
    226     tGAP_BLE_PENDING_OP  *p_op = (tGAP_BLE_PENDING_OP *)GKI_getbuf(sizeof(tGAP_BLE_PENDING_OP));
    227 
    228     if (p_op != NULL)
    229     {
    230         p_op->op = op;
    231         p_op->p_pending_cback = p_cback;
    232 
    233         if (op == GATT_SET_GAP_PRIVACY_FLAG)
    234             p_op->pending_data.privacy_flag = privacy_flag;
    235         else if (op == GATT_UPDATE_RECONN_ADDR)
    236             memcpy(p_op->pending_data.reconn_addr, reconn_addr, BD_ADDR_LEN);
    237 
    238         GKI_enqueue(&p_clcb->pending_op_q, p_op);
    239     }
    240 }
    241 
    242 /*******************************************************************************
    243 **
    244 ** Function         gap_ble_process_pending_op
    245 **
    246 ** Description      get next pending operation and process it
    247 **
    248 ** Returns          void
    249 **
    250 *******************************************************************************/
    251 static BOOLEAN gap_ble_process_pending_op(tGAP_CLCB *p_clcb)
    252 {
    253     tGAP_BLE_PENDING_OP *p_pending_op = (tGAP_BLE_PENDING_OP *)GKI_dequeue(&p_clcb->pending_op_q);
    254     BOOLEAN         started = FALSE;
    255 
    256     if (p_pending_op != NULL)
    257     {
    258         if (p_pending_op->op == GATT_UPDATE_RECONN_ADDR)
    259         {
    260             GAP_BleUpdateReconnectAddr( p_clcb->bda,
    261                                         p_pending_op->pending_data.reconn_addr,
    262                                         (tGAP_BLE_RECONN_ADDR_CBACK *)p_pending_op->p_pending_cback);
    263             started = TRUE;
    264         }
    265         GKI_freebuf(p_pending_op);
    266     }
    267     else
    268     {
    269         GAP_TRACE_EVENT0("No pending operation");
    270     }
    271 
    272     return started;
    273 }
    274 
    275 /*******************************************************************************
    276 **   GAP Attributes Database Request callback
    277 *******************************************************************************/
    278 tGATT_STATUS gap_read_attr_value (UINT16 handle, tGATT_VALUE *p_value, BOOLEAN is_long)
    279 {
    280     tGAP_ATTR   *p_db_attr = gap_cb.gatt_attr;
    281     UINT8       *p = p_value->value, i;
    282     UINT16      offset = p_value->offset;
    283     UINT8       *p_dev_name = NULL;
    284 
    285     for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++)
    286     {
    287         if (handle == p_db_attr->handle)
    288         {
    289             if (p_db_attr->uuid != GATT_UUID_GAP_DEVICE_NAME &&
    290                 is_long == TRUE)
    291                 return GATT_NOT_LONG;
    292 
    293             switch (p_db_attr->uuid)
    294             {
    295                 case GATT_UUID_GAP_DEVICE_NAME:
    296                     BTM_ReadLocalDeviceName((char **)&p_dev_name);
    297                     if (strlen ((char *)p_dev_name) > GATT_MAX_ATTR_LEN)
    298                         p_value->len = GATT_MAX_ATTR_LEN;
    299                     else
    300                         p_value->len = (UINT16)strlen ((char *)p_dev_name);
    301 
    302                     if (offset > p_value->len)
    303                         return GATT_INVALID_OFFSET;
    304                     else
    305                     {
    306                         p_value->len -= offset;
    307                         p_dev_name += offset;
    308                         ARRAY_TO_STREAM(p, p_dev_name, p_value->len);
    309                         GAP_TRACE_EVENT1("GATT_UUID_GAP_DEVICE_NAME len=0x%04x", p_value->len);
    310                     }
    311                     break;
    312 
    313                 case GATT_UUID_GAP_ICON:
    314                     UINT16_TO_STREAM(p, p_db_attr->attr_value.icon);
    315                     p_value->len = 2;
    316                     break;
    317 
    318                 case GATT_UUID_GAP_PRIVACY_FLAG:
    319                     UINT8_TO_STREAM(p, p_db_attr->attr_value.privacy);
    320                     p_value->len = 1;
    321                     break;
    322 
    323                 case GATT_UUID_GAP_RECONN_ADDR:
    324                     p_value->len = BD_ADDR_LEN;
    325                     BDADDR_TO_STREAM(p, p_db_attr->attr_value.reconn_bda);
    326                     break;
    327 
    328                 case GATT_UUID_GAP_PREF_CONN_PARAM:
    329                     UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_min); /* int_min */
    330                     UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.int_max); /* int_max */
    331                     UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.latency); /* latency */
    332                     UINT16_TO_STREAM(p, p_db_attr->attr_value.conn_param.sp_tout);  /* sp_tout */
    333                     p_value->len =8;
    334                     break;
    335             }
    336             return GATT_SUCCESS;
    337         }
    338     }
    339     return GATT_NOT_FOUND;
    340 }
    341 
    342 /*******************************************************************************
    343 **   GAP Attributes Database Read/Read Blob Request process
    344 *******************************************************************************/
    345 tGATT_STATUS gap_proc_read (tGATTS_REQ_TYPE type, tGATT_READ_REQ *p_data, tGATTS_RSP *p_rsp)
    346 {
    347     tGATT_STATUS    status = GATT_NO_RESOURCES;
    348 
    349     if (p_data->is_long)
    350         p_rsp->attr_value.offset = p_data->offset;
    351 
    352     p_rsp->attr_value.handle = p_data->handle;
    353 
    354     status = gap_read_attr_value(p_data->handle, &p_rsp->attr_value, p_data->is_long);
    355 
    356     return status;
    357 }
    358 BOOLEAN gap_read_local_reconn_addr(BD_ADDR_PTR reconn_bda)
    359 {
    360     BD_ADDR dummy_bda = {0};
    361 
    362     if (memcmp(gap_cb.reconn_bda, dummy_bda, BD_ADDR_LEN) != 0)
    363     {
    364         memcpy(reconn_bda, gap_cb.reconn_bda, BD_ADDR_LEN);
    365         return TRUE;
    366     }
    367     else
    368         return FALSE;
    369 }
    370 
    371 /******************************************************************************
    372 **
    373 ** Function         gap_proc_write_req
    374 **
    375 ** Description      GAP ATT server process a write request.
    376 **
    377 ** Returns          void.
    378 **
    379 *******************************************************************************/
    380 UINT8 gap_proc_write_req( tGATTS_REQ_TYPE type, tGATT_WRITE_REQ *p_data)
    381 {
    382     tGAP_ATTR   *p_db_attr = gap_cb.gatt_attr;
    383     UINT8   i;
    384 
    385     for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++)
    386     {
    387         if (p_data-> handle == p_db_attr->handle)
    388         {
    389             if (p_data->offset != 0) return GATT_NOT_LONG;
    390             if (p_data->is_prep) return GATT_REQ_NOT_SUPPORTED;
    391 
    392 /* DO NOT SUPPORT RECONNECTION ADDRESS FOR NOW
    393 
    394             if (p_db_attr->uuid == GATT_UUID_GAP_RECONN_ADDR)
    395             {
    396                 if (!btm_cb.ble_ctr_cb.privacy)
    397                     return GATT_WRITE_NOT_PERMIT;
    398                 if (p_data->len != BD_ADDR_LEN) return GATT_INVALID_ATTR_LEN;
    399 
    400                 STREAM_TO_BDADDR(p_db_attr->attr_value.reconn_bda, p);
    401                 // write direct connection address
    402                 memcpy(&gap_cb.reconn_bda, p_db_attr->attr_value.reconn_bda, BD_ADDR_LEN);
    403 
    404                 return GATT_SUCCESS;
    405             }
    406             else
    407 */
    408             return GATT_WRITE_NOT_PERMIT;
    409         }
    410     }
    411     return GATT_NOT_FOUND;
    412 
    413 }
    414 
    415 /******************************************************************************
    416 **
    417 ** Function         gap_ble_s_attr_request_cback
    418 **
    419 ** Description      GAP ATT server attribute access request callback.
    420 **
    421 ** Returns          void.
    422 **
    423 *******************************************************************************/
    424 void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id,
    425                                    tGATTS_REQ_TYPE type, tGATTS_DATA *p_data)
    426 {
    427     UINT8       status = GATT_INVALID_PDU;
    428     tGATTS_RSP  rsp_msg;
    429     BOOLEAN     ignore = FALSE;
    430 
    431     GAP_TRACE_EVENT1("gap_ble_s_attr_request_cback : recv type (0x%02x)", type);
    432 
    433     memset(&rsp_msg, 0, sizeof(tGATTS_RSP));
    434 
    435     switch (type)
    436     {
    437         case GATTS_REQ_TYPE_READ:
    438             status = gap_proc_read(type, &p_data->read_req, &rsp_msg);
    439             break;
    440 
    441         case GATTS_REQ_TYPE_WRITE:
    442             if (!p_data->write_req.need_rsp)
    443                 ignore = TRUE;
    444 
    445             status = gap_proc_write_req(type, &p_data->write_req);
    446             break;
    447 
    448         case GATTS_REQ_TYPE_WRITE_EXEC:
    449             ignore = TRUE;
    450             GAP_TRACE_EVENT0("Ignore GATTS_REQ_TYPE_WRITE_EXEC"  );
    451             break;
    452 
    453         case GATTS_REQ_TYPE_MTU:
    454             GAP_TRACE_EVENT1("Get MTU exchange new mtu size: %d", p_data->mtu);
    455             ignore = TRUE;
    456             break;
    457 
    458         default:
    459             GAP_TRACE_EVENT1("Unknown/unexpected LE GAP ATT request: 0x%02x", type);
    460             break;
    461     }
    462 
    463     if (!ignore)
    464         GATTS_SendRsp (conn_id, trans_id, status, &rsp_msg);
    465 }
    466 
    467 /*******************************************************************************
    468 **
    469 ** Function         btm_ble_att_db_init
    470 **
    471 ** Description      GAP ATT database initalization.
    472 **
    473 ** Returns          void.
    474 **
    475 *******************************************************************************/
    476 void gap_attr_db_init(void)
    477 {
    478     tBT_UUID        app_uuid = {LEN_UUID_128,{0}};
    479     tBT_UUID        uuid     = {LEN_UUID_16,{UUID_SERVCLASS_GAP_SERVER}};
    480     UINT16          service_handle;
    481     tGAP_ATTR       *p_db_attr = &gap_cb.gatt_attr[0];
    482     tGATT_STATUS    status;
    483 
    484     /* Fill our internal UUID with a fixed pattern 0x82 */
    485     memset (&app_uuid.uu.uuid128, 0x82, LEN_UUID_128);
    486     memset(gap_cb.gatt_attr, 0, sizeof(tGAP_ATTR) *GAP_MAX_CHAR_NUM);
    487 
    488     gap_cb.gatt_if = GATT_Register(&app_uuid, &gap_cback);
    489 
    490     GATT_StartIf(gap_cb.gatt_if);
    491 
    492     /* Create a GAP service */
    493     service_handle = GATTS_CreateService (gap_cb.gatt_if, &uuid, 0, GAP_MAX_ATTR_NUM, TRUE);
    494 
    495     GAP_TRACE_EVENT1 ("gap_attr_db_init service_handle = %d", service_handle);
    496 
    497     /* add Device Name Characteristic
    498     */
    499     uuid.len = LEN_UUID_16;
    500     uuid.uu.uuid16 = p_db_attr->uuid = GATT_UUID_GAP_DEVICE_NAME;
    501     p_db_attr->handle = GATTS_AddCharacteristic(service_handle, &uuid, GATT_PERM_READ, GATT_CHAR_PROP_BIT_READ);
    502     p_db_attr ++;
    503 
    504     /* add Icon characteristic
    505     */
    506     uuid.uu.uuid16   = p_db_attr->uuid = GATT_UUID_GAP_ICON;
    507     p_db_attr->handle = GATTS_AddCharacteristic(service_handle,
    508                                                 &uuid,
    509                                                 GATT_PERM_READ,
    510                                                 GATT_CHAR_PROP_BIT_READ);
    511     p_db_attr ++;
    512 
    513     /* start service now */
    514     memset (&app_uuid.uu.uuid128, 0x81, LEN_UUID_128);
    515 
    516     status = GATTS_StartService(gap_cb.gatt_if, service_handle, GAP_TRANSPORT_SUPPORTED );
    517 
    518     GAP_TRACE_EVENT3 ("GAP App gatt_if: %d  s_hdl = %d start_status=%d",
    519                       gap_cb.gatt_if, service_handle, status);
    520 
    521 
    522 
    523 }
    524 
    525 /*******************************************************************************
    526 **
    527 ** Function         GAP_BleAttrDBUpdate
    528 **
    529 ** Description      GAP ATT database update.
    530 **
    531 ** Returns          void.
    532 **
    533 *******************************************************************************/
    534 void GAP_BleAttrDBUpdate(UINT16 attr_uuid, tGAP_BLE_ATTR_VALUE *p_value)
    535 {
    536     tGAP_ATTR  *p_db_attr = gap_cb.gatt_attr;
    537     UINT8       i = 0;
    538 
    539     GAP_TRACE_EVENT1("GAP_BleAttrDBUpdate attr_uuid=0x%04x", attr_uuid);
    540 
    541     for (i = 0; i < GAP_MAX_CHAR_NUM; i ++, p_db_attr ++)
    542     {
    543         if (p_db_attr->uuid == attr_uuid)
    544         {
    545             GAP_TRACE_EVENT1("Found attr_uuid=0x%04x", attr_uuid);
    546 
    547             switch (attr_uuid)
    548             {
    549             case GATT_UUID_GAP_ICON:
    550                 p_db_attr->attr_value.icon  =  p_value->icon;
    551                 break;
    552 
    553             case GATT_UUID_GAP_PREF_CONN_PARAM:
    554                 memcpy((void *)&p_db_attr->attr_value.conn_param, (const void *)&p_value->conn_param, sizeof(tGAP_BLE_PREF_PARAM));
    555                 break;
    556 
    557             case GATT_UUID_GAP_DEVICE_NAME:
    558                 BTM_SetLocalDeviceName((char *)p_value->p_dev_name);
    559                 break;
    560 
    561             }
    562             break;
    563         }
    564     }
    565 
    566     return;
    567 }
    568 
    569 /*******************************************************************************
    570 **
    571 ** Function         gap_ble_cl_op_cmpl
    572 **
    573 ** Description      GAP client operation complete callback
    574 **
    575 ** Returns          void
    576 **
    577 *******************************************************************************/
    578 void gap_ble_cl_op_cmpl(tGAP_CLCB *p_clcb, BOOLEAN status, UINT16 len, UINT8 *p_name)
    579 {
    580     tGAP_BLE_DEV_NAME_CBACK *p_dev_name_cback = (tGAP_BLE_DEV_NAME_CBACK *)(p_clcb->p_cback);
    581     UINT16                  op = p_clcb->cl_op_uuid;
    582 
    583     GAP_TRACE_EVENT1("gap_ble_cl_op_cmpl status: %d", status);
    584 
    585     p_clcb->cl_op_uuid = 0;
    586     p_clcb->p_cback=NULL;
    587 
    588     if (!gap_ble_process_pending_op(p_clcb) && op != 0)
    589         GATT_Disconnect(p_clcb->conn_id);
    590 
    591     if (p_dev_name_cback)
    592     {
    593         GAP_TRACE_EVENT0("calling gap_ble_cl_op_cmpl");
    594 
    595         if (op == GATT_UUID_GAP_DEVICE_NAME)
    596             (* p_dev_name_cback)(status, p_clcb->bda, len, (char *)p_name);
    597     }
    598 
    599 }
    600 
    601 /*******************************************************************************
    602 **
    603 ** Function         gap_ble_c_connect_cback
    604 **
    605 ** Description      Client connection callback.
    606 **
    607 ** Returns          void
    608 **
    609 *******************************************************************************/
    610 static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
    611                                      BOOLEAN connected, tGATT_DISCONN_REASON reason)
    612 {
    613     tGAP_CLCB   *p_clcb = gap_find_clcb_by_bd_addr (bda);
    614     UINT16      cl_op_uuid;
    615 
    616     GAP_TRACE_EVENT5 ("gap_ble_c_connect_cback: from %08x%04x connected:%d conn_id=%d reason = 0x%04x",
    617                       (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3],
    618                       (bda[4]<<8)+bda[5], connected, conn_id, reason);
    619 
    620 
    621     if (connected)
    622     {
    623         if (p_clcb == NULL)
    624         {
    625             if ((p_clcb = gap_clcb_alloc(conn_id, bda))== NULL)
    626             {
    627                 GAP_TRACE_ERROR0 ("gap_ble_c_connect_cback: no_resource");
    628                 return;
    629             }
    630         }
    631         p_clcb->conn_id = conn_id;
    632         p_clcb->connected = TRUE;
    633 
    634         /* Do not use reconnection address for now -->
    635           check privacy enabled? set reconnect address
    636         btm_ble_update_reconnect_address(bda);*/
    637     }
    638     else
    639     {
    640         if (p_clcb != NULL)
    641             p_clcb->connected = FALSE;
    642     }
    643 
    644     if (p_clcb)
    645     {
    646         cl_op_uuid = p_clcb->cl_op_uuid;
    647 
    648         GAP_TRACE_EVENT1 ("cl_op_uuid=0x%04x", cl_op_uuid  );
    649 
    650         if (p_clcb->connected)
    651         {
    652             p_clcb->cl_op_uuid = 0;
    653             if (cl_op_uuid == GATT_UUID_GAP_DEVICE_NAME)
    654             {
    655                 GAP_BleReadPeerDevName (bda, (tGAP_BLE_DEV_NAME_CBACK *)p_clcb->p_cback);
    656             }
    657         }
    658         /* current link disconnect */
    659         else
    660         {
    661             gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
    662             memset(p_clcb, 0, sizeof(tGAP_CLCB));
    663         }
    664     }
    665 
    666 }
    667 
    668 /*******************************************************************************
    669 **
    670 ** Function         gap_ble_c_cmpl_cback
    671 **
    672 ** Description      Client operation complete callback.
    673 **
    674 ** Returns          void
    675 **
    676 *******************************************************************************/
    677 static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
    678 
    679 {
    680     tGAP_CLCB   *p_clcb = gap_ble_find_clcb_by_conn_id(conn_id);
    681     UINT16      op_type;
    682     UINT16      min, max, latency, tout;
    683     UINT16      len;
    684     UINT8       *pp;
    685 
    686     if (p_clcb == NULL)
    687         return;
    688 
    689     op_type = p_clcb->cl_op_uuid;
    690 
    691     GAP_TRACE_EVENT3 ("gap_ble_c_cmpl_cback() - op_code: 0x%02x  status: 0x%02x  read_type: 0x%04x", op, status, op_type);
    692     /* Currently we only issue read commands */
    693     if (op != GATTC_OPTYPE_READ && op != GATTC_OPTYPE_WRITE)
    694         return;
    695 
    696     if (status != GATT_SUCCESS)
    697     {
    698         gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
    699         return;
    700     }
    701 
    702     pp = p_data->att_value.value;
    703 
    704     switch (op_type)
    705     {
    706         case GATT_UUID_GAP_PREF_CONN_PARAM:
    707             GAP_TRACE_EVENT0 ("GATT_UUID_GAP_PREF_CONN_PARAM");
    708             /* Extract the peripheral preferred connection parameters and save them */
    709 
    710             STREAM_TO_UINT16 (min, pp);
    711             STREAM_TO_UINT16 (max, pp);
    712             STREAM_TO_UINT16 (latency, pp);
    713             STREAM_TO_UINT16 (tout, pp);
    714 
    715             BTM_BleSetPrefConnParams (p_clcb->bda, min, max, latency, tout);
    716             /* release the connection here */
    717             gap_ble_cl_op_cmpl(p_clcb, TRUE, 0, NULL);
    718             break;
    719 
    720         case GATT_UUID_GAP_DEVICE_NAME:
    721             GAP_TRACE_EVENT0 ("GATT_UUID_GAP_DEVICE_NAME");
    722             len = (UINT16)strlen((char *)pp);
    723             if (len > GAP_CHAR_DEV_NAME_SIZE)
    724                 len = GAP_CHAR_DEV_NAME_SIZE;
    725             gap_ble_cl_op_cmpl(p_clcb, TRUE, len, pp);
    726             break;
    727         case GATT_UUID_GAP_ICON:
    728             break;
    729 
    730     }
    731 }
    732 
    733 /*******************************************************************************
    734 **
    735 ** Function         gap_ble_cl_read_request
    736 **
    737 ** Description      utility function to start a read request for a GAP charactersitic
    738 **
    739 ** Returns          TRUE if read started, else FALSE if GAP is busy
    740 **
    741 *******************************************************************************/
    742 BOOLEAN gap_ble_cl_read_request(tGAP_CLCB *p_clcb, UINT16 uuid, void * p_cback)
    743 {
    744     tGATT_READ_PARAM   param;
    745 
    746     memset(&param, 0, sizeof(tGATT_READ_PARAM));
    747 
    748     param.service.uuid.len       = LEN_UUID_16;
    749     param.service.uuid.uu.uuid16 = uuid;
    750     param.service.s_handle       = 1;
    751     param.service.e_handle       = 0xFFFF;
    752     param.service.auth_req       = 0;
    753 
    754     if (GATTC_Read(p_clcb->conn_id, GATT_READ_BY_TYPE, &param) != GATT_SUCCESS)
    755     {
    756         GAP_TRACE_ERROR0 ("GAP_BleReadPeerPrefConnParams: GATT_Read Failed");
    757         /* release the link here */
    758         GATT_Disconnect(p_clcb->conn_id);
    759         return(FALSE);
    760     }
    761     else
    762     {
    763         p_clcb->p_cback = p_cback;
    764         p_clcb->cl_op_uuid = uuid;
    765         return TRUE;
    766     }
    767 
    768 }
    769 
    770 /*******************************************************************************
    771 **
    772 ** Function         GAP_BleReadPeerPrefConnParams
    773 **
    774 ** Description      Start a process to read a connected peripheral's preferred
    775 **                  connection parameters
    776 **
    777 ** Returns          TRUE if read started, else FALSE if GAP is busy
    778 **
    779 *******************************************************************************/
    780 BOOLEAN GAP_BleReadPeerPrefConnParams (BD_ADDR peer_bda)
    781 {
    782     tGAP_CLCB   *p_clcb;
    783 
    784 
    785     /* This function should only be called if there is a connection to  */
    786     /* the peer. Get a client handle for that connection.               */
    787     if ((p_clcb = gap_find_clcb_by_bd_addr (peer_bda)) == NULL ||
    788         !p_clcb->connected)
    789     {
    790         GAP_TRACE_ERROR0("No connection, can not update reconnect address");
    791         return(FALSE);
    792     }
    793 
    794     GAP_TRACE_API3 ("GAP_BleReadPeerPrefConnParams() - BDA: %08x%04x  cl_op_uuid: 0x%04x",
    795                     (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
    796                     (peer_bda[4]<<8)+peer_bda[5], p_clcb->cl_op_uuid);
    797 
    798     /* For now we only handle one at a time */
    799     if (p_clcb->cl_op_uuid != 0)
    800         return(FALSE);
    801 
    802     return gap_ble_cl_read_request(p_clcb, GATT_UUID_GAP_PREF_CONN_PARAM, NULL);
    803 
    804 }
    805 
    806 /*******************************************************************************
    807 **
    808 ** Function         GAP_BleReadPeerDevName
    809 **
    810 ** Description      Start a process to read a connected peripheral's device name.
    811 **
    812 ** Returns          TRUE if request accepted
    813 **
    814 *******************************************************************************/
    815 BOOLEAN GAP_BleReadPeerDevName (BD_ADDR peer_bda, tGAP_BLE_DEV_NAME_CBACK *p_cback)
    816 {
    817     tGAP_CLCB   *p_clcb = gap_find_clcb_by_bd_addr (peer_bda);
    818 
    819     if (p_cback == NULL)
    820         return(FALSE);
    821 
    822     if (p_clcb == NULL)
    823     {
    824         p_clcb = gap_clcb_alloc(0, peer_bda);
    825         p_clcb->connected = FALSE;
    826     }
    827 
    828     if (p_clcb == NULL)
    829     {
    830         GAP_TRACE_ERROR0("GAP_BleReadPeerDevName max connection reached");
    831     }
    832 
    833 
    834     GAP_TRACE_EVENT3 ("GAP_BleReadPeerDevName() - BDA: %08x%04x  cl_op_uuid: 0x%04x",
    835                       (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
    836                       (peer_bda[4]<<8)+peer_bda[5], p_clcb->cl_op_uuid);
    837 
    838     /* For now we only handle one at a time */
    839     if (p_clcb->cl_op_uuid != 0)
    840         return(FALSE);
    841 
    842     /* hold the link here */
    843     GATT_Connect(gap_cb.gatt_if, p_clcb->bda, TRUE);
    844 
    845     if (p_clcb->connected)
    846     {
    847         return gap_ble_cl_read_request(p_clcb, GATT_UUID_GAP_DEVICE_NAME, (void *)p_cback);
    848     }
    849 
    850     p_clcb->p_cback = (void *)p_cback;
    851     /* Mark currently active operation */
    852     p_clcb->cl_op_uuid = GATT_UUID_GAP_DEVICE_NAME;
    853 
    854 
    855     return(TRUE);
    856 }
    857 
    858 /*******************************************************************************
    859 **
    860 ** Function         GAP_BleCancelReadPeerDevName
    861 **
    862 ** Description      Cancel reading a peripheral's device name.
    863 **
    864 ** Returns          TRUE if request accepted
    865 **
    866 *******************************************************************************/
    867 BOOLEAN GAP_BleCancelReadPeerDevName (BD_ADDR peer_bda)
    868 {
    869     tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (peer_bda);
    870 
    871     GAP_TRACE_EVENT3 ("GAP_BleCancelReadPeerDevName() - BDA: %08x%04x  cl_op_uuid: 0x%04x",
    872                       (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
    873                       (peer_bda[4]<<8)+peer_bda[5], (p_clcb == NULL)? 0 : p_clcb->cl_op_uuid);
    874 
    875     if (p_clcb == NULL || p_clcb->cl_op_uuid != GATT_UUID_GAP_DEVICE_NAME)
    876     {
    877         GAP_TRACE_ERROR0 ("Cannot cancel current op is not get dev name");
    878         return FALSE;
    879     }
    880 
    881     if (!p_clcb->connected)
    882     {
    883         if (!GATT_CancelConnect(gap_cb.gatt_if, peer_bda, TRUE))
    884         {
    885             GAP_TRACE_ERROR0 ("Cannot cancel where No connection id");
    886             return FALSE;
    887         }
    888     }
    889 
    890     gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
    891 
    892     return(TRUE);
    893 }
    894 
    895 /*******************************************************************************
    896 **
    897 ** Function         GAP_BleUpdateReconnectAddr
    898 **
    899 ** Description      Start a process to udpate the reconnect address if remote devive
    900 **                  has privacy enabled.
    901 **
    902 ** Returns          TRUE if read started, else FALSE if GAP is busy
    903 **
    904 *******************************************************************************/
    905 BOOLEAN GAP_BleUpdateReconnectAddr (BD_ADDR peer_bda, BD_ADDR reconn_addr,
    906                                     tGAP_BLE_RECONN_ADDR_CBACK *p_cback)
    907 {
    908     tGAP_CLCB         *p_clcb;
    909     tGATT_DISC_PARAM   param;
    910 
    911     if (p_cback == NULL)
    912         return(FALSE);
    913 
    914     /* This function should only be called if there is a connection to  */
    915     /* the peer. Get a client handle for that connection.               */
    916     if ((p_clcb = gap_find_clcb_by_bd_addr (peer_bda)) == NULL ||
    917         !p_clcb->connected)
    918     {
    919         GAP_TRACE_ERROR0("No connection, can not update reconnect address");
    920         return(FALSE);
    921     }
    922 
    923     GAP_TRACE_API3 ("GAP_BleUpdateReconnectAddr() - BDA: %08x%04x  cl_op_uuid: 0x%04x",
    924                     (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
    925                     (peer_bda[4]<<8)+peer_bda[5], p_clcb->cl_op_uuid);
    926 
    927     /* For now we only handle one at a time */
    928     if (p_clcb->cl_op_uuid != 0)
    929     {
    930         gap_ble_enqueue_op(p_clcb, GATT_UPDATE_RECONN_ADDR, reconn_addr, 0, (void *)p_cback);
    931         return(FALSE);
    932     }
    933 
    934     /* hold the link here */
    935     GATT_Connect(gap_cb.gatt_if, p_clcb->bda, TRUE);
    936 
    937     memset(&param, 0, sizeof(tGATT_DISC_PARAM));
    938 
    939     param.service.len       = LEN_UUID_16;
    940     param.service.uu.uuid16 = GATT_UUID_GAP_RECONN_ADDR;
    941     param.s_handle          = 1;
    942     param.e_handle          = 0xFFFF;
    943 
    944     if (GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR, &param) != GATT_SUCCESS)
    945     {
    946         GAP_TRACE_ERROR0 ("GAP_BleReadPeerPrefConnParams: GATT_Read Failed");
    947         /* release the link here */
    948         GATT_Disconnect(p_clcb->conn_id);
    949         return(FALSE);
    950     }
    951     else
    952     {
    953         p_clcb->p_cback     = (void *)p_cback;
    954         memcpy(p_clcb->reconn_addr, reconn_addr, BD_ADDR_LEN);
    955         p_clcb->cl_op_uuid  = GATT_UUID_GAP_RECONN_ADDR;
    956     }
    957 
    958     return TRUE;
    959 
    960 }
    961 
    962 #endif  /* BLE_INCLUDED */
    963 
    964 
    965 
    966 
    967 
    968