Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c218299e authored by Chaojing Sun's avatar Chaojing Sun Committed by Andre Eisenbach
Browse files

LE: Register for service change indication

Some bonded remote devices require the client to register for service
change indication and actually set the client configuration descriptor
before service change indications can be removed.

This change add an additional step after device bonding has occured to
register for service change indication if possible.

Bug: 18173911
Change-Id: I25386faec0d58834ee2b0a9d1db2d2e052311264
parent e918c92e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -4937,8 +4937,8 @@ static UINT8 bta_dm_ble_smp_cback (tBTM_LE_EVT event, BD_ADDR bda, tBTM_LE_EVT_D
            else
            {
                sec_event.auth_cmpl.success = TRUE;
                GATT_ConfigServiceChangeCCC(bda, TRUE, BT_TRANSPORT_LE);
            }
            sec_event.auth_cmpl.privacy_enabled = p_data->complt.privacy_supported;
            if (bta_dm_cb.p_sec_cback)
            {
                //bta_dm_cb.p_sec_cback(BTA_DM_AUTH_CMPL_EVT, &sec_event);
+0 −3
Original line number Diff line number Diff line
@@ -761,9 +761,6 @@ typedef struct
    LINK_KEY        key;                /* Link key associated with peer device. */
    UINT8           key_type;           /* The type of Link Key */
    BOOLEAN         success;            /* TRUE of authentication succeeded, FALSE if failed. */
#if BLE_INCLUDED == TRUE
    BOOLEAN         privacy_enabled;    /* used for BLE device only */
#endif
    UINT8           fail_reason;        /* The HCI reason/error code for when success=FALSE */

} tBTA_DM_AUTH_CMPL;
+269 −46
Original line number Diff line number Diff line
@@ -40,17 +40,24 @@
#define GATTP_ATTR_DB_SIZE      GATT_DB_MEM_SIZE(GATTP_MAX_NUM_INC_SVR, GATTP_MAX_CHAR_NUM, GATTP_MAX_CHAR_VALUE_SIZE)
#endif

static void gatt_profile_request_cback (UINT16 conn_id, UINT32 trans_id, UINT8 op_code, tGATTS_DATA *p_data);
static void gatt_profile_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
                                         BOOLEAN connected, tGATT_DISCONN_REASON reason, tBT_TRANSPORT transport);
static void gatt_request_cback(UINT16 conn_id, UINT32 trans_id, UINT8 op_code, tGATTS_DATA *p_data);
static void gatt_connect_cback(tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id, BOOLEAN connected,
              tGATT_DISCONN_REASON reason, tBT_TRANSPORT transport);
static void gatt_disc_res_cback(UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data);
static void gatt_disc_cmpl_cback(UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status);
static void gatt_cl_op_cmpl_cback(UINT16 conn_id, tGATTC_OPTYPE op, tGATT_STATUS status,
              tGATT_CL_COMPLETE *p_data);

static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB *p_clcb);


static tGATT_CBACK gatt_profile_cback =
{
    gatt_profile_connect_cback,
    NULL,
    NULL,
    NULL,
    gatt_profile_request_cback,
    gatt_connect_cback,
    gatt_cl_op_cmpl_cback,
    gatt_disc_res_cback,
    gatt_disc_cmpl_cback,
    gatt_request_cback,
    NULL,
    NULL
} ;
@@ -59,25 +66,39 @@ static tGATT_CBACK gatt_profile_cback =
**
** Function         gatt_profile_find_conn_id_by_bd_addr
**
** Description      The function searches all LCB with macthing bd address
** Description      Find the connection ID by remote address
**
** Returns          Connection ID
**
*******************************************************************************/
UINT16 gatt_profile_find_conn_id_by_bd_addr(BD_ADDR remote_bda)
{
    UINT16 conn_id = GATT_INVALID_CONN_ID;
    GATT_GetConnIdIfConnected (gatt_cb.gatt_if, remote_bda, &conn_id, BT_TRANSPORT_LE);
    return conn_id;
}

/*******************************************************************************
**
** Function         gatt_profile_find_clcb_by_conn_id
**
** Returns          total number of clcb found.
** Description      find clcb by Connection ID
**
** Returns          Pointer to the found link conenction control block.
**
*******************************************************************************/
UINT16 gatt_profile_find_conn_id_by_bd_addr(BD_ADDR bda)
static tGATT_PROFILE_CLCB *gatt_profile_find_clcb_by_conn_id(UINT16 conn_id)
{
    UINT8 i_clcb;
    tGATT_PROFILE_CLCB    *p_clcb = NULL;

    for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++)
    {
        if (p_clcb->in_use && p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
        {
            return p_clcb->conn_id;
        }
        if (p_clcb->in_use && p_clcb->conn_id == conn_id)
            return p_clcb;
    }

    return GATT_INVALID_CONN_ID;
    return p_clcb;
}

