/*******************************************************************************
*
* 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;
VLOG(1) << __func__;
gatt_cb = tGATT_CB();
memset(&fixed_reg, 0, sizeof(tL2CAP_FIXED_CHNL_REG));
gatt_cb.def_mtu_size = GATT_DEF_BLE_MTU_SIZE;
gatt_cb.sign_op_queue = fixed_queue_new(SIZE_MAX);
gatt_cb.srv_chg_clt_q = fixed_queue_new(SIZE_MAX);
/* 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.pL2CA_FixedCong_Cb = gatt_le_cong_cback; /* congestion callback */
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)) {
LOG(ERROR) << "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_cb.hdl_list_info = new std::list<tGATT_HDL_LIST_ELEM>();
gatt_cb.srv_list_info = new std::list<tGATT_SRV_LIST_ELEM>();
gatt_profile_db_init();
}
fixed_reg.pL2CA_FixedData_Cb = gatt_le_data_ind;
/*******************************************************************************
*
* 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(uint16_t chan, const RawAddress& bd_addr,
BT_HDR* p_buf) {
tGATT_TCB* p_tcb;
/* Find CCB based on bd addr */
if ((p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE)) != NULL) {
if (gatt_get_ch_state(p_tcb) < GATT_CH_OPEN) {
LOG(WARNING) << "ATT - Ignored L2CAP data while in state: "
<< +gatt_get_ch_state(p_tcb);
} else
gatt_data_process(*p_tcb, p_buf);
}
osi_free(p_buf);
}
/*******************************************************************************
*
* 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& tcb, BT_HDR* p_buf) {
uint8_t* p = (uint8_t*)(p_buf + 1) + p_buf->offset; // 取buffer指针
uint8_t op_code, pseudo_op_code;
if (p_buf->len <= 0) { // p_buf->len是buffer的长度
LOG(ERROR) << "invalid data length, ignore";
return;
}
uint16_t msg_len = p_buf->len - 1; // 消息长度
STREAM_TO_UINT8(op_code, p); // 取buffer的第一个8位作为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) {
LOG(ERROR) << "ATT - Rcvd L2CAP data, unknown cmd: 0x" << std::hex
<< op_code;
return;
}
if (op_code == GATT_SIGN_CMD_WRITE) {
gatt_verify_signature(tcb, p_buf);
} else {
/* message from client */
if ((op_code % 2) == 0)
// OP_CODE = GATT_REQ_READ_BY_TYPE 0x08
// 所以会走入这个分支
gatt_server_handle_client_req(tcb, op_code, msg_len, p);
else
gatt_client_handle_server_rsp(tcb, op_code, msg_len, p);
}
}
/** This function is called to handle the client requests to server */
void gatt_server_handle_client_req(tGATT_TCB& tcb, uint8_t op_code,
uint16_t len, uint8_t* p_data) {
/* there is pending command, discard this one */
if (!gatt_sr_cmd_empty(tcb) && op_code != GATT_HANDLE_VALUE_CONF) return;
/* the size of the message may not be bigger than the local max PDU size*/
/* The message has to be smaller than the agreed MTU, len does not include op
* code */
if (len >= tcb.payload_size) {
LOG(ERROR) << StringPrintf("server receive invalid PDU size:%d pdu size:%d",
len + 1, tcb.payload_size);
/* for invalid request expecting response, send it now */
if (op_code != GATT_CMD_WRITE && op_code != GATT_SIGN_CMD_WRITE &&
op_code != GATT_HANDLE_VALUE_CONF) {
gatt_send_error_rsp(tcb, GATT_INVALID_PDU, op_code, 0, false);
}
/* otherwise, ignore the pkt */
} else {
switch (op_code) {
case GATT_REQ_READ_BY_GRP_TYPE: /* discover primary services */
case GATT_REQ_FIND_TYPE_VALUE: /* discover service by UUID */
gatts_process_primary_service_req(tcb, op_code, len, p_data);
break;
case GATT_REQ_FIND_INFO: /* discover char descrptor */
gatts_process_find_info(tcb, op_code, len, p_data);
break;
// switch判断,走入这个分支
case GATT_REQ_READ_BY_TYPE: /* read characteristic value, char descriptor value */
/* discover characteristic, discover char by UUID */
gatts_process_read_by_type_req(tcb, op_code, len, p_data);
break;