Exemple #1
0
/*******************************************************************************
**
** Function         gatt_proc_srv_chg
**
** Description      This function is process the service changed request
**
** Returns          void
**
*******************************************************************************/
void gatt_proc_srv_chg (void)
{
    UINT8               start_idx, found_idx;
    BD_ADDR             bda;
    BOOLEAN             srv_chg_ind_pending=FALSE;
    tGATT_TCB           *p_tcb;

    GATT_TRACE_DEBUG0 ("gatt_proc_srv_chg");

    if (gatt_cb.cb_info.p_srv_chg_callback && gatt_cb.handle_of_h_r)
    {
        gatt_set_srv_chg();
        start_idx =0;
        while (gatt_find_the_connected_bda(start_idx, bda, &found_idx))
        {
            p_tcb = &gatt_cb.tcb[found_idx];;
            srv_chg_ind_pending  = gatt_is_srv_chg_ind_pending(p_tcb);

            if (!srv_chg_ind_pending)
            {
                gatt_send_srv_chg_ind(bda);
            }
            else
            {
                GATT_TRACE_DEBUG0 ("discard srv chg - already has one in the queue");
            }
            start_idx = ++found_idx;
        }
    }
}
Exemple #2
0
/*******************************************************************************
**
** Function         gatt_le_data_ind
**
** Description      This function is called when data is received from L2CAP.
**                  if we are the originator of the connection, we are the ATT
**                  client, and the received message is queued up for the client.
**
**                  If we are the destination of the connection, we are the ATT
**                  server, so the message is passed to the server processing
**                  function.
**
** Returns          void
**
*******************************************************************************/
void gatt_data_process (tGATT_TCB *p_tcb, BT_HDR *p_buf)
{
    GATT_TRACE_DEBUG0("gatt_data_process");
    UINT8   *p = (UINT8 *)(p_buf + 1) + p_buf->offset;
    UINT8   op_code, pseudo_op_code;
    UINT16  msg_len;


    if (p_buf->len > 0)
    {
        msg_len = p_buf->len - 1;
        STREAM_TO_UINT8(op_code, p);
        GATT_TRACE_DEBUG1("op_code = %d", op_code);

        /* remove the two MSBs associated with sign write and write cmd */
        pseudo_op_code = op_code & (~GATT_WRITE_CMD_MASK);

        if (pseudo_op_code < GATT_OP_CODE_MAX)
        {
            if (op_code == GATT_SIGN_CMD_WRITE)
            {
                GATT_TRACE_DEBUG0("op_code == GATT_SIGN_CMD_WRITE");
                gatt_verify_signature(p_tcb, p_buf);
                return;
            }
            else
            {
                /* message from client */
                if ((op_code % 2) == 0)
                {
                    GATT_TRACE_DEBUG0("gatt_server_handle_client_req");
                    gatt_server_handle_client_req (p_tcb, op_code, msg_len, p);
                }
                else
                {
                    GATT_TRACE_DEBUG0("gatt_client_handle_server_rsp");
                    gatt_client_handle_server_rsp (p_tcb, op_code, msg_len, p);
                }
            }
        }
        else
        {
            GATT_TRACE_ERROR1 ("ATT - Rcvd L2CAP data, unknown cmd: 0x%x", op_code);
        }
    }
    else
    {
        GATT_TRACE_ERROR0 ("invalid data length, ignore");
    }

    GKI_freebuf (p_buf);
}
/*******************************************************************************
**
** Function         gatt_process_find_type_value_rsp
**
** Description      This function is called to handle find by type value response.
**
**
** Returns          void
**
*******************************************************************************/
void gatt_process_find_type_value_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data)
{
    tGATT_DISC_RES      result;
    UINT8               *p = p_data;

    GATT_TRACE_DEBUG0("gatt_process_find_type_value_rsp ");
    /* unexpected response */
    if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_SRVC_BY_UUID)
        return;

    memset (&result, 0, sizeof(tGATT_DISC_RES));
    result.type.len = 2;
    result.type.uu.uuid16 = GATT_UUID_PRI_SERVICE;

    /* returns a series of handle ranges */
    while (len >= 4)
    {
        STREAM_TO_UINT16 (result.handle, p);
        STREAM_TO_UINT16 (result.value.group_value.e_handle, p);
        memcpy (&result.value.group_value.service_type,  &p_clcb->uuid, sizeof(tBT_UUID));

        len -= 4;

        if (p_clcb->p_reg->app_cb.p_disc_res_cb)
            (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
    }

    /* last handle  + 1 */
    p_clcb->s_handle = (result.value.group_value.e_handle == 0) ? 0 : (result.value.group_value.e_handle + 1);
    /* initiate another request */
    gatt_act_discovery(p_clcb) ;
}
/*******************************************************************************
**
** Function         gatt_check_write_long_terminate
**
** Description      To terminate write long or not.
**
** Returns          TRUE: write long is terminated; FALSE keep sending.
**
*******************************************************************************/
BOOLEAN gatt_check_write_long_terminate(tGATT_TCB  *p_tcb, tGATT_CLCB *p_clcb, tGATT_VALUE *p_rsp_value)
{
    tGATT_VALUE         *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
    BOOLEAN             exec = FALSE;
    tGATT_EXEC_FLAG     flag = GATT_PREP_WRITE_EXEC;

    GATT_TRACE_DEBUG0("gatt_check_write_long_terminate ");
    /* check the first write response status */
    if (p_rsp_value != NULL)
    {
        if (p_rsp_value->handle != p_attr->handle ||
            p_rsp_value->len != p_clcb->counter ||
            memcmp(p_rsp_value->value, p_attr->value + p_attr->offset, p_rsp_value->len))
        {
            /* data does not match    */
            p_clcb->status = GATT_ERROR;
            flag = GATT_PREP_WRITE_CANCEL;
            exec = TRUE;
        }
        else /* response checking is good */
        {
            p_clcb->status = GATT_SUCCESS;
            /* update write offset and check if end of attribute value */
            if ((p_attr->offset += p_rsp_value->len) >= p_attr->len)
                exec = TRUE;
        }
    }
    if (exec)
    {
        gatt_send_queue_write_cancel (p_tcb, p_clcb, flag);
        return TRUE;
    }
    return FALSE;
}
Exemple #5
0
/*******************************************************************************
**
** Function         gatt_update_app_use_link_flag
**
** Description      Update the application use link flag and optional to check the acl link
**                  if the link is up then set the idle time out accordingly
**
** Returns          void.
**
*******************************************************************************/
void gatt_update_app_use_link_flag (tGATT_IF gatt_if, tGATT_TCB *p_tcb, BOOLEAN is_add, BOOLEAN check_acl_link)
{
    GATT_TRACE_DEBUG2("gatt_update_app_use_link_flag  is_add=%d chk_link=%d",
                      is_add, check_acl_link);

    gatt_update_app_hold_link_status(gatt_if, p_tcb, is_add);

    if (check_acl_link &&
        p_tcb &&
        (BTM_GetHCIConnHandle(p_tcb->peer_bda) != GATT_INVALID_ACL_HANDLE))
    {
        if (is_add)
        {
            GATT_TRACE_DEBUG0("GATT disables link idle timer");
            /* acl link is connected disable the idle timeout */
            GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_NO_IDLE_TIMEOUT);
        }
        else
        {
            if (!gatt_num_apps_hold_link(p_tcb))
            {
                /* acl link is connected but no application needs to use the link
                   so set the timeout value to GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP seconds */
                GATT_TRACE_DEBUG1("GATT starts link idle timer =%d sec", GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP);
                GATT_SetIdleTimeout(p_tcb->peer_bda, GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP);
            }

        }
    }
}
/*******************************************************************************
**
** Function         gatt_proc_disc_error_rsp
**
** Description      This function process the read by type response and send another
**                  request if needed.
**
** Returns          void.
**
*******************************************************************************/
void gatt_proc_disc_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 opcode,
                              UINT16 handle, UINT8 reason)
{
    tGATT_STATUS    status = (tGATT_STATUS) reason;

    GATT_TRACE_DEBUG2("gatt_proc_disc_error_rsp reason: %02x cmd_code %04x", reason, opcode);

    switch (opcode)
    {
        case GATT_REQ_READ_BY_GRP_TYPE:
        case GATT_REQ_FIND_TYPE_VALUE:
        case GATT_REQ_READ_BY_TYPE:
        case GATT_REQ_FIND_INFO:
            if (reason == GATT_NOT_FOUND)
            {
                status = GATT_SUCCESS;
                GATT_TRACE_DEBUG0("Discovery completed");
            }
            break;
        default:
            GATT_TRACE_ERROR1("Incorrect discovery opcode %04x",   opcode);
            break;
    }

    gatt_end_operation(p_clcb, status, NULL);
}
Exemple #7
0
/*******************************************************************************
**
** Function         gatt_send_srv_chg_ind
**
** Description      This function is called to send a service chnaged indication to
**                  the specified bd address
**
** Returns          void
**
*******************************************************************************/
void gatt_send_srv_chg_ind (BD_ADDR peer_bda)
{
    UINT8   handle_range[GATT_SIZE_OF_SRV_CHG_HNDL_RANGE];
    UINT8   *p = handle_range;
    UINT16  conn_id;

    GATT_TRACE_DEBUG0("gatt_send_srv_chg_ind");

    if (gatt_cb.handle_of_h_r)
    {
        if ((conn_id = gatt_profile_find_conn_id_by_bd_addr(peer_bda)) != GATT_INVALID_CONN_ID)
        {
            UINT16_TO_STREAM (p, 1);
            UINT16_TO_STREAM (p, 0xFFFF);
            GATTS_HandleValueIndication (conn_id,
                                         gatt_cb.handle_of_h_r,
                                         GATT_SIZE_OF_SRV_CHG_HNDL_RANGE,
                                         handle_range);
        }
        else
        {
            GATT_TRACE_ERROR2("Unable to find conn_id for  %08x%04x ",
                              (peer_bda[0]<<24)+(peer_bda[1]<<16)+(peer_bda[2]<<8)+peer_bda[3],
                              (peer_bda[4]<<8)+peer_bda[5] );
        }
    }
}
/*******************************************************************************
**
** Function         gatt_act_connect
**
** Description      GATT connection initiation.
**
** Returns          void.
**
*******************************************************************************/
BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr)
{
    BOOLEAN     ret = FALSE;
    tGATT_TCB   *p_tcb;
    UINT8       st;

    GATT_TRACE_DEBUG0("gatt_act_connect");

    if ((p_tcb = gatt_find_tcb_by_addr(bd_addr)) != NULL)
    {
        ret = TRUE;
        st = gatt_get_ch_state(p_tcb);

        /* before link down, another app try to open a GATT connection */
        if(st == GATT_CH_OPEN &&  gatt_num_apps_hold_link(p_tcb) == 0 &&
            /* only connection on fix channel when the l2cap channel is already open */
            p_tcb->att_lcid == L2CAP_ATT_CID )
        {
            if (!gatt_connect(bd_addr,  p_tcb))
                ret = FALSE;
        }
        else if(st == GATT_CH_CLOSING)
        {
            /* need to complete the closing first */
            ret = FALSE;
        }
    }
    else
    {
        if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr)) != NULL)
        {
            if (!gatt_connect(bd_addr,  p_tcb))
            {
                GATT_TRACE_ERROR0("gatt_connect failed");
                memset(p_tcb, 0, sizeof(tGATT_TCB));
            }
            else
                ret = TRUE;
        }
        else
        {
            ret = 0;
            GATT_TRACE_ERROR1("Max TCB for gatt_if [%d] reached.", p_reg->gatt_if);
        }
    }

    if (ret)
    {
        gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, FALSE);
    }

    return ret;
}
/*******************************************************************************
**
** Function         gatt_send_queue_write_cancel
**
** Description      send queue write cancel
**
** Returns          void.
**
*******************************************************************************/
void gatt_send_queue_write_cancel (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_EXEC_FLAG flag)
{
    UINT8       rt ;

    GATT_TRACE_DEBUG0("gatt_send_queue_write_cancel ");

    rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_EXEC_WRITE, (tGATT_CL_MSG *)&flag);

    if (rt != GATT_SUCCESS)
    {
        gatt_end_operation(p_clcb, rt, NULL);
    }
}
Exemple #10
0
/*******************************************************************************
**
** Function         gatt_init_srv_chg
**
** Description      This function is used to initialize the service changed
**                  attribute value
**
** Returns          void
**
*******************************************************************************/
void gatt_init_srv_chg (void)
{
    tGATTS_SRV_CHG_REQ req;
    tGATTS_SRV_CHG_RSP rsp;
    BOOLEAN status;
    UINT8 num_clients,i;
    tGATTS_SRV_CHG  srv_chg_clt;

    GATT_TRACE_DEBUG0("gatt_init_srv_chg");
    if (gatt_cb.cb_info.p_srv_chg_callback)
    {
        status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_NUM_CLENTS, NULL, &rsp);

        if (status && rsp.num_clients)
        {
            GATT_TRACE_DEBUG1("gatt_init_srv_chg num_srv_chg_clt_clients=%d", rsp.num_clients);
            num_clients = rsp.num_clients;
            i = 1; /* use one based index */
            while ((i <= num_clients) && status)
            {
                req.client_read_index = i;
                if ((status = (*gatt_cb.cb_info.p_srv_chg_callback)(GATTS_SRV_CHG_CMD_READ_CLENT, &req, &rsp)))
                {
                    memcpy(&srv_chg_clt, &rsp.srv_chg ,sizeof(tGATTS_SRV_CHG));
                    if (gatt_add_srv_chg_clt(&srv_chg_clt) == NULL)
                    {
                        GATT_TRACE_ERROR0("Unable to add a service change client");
                        status = FALSE;
                    }
                }
                i++;
            }
        }
    }
    else
    {
        GATT_TRACE_DEBUG0("gatt_init_srv_chg callback not registered yet");
    }
}
/*******************************************************************************
**
** Function         gatt_disconnect
**
** Description      This function is called to disconnect to an ATT device.
**
** Parameter        rem_bda: remote device address to disconnect from.
**
** Returns          TRUE: if connection found and to be disconnected; otherwise
**                  return FALSE.
**
*******************************************************************************/
BOOLEAN gatt_disconnect (BD_ADDR rem_bda)
{
    tGATT_TCB           *p_tcb = gatt_find_tcb_by_addr(rem_bda);
    BOOLEAN             ret = FALSE;
    tGATT_CH_STATE      ch_state;
    GATT_TRACE_DEBUG0 ("gatt_disconnect ");

    if (p_tcb != NULL)
    {
        ret = TRUE;
        if ( (ch_state = gatt_get_ch_state(p_tcb)) != GATT_CH_CLOSING )
        {
            if (p_tcb->att_lcid == L2CAP_ATT_CID)
            {
                if (ch_state == GATT_CH_OPEN)
                {
                    /* only LCB exist between remote device and local */
                    ret = L2CA_RemoveFixedChnl (L2CAP_ATT_CID, rem_bda);
                }
                else
                {
                    gatt_set_ch_state(p_tcb, GATT_CH_CLOSING);
                    ret = L2CA_CancelBleConnectReq (rem_bda);
                }
            }
            else
            {
                ret = L2CA_DisconnectReq(p_tcb->att_lcid);
            }
        }
        else
        {
            GATT_TRACE_DEBUG0 ("gatt_disconnect already in closing state");
        }
    }

    return ret;
}
Exemple #12
0
/*******************************************************************************
**
** Function         gatt_chk_srv_chg
**
** Description      Check sending service chnaged Indication is required or not
**                  if required then send the Indication
**
** Returns          void
**
*******************************************************************************/
void gatt_chk_srv_chg(tGATTS_SRV_CHG *p_srv_chg_clt)
{
    GATT_TRACE_DEBUG1("gatt_chk_srv_chg srv_changed=%d", p_srv_chg_clt->srv_changed );

    if (p_srv_chg_clt->srv_changed)
    {
        gatt_send_srv_chg_ind(p_srv_chg_clt->bda);
    }
    else
    {
        GATT_TRACE_DEBUG0("No need to send srv chg ");
    }

}
Exemple #13
0
/*******************************************************************************
**
** Function         gatt_init
**
** Description      This function is enable the GATT profile on the device.
**                  It clears out the control blocks, and registers with L2CAP.
**
** Returns          void
**
*******************************************************************************/
void gatt_init (void)
{
    tL2CAP_FIXED_CHNL_REG  fixed_reg;

    GATT_TRACE_DEBUG0("gatt_init()");

    memset (&gatt_cb, 0, sizeof(tGATT_CB));

#if defined(GATT_INITIAL_TRACE_LEVEL)
    gatt_cb.trace_level = GATT_INITIAL_TRACE_LEVEL;
#else
    gatt_cb.trace_level = BT_TRACE_LEVEL_NONE;    /* No traces */
#endif
    gatt_cb.def_mtu_size = GATT_DEF_BLE_MTU_SIZE;
    GKI_init_q (&gatt_cb.sign_op_queue);
    /* First, register fixed L2CAP channel for ATT over BLE */
    fixed_reg.fixed_chnl_opts.mode         = L2CAP_FCR_BASIC_MODE;
    fixed_reg.fixed_chnl_opts.max_transmit = 0xFF;
    fixed_reg.fixed_chnl_opts.rtrans_tout  = 2000;
    fixed_reg.fixed_chnl_opts.mon_tout     = 12000;
    fixed_reg.fixed_chnl_opts.mps          = 670;
    fixed_reg.fixed_chnl_opts.tx_win_sz    = 1;

    fixed_reg.pL2CA_FixedConn_Cb = gatt_le_connect_cback;
    fixed_reg.pL2CA_FixedData_Cb = gatt_le_data_ind;
    fixed_reg.default_idle_tout  = 0xffff;                  /* 0xffff default idle timeout */

    L2CA_RegisterFixedChannel (L2CAP_ATT_CID, &fixed_reg);

    /* Now, register with L2CAP for ATT PSM over BR/EDR */
    if (!L2CA_Register (BT_PSM_ATT, (tL2CAP_APPL_INFO *) &dyn_info))
    {
        GATT_TRACE_ERROR0 ("ATT Dynamic Registration failed");
    }

    BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0);
    BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_ATT, BTM_SEC_NONE, BT_PSM_ATT, 0, 0);

    gatt_cb.hdl_cfg.gatt_start_hdl = GATT_GATT_START_HANDLE;
    gatt_cb.hdl_cfg.gap_start_hdl  = GATT_GAP_START_HANDLE;
    gatt_cb.hdl_cfg.app_start_hdl  = GATT_APP_START_HANDLE;
    gatt_profile_db_init();

}
Exemple #14
0
/*******************************************************************************
**
** Function         gatt_act_connect
**
** Description      GATT connection initiation.
**
** Returns          void.
**
*******************************************************************************/
BOOLEAN gatt_act_connect (tGATT_REG *p_reg, BD_ADDR bd_addr)
{
    BOOLEAN     ret = FALSE;
    tGATT_TCB   *p_tcb;

    GATT_TRACE_DEBUG0("gatt_act_connect");

    if ((p_tcb = gatt_find_tcb_by_addr(bd_addr)) != NULL)
    {
        ret = TRUE;
        if(gatt_get_ch_state(p_tcb) == GATT_CH_CLOSING )
        {
            /* need to complete the closing first */
            ret = FALSE;
        }
    }
    else
    {
        if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr)) != NULL)
        {
            if (!gatt_connect(bd_addr,  p_tcb))
            {
                GATT_TRACE_ERROR0("gatt_connect failed");
                memset(p_tcb, 0, sizeof(tGATT_TCB));
            }
            else
                ret = TRUE;
        }
        else
        {
            ret = 0;
            GATT_TRACE_ERROR1("Max TCB for gatt_if [%d] reached.", p_reg->gatt_if);
        }
    }

    if (ret)
    {
        gatt_update_app_use_link_flag(p_reg->gatt_if, p_tcb, TRUE, FALSE);
    }

    return ret;
}
/*******************************************************************************
**
** Function         gatt_process_error_rsp
**
** Description      This function is called to handle the error response
**
**
** Returns          void
**
*******************************************************************************/
void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
                            UINT16 len, UINT8 *p_data)
{
    UINT8   opcode, reason, * p= p_data;
    UINT16  handle;
    tGATT_VALUE  *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;

    GATT_TRACE_DEBUG0("gatt_process_error_rsp ");
    STREAM_TO_UINT8(opcode, p);
    STREAM_TO_UINT16(handle, p);
    STREAM_TO_UINT8(reason, p);

    if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
    {
        gatt_proc_disc_error_rsp(p_tcb, p_clcb, opcode, handle, reason);
    }
    else
    {
        if ( (p_clcb->operation == GATTC_OPTYPE_WRITE) &&
             (p_clcb->op_subtype == GATT_WRITE) &&
             (opcode == GATT_REQ_PREPARE_WRITE) &&
             (p_attr) &&
             (handle == p_attr->handle)  )
        {
            p_clcb->status = reason;
            gatt_send_queue_write_cancel(p_tcb, p_clcb, GATT_PREP_WRITE_CANCEL);
        }
        else if ((p_clcb->operation == GATTC_OPTYPE_READ) &&
                 ((p_clcb->op_subtype == GATT_READ_CHAR_VALUE_HDL) ||
                  (p_clcb->op_subtype == GATT_READ_BY_HANDLE)) &&
                 (opcode == GATT_REQ_READ_BLOB) &&
                 p_clcb->first_read_blob_after_read &&
                 (reason == GATT_NOT_LONG))
        {
            gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf);
        }
        else
            gatt_end_operation(p_clcb, reason, NULL);
    }
}
Exemple #16
0
/*******************************************************************************
**
** Function         gatt_le_data_ind
**
** Description      This function is called when data is received from L2CAP.
**                  if we are the originator of the connection, we are the ATT
**                  client, and the received message is queued up for the client.
**
**                  If we are the destination of the connection, we are the ATT
**                  server, so the message is passed to the server processing
**                  function.
**
** Returns          void
**
*******************************************************************************/
static void gatt_le_data_ind (BD_ADDR bd_addr, BT_HDR *p_buf)
{
    GATT_TRACE_DEBUG0("gatt_le_data_ind");
    tGATT_TCB    *p_tcb;

    /* Find CCB based on bd addr */
    if ((p_tcb = gatt_find_tcb_by_addr (bd_addr)) != NULL &&
        gatt_get_ch_state(p_tcb) >= GATT_CH_OPEN)
    {
        gatt_data_process(p_tcb, p_buf);
    }
    else
    {
        GKI_freebuf (p_buf);

        if (p_tcb != NULL)
        {
            GATT_TRACE_WARNING1 ("ATT - Ignored L2CAP data while in state: %d",
                                 gatt_get_ch_state(p_tcb));
        }
    }
}
/*******************************************************************************
**
** Function         gatt_process_notification
**
** Description      This function is called to handle the handle value indication
**                  or handle value notification.
**
**
** Returns          void
**
*******************************************************************************/
void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code,
                               UINT16 len, UINT8 *p_data)
{
    tGATT_VALUE     value = {0};
    tGATT_REG       *p_reg;
    UINT16          conn_id;
    tGATT_STATUS    encrypt_status;
    UINT8           *p= p_data, i,
    event = (op_code == GATT_HANDLE_VALUE_NOTIF) ? GATTC_OPTYPE_NOTIFICATION : GATTC_OPTYPE_INDICATION;

    GATT_TRACE_DEBUG0("gatt_process_notification ");

    STREAM_TO_UINT16 (value.handle, p);
    value.len = len - 2;
    memcpy (value.value, p, value.len);

    if (!GATT_HANDLE_IS_VALID(value.handle))
    {
        /* illegal handle, send ack now */
        if (op_code == GATT_HANDLE_VALUE_IND)
            attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
        return;
    }

    if (event == GATTC_OPTYPE_INDICATION)
    {
        if (p_tcb->ind_count)
        {
            /* this is an error case that receiving an indication but we
               still has an indication not being acked yet.
               For now, just log the error reset the counter.
               Later we need to disconnect the link unconditionally.
            */
            GATT_TRACE_ERROR1("gatt_process_notification rcv Ind. but ind_count=%d (will reset ind_count)",  p_tcb->ind_count);
        }
        p_tcb->ind_count = 0;
    }

    /* should notify all registered client with the handle value notificaion/indication
       Note: need to do the indication count and start timer first then do callback
     */

    for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
    {
        if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb && (event == GATTC_OPTYPE_INDICATION))
            p_tcb->ind_count++;
    }

    if (event == GATTC_OPTYPE_INDICATION)
    {
        /* start a timer for app confirmation */
        if (p_tcb->ind_count > 0)
            gatt_start_ind_ack_timer(p_tcb);
        else /* no app to indicate, or invalid handle */
            attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
    }

    encrypt_status = gatt_get_link_encrypt_status(p_tcb);
    for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
    {
        if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb)
        {
            conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
            (*p_reg->app_cb.p_cmpl_cb) (conn_id, event, encrypt_status, (tGATT_CL_COMPLETE *)&value);
        }
    }

}
Exemple #18
0
/*******************************************************************************
**
** Function         gatt_le_connect_cback
**
** Description      This callback function is called by L2CAP to indicate that
**                  the ATT fixed channel for LE is
**                      connected (conn = TRUE)/disconnected (conn = FALSE).
**
*******************************************************************************/
static void gatt_le_connect_cback (BD_ADDR bd_addr, BOOLEAN connected, UINT16 reason)
{

    tGATT_TCB       *p_tcb = gatt_find_tcb_by_addr(bd_addr);

    BOOLEAN                 check_srv_chg = FALSE;
    tGATTS_SRV_CHG          *p_srv_chg_clt=NULL;
    BOOLEAN                 is_bg_conn = FALSE;


    GATT_TRACE_DEBUG3 ("GATT   ATT protocol channel with BDA: %08x%04x is %s",
                       (bd_addr[0]<<24)+(bd_addr[1]<<16)+(bd_addr[2]<<8)+bd_addr[3],
                       (bd_addr[4]<<8)+bd_addr[5], (connected) ? "connected" : "disconnected");


    if ((p_srv_chg_clt = gatt_is_bda_in_the_srv_chg_clt_list(bd_addr)) != NULL)
    {
        check_srv_chg = TRUE;
    }
    else
    {
        if (btm_sec_is_a_bonded_dev(bd_addr))
            gatt_add_a_bonded_dev_for_srv_chg(bd_addr);
    }

    if (connected)
    {
        GATT_TRACE_DEBUG1("connected is TRUE reason=%d",reason );
        /* BR/EDR lik, ignore this callback */
        if (reason == 0)
            return;

        /* do we have a channel initiating a connection? */
        if (p_tcb)
        {
            if (check_srv_chg)
                gatt_chk_srv_chg (p_srv_chg_clt);
            /* we are initiating connection */
            if ( gatt_get_ch_state(p_tcb) == GATT_CH_CONN)
            {
                /* send callback */
                gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
                p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;

                gatt_send_conn_cback(FALSE, p_tcb);
            }
            else /* there was an exisiting link, ignore the callback */
            {
                GATT_TRACE_ERROR0("connection already up, ignore it");
                return;
            }
        }
        /* this is incoming connection or background connection callback */
        else
        {
            if ((p_tcb = gatt_allocate_tcb_by_bdaddr(bd_addr)) != NULL)
            {
                p_tcb->att_lcid = L2CAP_ATT_CID;

                gatt_set_ch_state(p_tcb, GATT_CH_OPEN);

                p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
                if (L2CA_GetBleConnRole(p_tcb->peer_bda)== HCI_ROLE_MASTER)
                {
                    is_bg_conn = TRUE;
                }
                gatt_send_conn_cback (is_bg_conn, p_tcb);
                if (check_srv_chg)
                {
                    gatt_chk_srv_chg (p_srv_chg_clt);
                }
            }
            else
            {
                GATT_TRACE_ERROR0("CCB max out, no rsources");
            }
        }
    }
    else
    {
        gatt_cleanup_upon_disc(bd_addr, reason);
        GATT_TRACE_DEBUG0 ("ATT disconnected");
    }
}