/*******************************************************************************
@@ -98,10 +119,8 @@ static tGATT_PROFILE_CLCB *gatt_profile_find_clcb_by_bd_addr(BD_ADDR bda, tBT_TR
    {
        if (p_clcb->in_use && p_clcb->transport == transport &&
            p_clcb->connected && !memcmp(p_clcb->bda, bda, BD_ADDR_LEN))
        {
            return p_clcb;
    }
    }

    return p_clcb;
}
@@ -134,42 +153,31 @@ tGATT_PROFILE_CLCB *gatt_profile_clcb_alloc (UINT16 conn_id, BD_ADDR bda, tBT_TR
    }
    return p_clcb;
}

/*******************************************************************************
**
** Function         gatt_profile_clcb_dealloc
**
** Description      The function deallocates a GATT profile  connection link control block
**
** Returns           NTrue the deallocation is successful
** Returns          void
**
*******************************************************************************/
BOOLEAN gatt_profile_clcb_dealloc (UINT16 conn_id)
{
    UINT8                   i_clcb = 0;
    tGATT_PROFILE_CLCB      *p_clcb = NULL;

    for (i_clcb = 0, p_clcb= gatt_cb.profile_clcb; i_clcb < GATT_MAX_APPS; i_clcb++, p_clcb++)
    {
        if (p_clcb->in_use && p_clcb->connected && (p_clcb->conn_id == conn_id))
void gatt_profile_clcb_dealloc (tGATT_PROFILE_CLCB *p_clcb)
{
    memset(p_clcb, 0, sizeof(tGATT_PROFILE_CLCB));
            return TRUE;
        }
}
    return FALSE;
}


/*******************************************************************************
**
** Function         gatt_profile_request_cback
** Function         gatt_request_cback
**
** Description      GATT profile attribute access request callback.
**
** Returns          void.
**
*******************************************************************************/
static void gatt_profile_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type,
static void gatt_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_REQ_TYPE type,
                                        tGATTS_DATA *p_data)
{
    UINT8       status = GATT_INVALID_PDU;
@@ -211,36 +219,40 @@ static void gatt_profile_request_cback (UINT16 conn_id, UINT32 trans_id, tGATTS_

/*******************************************************************************
**
** Function         gatt_profile_connect_cback
** Function         gatt_connect_cback
**
** Description      Gatt profile connection callback.
**
** Returns          void
**
*******************************************************************************/
static void gatt_profile_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
static void gatt_connect_cback (tGATT_IF gatt_if, BD_ADDR bda, UINT16 conn_id,
                                        BOOLEAN connected, tGATT_DISCONN_REASON reason,
                                        tBT_TRANSPORT transport)
{
    UNUSED(gatt_if);

    GATT_TRACE_EVENT ("gatt_profile_connect_cback: from %08x%04x connected:%d conn_id=%d reason = 0x%04x",
    GATT_TRACE_EVENT ("%s: from %08x%04x connected:%d conn_id=%d reason = 0x%04x", __FUNCTION__,
                       (bda[0]<<24)+(bda[1]<<16)+(bda[2]<<8)+bda[3],
                       (bda[4]<<8)+bda[5], connected, conn_id, reason);

    tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_bd_addr(bda, transport);
    if (p_clcb == NULL)
        return;

    if (connected)
    {
        if (gatt_profile_clcb_alloc(conn_id, bda, transport) == NULL)
        p_clcb->conn_id = conn_id;
        p_clcb->connected = TRUE;

        if (p_clcb->ccc_stage == GATT_SVC_CHANGED_CONNECTING)
        {
            GATT_TRACE_ERROR ("gatt_profile_connect_cback: no_resource");
            return;
        }
            p_clcb->ccc_stage ++;
            gatt_cl_start_config_ccc(p_clcb);
        }
    else
    {
        gatt_profile_clcb_dealloc(conn_id);
    } else {
        gatt_profile_clcb_dealloc(p_clcb);
    }

}

/*******************************************************************************
@@ -284,4 +296,215 @@ void gatt_profile_db_init (void)
                       gatt_cb.gatt_if,  status);
}

/*******************************************************************************
**
** Function         gatt_config_ccc_complete
**
** Description      The function finish the service change ccc configuration
**
** Returns          void
**
*******************************************************************************/
static void gatt_config_ccc_complete(tGATT_PROFILE_CLCB *p_clcb)
{
    GATT_Disconnect(p_clcb->conn_id);
    gatt_profile_clcb_dealloc(p_clcb);
}

/*******************************************************************************
**
** Function         gatt_disc_res_cback
**
** Description      Gatt profile discovery result callback
**
** Returns          void
**
*******************************************************************************/
static void gatt_disc_res_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_DISC_RES *p_data)
{
    tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);

    if (p_clcb == NULL)
        return;

    switch (disc_type)
    {
    case GATT_DISC_SRVC_BY_UUID:/* stage 1 */
        p_clcb->e_handle = p_data->value.group_value.e_handle;
        p_clcb->ccc_result ++;
        break;

    case GATT_DISC_CHAR:/* stage 2 */
        p_clcb->s_handle = p_data->value.dclr_value.val_handle;
        p_clcb->ccc_result ++;
        break;

    case GATT_DISC_CHAR_DSCPT: /* stage 3 */
        if (p_data->type.uu.uuid16 == GATT_UUID_CHAR_CLIENT_CONFIG)
        {
            p_clcb->s_handle = p_data->handle;
            p_clcb->ccc_result ++;
        }
        break;
    }
}

/*******************************************************************************
**
** Function         gatt_disc_cmpl_cback
**
** Description      Gatt profile discovery complete callback
**
** Returns          void
**
*******************************************************************************/
static void gatt_disc_cmpl_cback (UINT16 conn_id, tGATT_DISC_TYPE disc_type, tGATT_STATUS status)
{
    tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);

    if (p_clcb == NULL)
        return;

    if (status == GATT_SUCCESS && p_clcb->ccc_result > 0)
    {
        p_clcb->ccc_result = 0;
        p_clcb->ccc_stage ++;
        gatt_cl_start_config_ccc(p_clcb);
    } else {
        GATT_TRACE_ERROR("%s() - Register for service changed indication failure", __FUNCTION__);
    }
}

