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 <string.h>
     23 #include "gap_int.h"
     24 #include "gap_api.h"
     25 #include "gattdefs.h"
     26 #include "gatt_api.h"
     27 #include "gatt_int.h"
     28 #include "btm_int.h"
     29 #include "hcimsgs.h"
     30 
     31 #define GAP_CHAR_ICON_SIZE          2
     32 #define GAP_CHAR_DEV_NAME_SIZE      248
     33 #define GAP_BLE_PRIVACY_FLAG_SIZE    1
     34 
     35 #define GAP_MAX_NUM_INC_SVR       0
     36 #define GAP_MAX_ATTR_NUM          (2 * GAP_MAX_CHAR_NUM + GAP_MAX_NUM_INC_SVR + 1)
     37 #define GAP_MAX_CHAR_VALUE_SIZE   (30 + GAP_CHAR_DEV_NAME_SIZE)
     38 
     39 
     40 #ifndef GAP_ATTR_DB_SIZE
     41 #define GAP_ATTR_DB_SIZE      GATT_DB_MEM_SIZE(GAP_MAX_NUM_INC_SVR, GAP_MAX_CHAR_NUM, GAP_MAX_CHAR_VALUE_SIZE)
     42 #endif
     43 
     44 /* privacy flag readable and writable with encryption on */
     45 #ifndef GAP_BLE_PRIVACY_FLAG_PERM
     46 #define GAP_BLE_PRIVACY_FLAG_PERM       (GATT_PERM_READ|GATT_PERM_WRITE)
     47 #endif
     48 
     49 #define GATT_READ_GAP_PRIVACY_FLAG      1
     50 #define GATT_SET_GAP_PRIVACY_FLAG       2
     51 #define GATT_READ_GAP_REMOTE_NAME       3
     52 #define GATT_UPDATE_RECONN_ADDR         4
     53 
     54 #define GAP_BLE_PRIVACY_UNKNOWN         0xff
     55 
     56 static void gap_ble_s_attr_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE op_code, tGATTS_DATA *p_data);
     57 
     58 /* client connection callback */
     59 static void  gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected, tGATT_DISCONN_REASON reason);
     60 static void  gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data);
     61 
     62 static tGATT_CBACK gap_cback =
     63 {
     64     gap_ble_c_connect_cback,
     65     gap_ble_c_cmpl_cback,
     66     NULL,
     67     NULL,
     68     gap_ble_s_attr_request_cback,
     69     NULL
     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 (p_dev_name_cback)
    589     {
    590         GAP_TRACE_EVENT0("calling gap_ble_cl_op_cmpl");
    591 
    592         if (op == GATT_UUID_GAP_DEVICE_NAME)
    593             (* p_dev_name_cback)(status, p_clcb->bda, len, (char *)p_name);
    594     }
    595 
    596     if (!gap_ble_process_pending_op(p_clcb) &&
    597         p_clcb->cl_op_uuid == 0)
    598         GATT_Disconnect(p_clcb->conn_id);
    599 
    600 }
    601 
    602 /*******************************************************************************
    603 **
    604 ** Function         gap_ble_c_connect_cback
    605 **
    606 ** Description      Client connection callback.
    607 **
    608 ** Returns          void
    609 **
    610 *******************************************************************************/
    611 static void gap_ble_c_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
    612                                      BOOLEAN connected, tGATT_DISCONN_REASON reason)
    613 {
    614     tGAP_CLCB   *p_clcb = gap_find_clcb_by_bd_addr (bda);
    615     UINT16      cl_op_uuid;
    616 
    617     GAP_TRACE_EVENT5 ("gap_ble_c_connect_cback: from %08x%04x connected:%d conn_id=%d reason = 0x%04x",
    618                       (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3],
    619                       (bda[4]<<8)+bda[5], connected, conn_id, reason);
    620 
    621 
    622     if (connected)
    623     {
    624         if (p_clcb == NULL)
    625         {
    626             if ((p_clcb = gap_clcb_alloc(conn_id, bda))== NULL)
    627             {
    628                 GAP_TRACE_ERROR0 ("gap_ble_c_connect_cback: no_resource");
    629                 return;
    630             }
    631         }
    632         p_clcb->conn_id = conn_id;
    633         p_clcb->connected = TRUE;
    634 
    635         /* Do not use reconnection address for now -->
    636           check privacy enabled? set reconnect address
    637         btm_ble_update_reconnect_address(bda);*/
    638     }
    639     else
    640     {
    641         if (p_clcb != NULL)
    642             p_clcb->connected = FALSE;
    643     }
    644 
    645     if (p_clcb)
    646     {
    647         cl_op_uuid = p_clcb->cl_op_uuid;
    648 
    649         GAP_TRACE_EVENT1 ("cl_op_uuid=0x%04x", cl_op_uuid  );
    650 
    651         if (p_clcb->connected)
    652         {
    653             p_clcb->cl_op_uuid = 0;
    654             if (cl_op_uuid == GATT_UUID_GAP_DEVICE_NAME)
    655             {
    656                 GAP_BleReadPeerDevName (bda, (tGAP_BLE_DEV_NAME_CBACK *)p_clcb->p_cback);
    657             }
    658         }
    659         /* current link disconnect */
    660         else
    661         {
    662             gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
    663             memset(p_clcb, 0, sizeof(tGAP_CLCB));
    664         }
    665     }
    666 
    667 }
    668 
    669 /*******************************************************************************
    670 **
    671 ** Function         gap_ble_c_cmpl_cback
    672 **
    673 ** Description      Client operation complete callback.
    674 **
    675 ** Returns          void
    676 **
    677 *******************************************************************************/
    678 static void gap_ble_c_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
    679 
    680 {
    681     tGAP_CLCB   *p_clcb = gap_ble_find_clcb_by_conn_id(conn_id);
    682     UINT16      op_type;
    683     UINT16      min, max, latency, tout;
    684     UINT16      len;
    685     UINT8       *pp;
    686 
    687     if (p_clcb == NULL)
    688         return;
    689 
    690     op_type = p_clcb->cl_op_uuid;
    691 
    692     GAP_TRACE_EVENT3 ("gap_ble_c_cmpl_cback() - op_code: 0x%02x  status: 0x%02x  read_type: 0x%04x", op, status, op_type);
    693     /* Currently we only issue read commands */
    694     if (op != GATTC_OPTYPE_READ && op != GATTC_OPTYPE_WRITE)
    695         return;
    696 
    697     if (status != GATT_SUCCESS)
    698     {
    699         gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
    700         return;
    701     }
    702 
    703     pp = p_data->att_value.value;
    704 
    705     switch (op_type)
    706     {
    707         case GATT_UUID_GAP_PREF_CONN_PARAM:
    708             GAP_TRACE_EVENT0 ("GATT_UUID_GAP_PREF_CONN_PARAM");
    709             /* Extract the peripheral preferred connection parameters and save them */
    710 
    711             STREAM_TO_UINT16 (min, pp);
    712             STREAM_TO_UINT16 (max, pp);
    713             STREAM_TO_UINT16 (latency, pp);
    714             STREAM_TO_UINT16 (tout, pp);
    715 
    716             BTM_BleSetPrefConnParams (p_clcb->bda, min, max, latency, tout);
    717             /* release the connection here */
    718             gap_ble_cl_op_cmpl(p_clcb, TRUE, 0, NULL);
    719             break;
    720 
    721         case GATT_UUID_GAP_DEVICE_NAME:
    722             GAP_TRACE_EVENT0 ("GATT_UUID_GAP_DEVICE_NAME");
    723             len = (UINT16)strlen((char *)pp);
    724             if (len > GAP_CHAR_DEV_NAME_SIZE)
    725                 len = GAP_CHAR_DEV_NAME_SIZE;
    726             gap_ble_cl_op_cmpl(p_clcb, TRUE, len, pp);
    727             break;
    728         case GATT_UUID_GAP_ICON:
    729             break;
    730 
    731     }
    732 }
    733 
    734 /*******************************************************************************
    735 **
    736 ** Function         gap_ble_cl_read_request
    737 **
    738 ** Description      utility function to start a read request for a GAP charactersitic
    739 **
    740 ** Returns          TRUE if read started, else FALSE if GAP is busy
    741 **
    742 *******************************************************************************/
    743 BOOLEAN gap_ble_cl_read_request(tGAP_CLCB *p_clcb, UINT16 uuid, void * p_cback)
    744 {
    745     tGATT_READ_PARAM   param;
    746 
    747     memset(&param, 0, sizeof(tGATT_READ_PARAM));
    748 
    749     param.service.uuid.len       = LEN_UUID_16;
    750     param.service.uuid.uu.uuid16 = uuid;
    751     param.service.s_handle       = 1;
    752     param.service.e_handle       = 0xFFFF;
    753     param.service.auth_req       = 0;
    754 
    755     if (GATTC_Read(p_clcb->conn_id, GATT_READ_BY_TYPE, &param) != GATT_SUCCESS)
    756     {
    757         GAP_TRACE_ERROR0 ("GAP_BleReadPeerPrefConnParams: GATT_Read Failed");
    758         /* release the link here */
    759         GATT_Disconnect(p_clcb->conn_id);
    760         return(FALSE);
    761     }
    762     else
    763     {
    764         p_clcb->p_cback = p_cback;
    765         p_clcb->cl_op_uuid = uuid;
    766         return TRUE;
    767     }
    768 
    769 }
    770 
    771 /*******************************************************************************
    772 **
    773 ** Function         GAP_BleReadPeerPrefConnParams
    774 **
    775 ** Description      Start a process to read a connected peripheral's preferred
    776 **                  connection parameters
    777 **
    778 ** Returns          TRUE if read started, else FALSE if GAP is busy
    779 **
    780 *******************************************************************************/
    781 BOOLEAN GAP_BleReadPeerPrefConnParams (BD_ADDR peer_bda)
    782 {
    783 
    784     tGAP_CLCB   *p_clcb = gap_find_clcb_by_bd_addr (peer_bda);
    785 
    786     if (p_clcb == NULL)
    787     {
    788         if ((p_clcb = gap_clcb_alloc(0, peer_bda)) == NULL)
    789         {
    790             GAP_TRACE_ERROR0("GAP_BleReadPeerPrefConnParams max connection reached");
    791             return FALSE;
    792         }
    793         p_clcb->connected = FALSE;
    794     }
    795 
    796     GAP_TRACE_API3 ("GAP_BleReadPeerPrefConnParams() - BDA: %08x%04x  cl_op_uuid: 0x%04x",
    797                     (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
    798                     (peer_bda[4]<<8)+peer_bda[5], p_clcb->cl_op_uuid);
    799 
    800     /* For now we only handle one at a time */
    801     if (p_clcb->cl_op_uuid != 0)
    802         return(FALSE);
    803 
    804     /* hold the link here */
    805     GATT_Connect(gap_cb.gatt_if, p_clcb->bda, TRUE);
    806 
    807     if (p_clcb->connected)
    808     {
    809     return gap_ble_cl_read_request(p_clcb, GATT_UUID_GAP_PREF_CONN_PARAM, NULL);
    810     }
    811     /* Mark currently active operation */
    812     p_clcb->cl_op_uuid = GATT_UUID_GAP_PREF_CONN_PARAM;
    813 
    814     return(TRUE);
    815 
    816 
    817 }
    818 
    819 /*******************************************************************************
    820 **
    821 ** Function         GAP_BleReadPeerDevName
    822 **
    823 ** Description      Start a process to read a connected peripheral's device name.
    824 **
    825 ** Returns          TRUE if request accepted
    826 **
    827 *******************************************************************************/
    828 BOOLEAN GAP_BleReadPeerDevName (BD_ADDR peer_bda, tGAP_BLE_DEV_NAME_CBACK *p_cback)
    829 {
    830     tGAP_CLCB   *p_clcb = NULL;
    831 
    832     if (p_cback == NULL)
    833         return(FALSE);
    834 
    835     if ((p_clcb = gap_find_clcb_by_bd_addr (peer_bda)) == NULL)
    836     {
    837         if ((p_clcb = gap_clcb_alloc(0, peer_bda)) == NULL)
    838     {
    839         GAP_TRACE_ERROR0("GAP_BleReadPeerDevName max connection reached");
    840             return FALSE;
    841     }
    842         p_clcb->connected = FALSE;
    843     }
    844 
    845     GAP_TRACE_EVENT3 ("GAP_BleReadPeerDevName() - BDA: %08x%04x  cl_op_uuid: 0x%04x",
    846                       (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
    847                       (peer_bda[4]<<8)+peer_bda[5], p_clcb->cl_op_uuid);
    848 
    849     /* For now we only handle one at a time */
    850     if (p_clcb->cl_op_uuid != 0)
    851         return(FALSE);
    852 
    853     /* hold the link here */
    854     GATT_Connect(gap_cb.gatt_if, p_clcb->bda, TRUE);
    855 
    856     if (p_clcb->connected)
    857     {
    858         return gap_ble_cl_read_request(p_clcb, GATT_UUID_GAP_DEVICE_NAME, (void *)p_cback);
    859     }
    860 
    861     p_clcb->p_cback = (void *)p_cback;
    862     /* Mark currently active operation */
    863     p_clcb->cl_op_uuid = GATT_UUID_GAP_DEVICE_NAME;
    864 
    865 
    866     return(TRUE);
    867 }
    868 
    869 /*******************************************************************************
    870 **
    871 ** Function         GAP_BleCancelReadPeerDevName
    872 **
    873 ** Description      Cancel reading a peripheral's device name.
    874 **
    875 ** Returns          TRUE if request accepted
    876 **
    877 *******************************************************************************/
    878 BOOLEAN GAP_BleCancelReadPeerDevName (BD_ADDR peer_bda)
    879 {
    880     tGAP_CLCB *p_clcb = gap_find_clcb_by_bd_addr (peer_bda);
    881 
    882     GAP_TRACE_EVENT3 ("GAP_BleCancelReadPeerDevName() - BDA: %08x%04x  cl_op_uuid: 0x%04x",
    883                       (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
    884                       (peer_bda[4]<<8)+peer_bda[5], (p_clcb == NULL)? 0 : p_clcb->cl_op_uuid);
    885 
    886     if (p_clcb == NULL || p_clcb->cl_op_uuid != GATT_UUID_GAP_DEVICE_NAME)
    887     {
    888         GAP_TRACE_ERROR0 ("Cannot cancel current op is not get dev name");
    889         return FALSE;
    890     }
    891 
    892     if (!p_clcb->connected)
    893     {
    894         if (!GATT_CancelConnect(gap_cb.gatt_if, peer_bda, TRUE))
    895         {
    896             GAP_TRACE_ERROR0 ("Cannot cancel where No connection id");
    897             return FALSE;
    898         }
    899     }
    900 
    901     gap_ble_cl_op_cmpl(p_clcb, FALSE, 0, NULL);
    902 
    903     return(TRUE);
    904 }
    905 
    906 /*******************************************************************************
    907 **
    908 ** Function         GAP_BleUpdateReconnectAddr
    909 **
    910 ** Description      Start a process to udpate the reconnect address if remote devive
    911 **                  has privacy enabled.
    912 **
    913 ** Returns          TRUE if read started, else FALSE if GAP is busy
    914 **
    915 *******************************************************************************/
    916 BOOLEAN GAP_BleUpdateReconnectAddr (BD_ADDR peer_bda, BD_ADDR reconn_addr,
    917                                     tGAP_BLE_RECONN_ADDR_CBACK *p_cback)
    918 {
    919     tGAP_CLCB         *p_clcb;
    920     tGATT_DISC_PARAM   param;
    921 
    922     if (p_cback == NULL)
    923         return(FALSE);
    924 
    925     /* This function should only be called if there is a connection to  */
    926     /* the peer. Get a client handle for that connection.               */
    927     if ((p_clcb = gap_find_clcb_by_bd_addr (peer_bda)) == NULL ||
    928         !p_clcb->connected)
    929     {
    930         GAP_TRACE_ERROR0("No connection, can not update reconnect address");
    931         return(FALSE);
    932     }
    933 
    934     GAP_TRACE_API3 ("GAP_BleUpdateReconnectAddr() - BDA: %08x%04x  cl_op_uuid: 0x%04x",
    935                     (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
    936                     (peer_bda[4]<<8)+peer_bda[5], p_clcb->cl_op_uuid);
    937 
    938     /* For now we only handle one at a time */
    939     if (p_clcb->cl_op_uuid != 0)
    940     {
    941         gap_ble_enqueue_op(p_clcb, GATT_UPDATE_RECONN_ADDR, reconn_addr, 0, (void *)p_cback);
    942         return(FALSE);
    943     }
    944 
    945     /* hold the link here */
    946     GATT_Connect(gap_cb.gatt_if, p_clcb->bda, TRUE);
    947 
    948     memset(&param, 0, sizeof(tGATT_DISC_PARAM));
    949 
    950     param.service.len       = LEN_UUID_16;
    951     param.service.uu.uuid16 = GATT_UUID_GAP_RECONN_ADDR;
    952     param.s_handle          = 1;
    953     param.e_handle          = 0xFFFF;
    954 
    955     if (GATTC_Discover(p_clcb->conn_id, GATT_DISC_CHAR, &param) != GATT_SUCCESS)
    956     {
    957         GAP_TRACE_ERROR0 ("GAP_BleReadPeerPrefConnParams: GATT_Read Failed");
    958         /* release the link here */
    959         GATT_Disconnect(p_clcb->conn_id);
    960         return(FALSE);
    961     }
    962     else
    963     {
    964         p_clcb->p_cback     = (void *)p_cback;
    965         memcpy(p_clcb->reconn_addr, reconn_addr, BD_ADDR_LEN);
    966         p_clcb->cl_op_uuid  = GATT_UUID_GAP_RECONN_ADDR;
    967     }
    968 
    969     return TRUE;
    970 
    971 }
    972 
    973 #endif  /* BLE_INCLUDED */
    974 
    975 
    976 
    977 
    978 
    979