/*******************************************************************************
**
** Function         gatt_cl_op_cmpl_cback
**
** Description      Gatt profile client operation complete callback
**
** Returns          void
**
*******************************************************************************/
static void gatt_cl_op_cmpl_cback (UINT16 conn_id, tGATTC_OPTYPE op,
                                           tGATT_STATUS status, tGATT_CL_COMPLETE *p_data)
{
    tGATT_PROFILE_CLCB *p_clcb = gatt_profile_find_clcb_by_conn_id(conn_id);

    if (p_clcb == NULL)
        return;

    if (op == GATTC_OPTYPE_WRITE)
    {
        GATT_TRACE_DEBUG("%s() - ccc write status : %d", __FUNCTION__, status);
    }

    /* free the connection */
    gatt_config_ccc_complete (p_clcb);
}

/*******************************************************************************
**
** Function         gatt_cl_start_config_ccc
**
** Description      Gatt profile start configure service change CCC
**
** Returns          void
**
*******************************************************************************/
static void gatt_cl_start_config_ccc(tGATT_PROFILE_CLCB *p_clcb)
{
    tGATT_DISC_PARAM    srvc_disc_param;
    tGATT_VALUE         ccc_value;

    GATT_TRACE_DEBUG("%s() - stage: %d", __FUNCTION__, p_clcb->ccc_stage);

    memset (&srvc_disc_param, 0 , sizeof(tGATT_DISC_PARAM));
    memset (&ccc_value, 0 , sizeof(tGATT_VALUE));

    switch(p_clcb->ccc_stage)
    {
    case GATT_SVC_CHANGED_SERVICE: /* discover GATT service */
        srvc_disc_param.s_handle = 1;
        srvc_disc_param.e_handle = 0xffff;
        srvc_disc_param.service.len = 2;
        srvc_disc_param.service.uu.uuid16 = UUID_SERVCLASS_GATT_SERVER;
        if (GATTC_Discover (p_clcb->conn_id, GATT_DISC_SRVC_BY_UUID, &srvc_disc_param) != GATT_SUCCESS)
        {
            GATT_TRACE_ERROR("%s() - ccc service error", __FUNCTION__);
            gatt_config_ccc_complete(p_clcb);
        }
        break;

    case GATT_SVC_CHANGED_CHARACTERISTIC: /* discover service change char */
        srvc_disc_param.s_handle = 1;
        srvc_disc_param.e_handle = p_clcb->e_handle;
        srvc_disc_param.service.len = 2;
        srvc_disc_param.service.uu.uuid16 = GATT_UUID_GATT_SRV_CHGD;
        if (GATTC_Discover (p_clcb->conn_id, GATT_DISC_CHAR, &srvc_disc_param) != GATT_SUCCESS)
        {
            GATT_TRACE_ERROR("%s() - ccc char error", __FUNCTION__);
            gatt_config_ccc_complete(p_clcb);
        }
        break;

    case GATT_SVC_CHANGED_DESCRIPTOR: /* discover service change ccc */
        srvc_disc_param.s_handle = p_clcb->s_handle;
        srvc_disc_param.e_handle = p_clcb->e_handle;
        if (GATTC_Discover (p_clcb->conn_id, GATT_DISC_CHAR_DSCPT, &srvc_disc_param) != GATT_SUCCESS)
        {
            GATT_TRACE_ERROR("%s() - ccc char descriptor error", __FUNCTION__);
            gatt_config_ccc_complete(p_clcb);
        }
        break;

    case GATT_SVC_CHANGED_CONFIGURE_CCCD: /* write ccc */
        ccc_value.handle = p_clcb->s_handle;
        ccc_value.len = 2;
        ccc_value.value[0] = GATT_CLT_CONFIG_INDICATION;
        if (GATTC_Write (p_clcb->conn_id, GATT_WRITE, &ccc_value) != GATT_SUCCESS)
        {
            GATT_TRACE_ERROR("%s() - write ccc error", __FUNCTION__);
            gatt_config_ccc_complete(p_clcb);
        }
        break;
    }
}

/*******************************************************************************
**
** Function         GATT_ConfigServiceChangeCCC
**
** Description      Configure service change indication on remote device
**
** Returns          none
**
*******************************************************************************/
void GATT_ConfigServiceChangeCCC (BD_ADDR remote_bda, BOOLEAN enable, tBT_TRANSPORT transport)
{
    UINT16              conn_id = GATT_INVALID_CONN_ID;
    tGATT_PROFILE_CLCB   *p_clcb = gatt_profile_find_clcb_by_bd_addr (remote_bda, transport);

    if (p_clcb == NULL)
        p_clcb = gatt_profile_clcb_alloc (0, remote_bda, transport);

    if (p_clcb == NULL)
        return;

    if (GATT_GetConnIdIfConnected (gatt_cb.gatt_if, remote_bda, &p_clcb->conn_id, transport))
    {
        p_clcb->connected = TRUE;
    }
    /* hold the link here */
    GATT_Connect(gatt_cb.gatt_if, remote_bda, TRUE, transport);
    p_clcb->ccc_stage = GATT_SVC_CHANGED_CONNECTING;

    if (!p_clcb->connected)
    {
        /* wait for connection */
        return;
    }

    p_clcb->ccc_stage ++;
    gatt_cl_start_config_ccc(p_clcb);
}

#endif  /* BLE_INCLUDED */
+11 −2
Original line number Diff line number Diff line
@@ -462,6 +462,11 @@ typedef struct
    BOOLEAN         in_use;
}tGATT_BG_CONN_DEV;

#define GATT_SVC_CHANGED_CONNECTING        1   /* wait for connection */
#define GATT_SVC_CHANGED_SERVICE           2   /* GATT service discovery */
#define GATT_SVC_CHANGED_CHARACTERISTIC    3   /* service change char discovery */
#define GATT_SVC_CHANGED_DESCRIPTOR        4   /* service change CCC discoery */
#define GATT_SVC_CHANGED_CONFIGURE_CCCD    5   /* config CCC */

typedef struct
{
@@ -470,6 +475,12 @@ typedef struct
    BOOLEAN connected;
    BD_ADDR bda;
    tBT_TRANSPORT   transport;

    /* GATT service change CCC related variables */
    UINT8       ccc_stage;
    UINT8       ccc_result;
    UINT16      s_handle;
    UINT16      e_handle;
}tGATT_PROFILE_CLCB;

typedef struct
@@ -557,8 +568,6 @@ extern void gatt_add_a_bonded_dev_for_srv_chg (BD_ADDR bda);

/* from gatt_attr.c */
extern UINT16 gatt_profile_find_conn_id_by_bd_addr(BD_ADDR bda);
extern BOOLEAN gatt_profile_clcb_dealloc (UINT16 conn_id);
extern tGATT_PROFILE_CLCB *gatt_profile_clcb_alloc (UINT16 conn_id, BD_ADDR bda, tBT_TRANSPORT transport);


/* Functions provided by att_protocol.c */
+12 −1
Original line number Diff line number Diff line
@@ -1169,6 +1169,17 @@ extern "C"
*******************************************************************************/
    GATT_API extern BOOLEAN GATT_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr);

/*******************************************************************************
**
** Function         GATT_ConfigServiceChangeCCC
**
** Description      Configure service change indication on remote device
**
** Returns          None.
**
*******************************************************************************/
    GATT_API extern void GATT_ConfigServiceChangeCCC (BD_ADDR remote_bda, BOOLEAN enable,
                                                    tBT_TRANSPORT transport);
 
#ifdef __cplusplus