Loading system/bta/gatt/bta_gattc_act.cc +58 −14 Original line number Diff line number Diff line Loading @@ -62,10 +62,6 @@ static void bta_gattc_conn_cback(tGATT_IF gattc_if, const RawAddress& bda, static void bta_gattc_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE* p_data); static void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE* p_data); static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB* p_clreg); static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, const RawAddress& bda); static void bta_gattc_cong_cback(uint16_t conn_id, bool congested); Loading Loading @@ -742,6 +738,42 @@ void bta_gattc_restart_discover(tBTA_GATTC_CLCB* p_clcb, /** Configure MTU size on the GATT connection */ void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) { uint16_t current_mtu = 0; auto result = GATTC_TryMtuRequest(p_clcb->bda, p_clcb->transport, p_clcb->bta_conn_id, ¤t_mtu); switch (result) { case MTU_EXCHANGE_DEVICE_DISCONNECTED: LOG_INFO("Device %s disconnected", ADDRESS_TO_LOGGABLE_CSTR(p_clcb->bda)); bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, GATT_NO_RESOURCES, NULL); bta_gattc_continue(p_clcb); return; case MTU_EXCHANGE_NOT_ALLOWED: LOG_INFO("Not allowed for BR/EDR devices %s", ADDRESS_TO_LOGGABLE_CSTR(p_clcb->bda)); bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, GATT_ERR_UNLIKELY, NULL); bta_gattc_continue(p_clcb); return; case MTU_EXCHANGE_ALREADY_DONE: /* Check if MTU is not already set, if so, just report it back to the user * and continue with other requests. */ GATTC_UpdateUserAttMtuIfNeeded(p_clcb->bda, p_clcb->transport, p_data->api_mtu.mtu); bta_gattc_send_mtu_response(p_clcb, p_data, current_mtu); return; case MTU_EXCHANGE_IN_PROGRESS: LOG_INFO("Enqueue MTU Request - waiting for response on p_clcb %p", p_clcb); bta_gattc_enqueue(p_clcb, p_data); return; case MTU_EXCHANGE_NOT_DONE_YET: /* OK to proceed */ break; } if (bta_gattc_enqueue(p_clcb, p_data) == ENQUEUED_FOR_LATER) return; tGATT_STATUS status = Loading Loading @@ -1171,18 +1203,31 @@ void bta_gattc_op_cmpl(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) { } /* service handle change void the response, discard it */ if (op == GATTC_OPTYPE_READ) if (op == GATTC_OPTYPE_READ) { bta_gattc_read_cmpl(p_clcb, &p_data->op_cmpl); else if (op == GATTC_OPTYPE_WRITE) } else if (op == GATTC_OPTYPE_WRITE) { bta_gattc_write_cmpl(p_clcb, &p_data->op_cmpl); else if (op == GATTC_OPTYPE_EXE_WRITE) } else if (op == GATTC_OPTYPE_EXE_WRITE) { bta_gattc_exec_cmpl(p_clcb, &p_data->op_cmpl); else if (op == GATTC_OPTYPE_CONFIG) } else if (op == GATTC_OPTYPE_CONFIG) { bta_gattc_cfg_mtu_cmpl(p_clcb, &p_data->op_cmpl); /* If there are more clients waiting for the MTU results on the same device, * lets trigger them now. */ auto outstanding_conn_ids = GATTC_GetAndRemoveListOfConnIdsWaitingForMtuRequest(p_clcb->bda); for (auto conn_id : outstanding_conn_ids) { tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); LOG_DEBUG("Continue MTU request clcb %p", p_clcb); if (p_clcb) { LOG_DEBUG("Continue MTU request for client conn_id=0x%04x", conn_id); bta_gattc_continue(p_clcb); } } } // If receive DATABASE_OUT_OF_SYNC error code, bta_gattc should start service // discovery immediately if (bta_gattc_is_robust_caching_enabled() && Loading Loading @@ -1542,9 +1587,8 @@ static void bta_gattc_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op, } /** client operation complete send message */ static void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE* p_data) { void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE* p_data) { const size_t len = sizeof(tBTA_GATTC_OP_CMPL) + sizeof(tGATT_CL_COMPLETE); tBTA_GATTC_OP_CMPL* p_buf = (tBTA_GATTC_OP_CMPL*)osi_calloc(len); Loading system/bta/gatt/bta_gattc_int.h +6 −0 Original line number Diff line number Diff line Loading @@ -445,6 +445,12 @@ extern BtaEnqueuedResult_t bta_gattc_enqueue(tBTA_GATTC_CLCB* p_clcb, extern bool bta_gattc_is_data_queued(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data); extern void bta_gattc_continue(tBTA_GATTC_CLCB* p_clcb); extern void bta_gattc_send_mtu_response(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data, uint16_t current_mtu); extern void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE* p_data); extern bool bta_gattc_check_notif_registry(tBTA_GATTC_RCB* p_clreg, tBTA_GATTC_SERV* p_srcb, Loading system/bta/gatt/bta_gattc_utils.cc +63 −7 Original line number Diff line number Diff line Loading @@ -359,6 +359,27 @@ tBTA_GATTC_SERV* bta_gattc_srcb_alloc(const RawAddress& bda) { return p_tcb; } void bta_gattc_send_mtu_response(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data, uint16_t current_mtu) { GATT_CONFIGURE_MTU_OP_CB cb = p_data->api_mtu.mtu_cb; if (cb) { void* my_cb_data = p_data->api_mtu.mtu_cb_data; cb(p_clcb->bta_conn_id, GATT_SUCCESS, my_cb_data); } tBTA_GATTC cb_data; p_clcb->status = GATT_SUCCESS; cb_data.cfg_mtu.conn_id = p_clcb->bta_conn_id; cb_data.cfg_mtu.status = GATT_SUCCESS; cb_data.cfg_mtu.mtu = current_mtu; if (p_clcb->p_rcb) { (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CFG_MTU_EVT, &cb_data); } } void bta_gattc_continue(tBTA_GATTC_CLCB* p_clcb) { if (p_clcb->p_q_cmd != NULL) { LOG_INFO("Already scheduled another request for conn_id = 0x%04x", Loading @@ -366,14 +387,49 @@ void bta_gattc_continue(tBTA_GATTC_CLCB* p_clcb) { return; } if (p_clcb->p_q_cmd_queue.empty()) { LOG_INFO("Nothing to do for conn_id = 0x%04x", p_clcb->bta_conn_id); while (!p_clcb->p_q_cmd_queue.empty()) { const tBTA_GATTC_DATA* p_q_cmd = p_clcb->p_q_cmd_queue.front(); if (p_q_cmd->hdr.event != BTA_GATTC_API_CFG_MTU_EVT) { p_clcb->p_q_cmd_queue.pop_front(); bta_gattc_sm_execute(p_clcb, p_q_cmd->hdr.event, p_q_cmd); return; } const tBTA_GATTC_DATA* p_q_cmd = p_clcb->p_q_cmd_queue.front(); /* The p_q_cmd is the MTU Request event. */ uint16_t current_mtu = 0; auto result = GATTC_TryMtuRequest(p_clcb->bda, p_clcb->transport, p_clcb->bta_conn_id, ¤t_mtu); switch (result) { case MTU_EXCHANGE_DEVICE_DISCONNECTED: bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, GATT_NO_RESOURCES, NULL); /* Handled, free command below and continue with a p_q_cmd_queue */ break; case MTU_EXCHANGE_NOT_ALLOWED: bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, GATT_ERR_UNLIKELY, NULL); /* Handled, free command below and continue with a p_q_cmd_queue */ break; case MTU_EXCHANGE_ALREADY_DONE: bta_gattc_send_mtu_response(p_clcb, p_q_cmd, current_mtu); /* Handled, free command below and continue with a p_q_cmd_queue */ break; case MTU_EXCHANGE_IN_PROGRESS: LOG_WARN("Waiting p_clcb %p", p_clcb); return; case MTU_EXCHANGE_NOT_DONE_YET: p_clcb->p_q_cmd_queue.pop_front(); bta_gattc_sm_execute(p_clcb, p_q_cmd->hdr.event, p_q_cmd); return; } /* p_q_cmd was the MTU request and it was handled. * If MTU request was handled without actually ATT request, * it is ok to take another message from the queue and proceed. */ p_clcb->p_q_cmd_queue.pop_front(); osi_free_and_reset((void**)&p_q_cmd); } } bool bta_gattc_is_data_queued(tBTA_GATTC_CLCB* p_clcb, Loading system/stack/gatt/gatt_api.cc +133 −4 Original line number Diff line number Diff line Loading @@ -713,15 +713,144 @@ tGATT_STATUS GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu) { /* For this request only ATT CID is valid */ p_clcb->cid = L2CAP_ATT_CID; p_clcb->p_tcb->payload_size = mtu; p_clcb->operation = GATTC_OPTYPE_CONFIG; tGATT_CL_MSG gatt_cl_msg; gatt_cl_msg.mtu = mtu; LOG_DEBUG("Configuring ATT mtu size conn_id:%hu mtu:%hu", conn_id, mtu); bluetooth::shim::arbiter::GetArbiter().OnOutgoingMtuReq(tcb_idx); return attp_send_cl_msg(*p_clcb->p_tcb, p_clcb, GATT_REQ_MTU, &gatt_cl_msg); /* Since GATT MTU Exchange can be done only once, and it is impossible to * predict what MTU will be requested by other applications, let's use * max possible MTU in the request. */ gatt_cl_msg.mtu = GATT_MAX_MTU_SIZE; LOG_INFO("Configuring ATT mtu size conn_id:%hu mtu:%hu user mtu %hu", conn_id, gatt_cl_msg.mtu, mtu); auto result = attp_send_cl_msg(*p_clcb->p_tcb, p_clcb, GATT_REQ_MTU, &gatt_cl_msg); if (result == GATT_SUCCESS) { p_clcb->p_tcb->pending_user_mtu_exchange_value = mtu; } return result; } /****************************************************************************** * * Function GATTC_TryMtuRequest * * Description This function shall be called before calling * GATTC_ConfgureMTU in order to check if operation is * available to do. * * Parameters remote_bda : peer device address. (input) * transport : physical transport of the GATT connection * (BR/EDR or LE) (input) * conn_id : connection id (input) * current_mtu: current mtu on the link (output) * * Returns tGATTC_TryMtuRequestResult: * - MTU_EXCHANGE_NOT_DONE_YET: There was no MTU Exchange * procedure on the link. User can call GATTC_ConfigureMTU * now. * - MTU_EXCHANGE_NOT_ALLOWED : Not allowed for BR/EDR or if * link does not exist * - MTU_EXCHANGE_ALREADY_DONE: MTU Exchange is done. MTU * should be taken from current_mtu * - MTU_EXCHANGE_IN_PROGRESS : Other use is doing MTU * Exchange. Conn_id is stored for result. * ******************************************************************************/ tGATTC_TryMtuRequestResult GATTC_TryMtuRequest(const RawAddress& remote_bda, tBT_TRANSPORT transport, uint16_t conn_id, uint16_t* current_mtu) { LOG_INFO("%s conn_id=0x%04x", remote_bda.ToString().c_str(), conn_id); *current_mtu = GATT_DEF_BLE_MTU_SIZE; if (transport == BT_TRANSPORT_BR_EDR) { LOG_ERROR("Device %s connected over BR/EDR", ADDRESS_TO_LOGGABLE_CSTR(remote_bda)); return MTU_EXCHANGE_NOT_ALLOWED; } tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(remote_bda, transport); if (!p_tcb) { LOG_ERROR("Device %s is not connected ", ADDRESS_TO_LOGGABLE_CSTR(remote_bda)); return MTU_EXCHANGE_DEVICE_DISCONNECTED; } if (gatt_is_pending_mtu_exchange(p_tcb)) { LOG_DEBUG("Continue MTU pending for other client."); /* MTU Exchange is in progress, started by other GATT Client. * Wait until it is completed. */ gatt_set_conn_id_waiting_for_mtu_exchange(p_tcb, conn_id); return MTU_EXCHANGE_IN_PROGRESS; } uint16_t mtu = gatt_get_mtu(remote_bda, transport); if (mtu == GATT_DEF_BLE_MTU_SIZE || mtu == 0) { LOG_DEBUG("MTU not yet updated for %s", ADDRESS_TO_LOGGABLE_CSTR(remote_bda)); return MTU_EXCHANGE_NOT_DONE_YET; } *current_mtu = mtu; return MTU_EXCHANGE_ALREADY_DONE; } /******************************************************************************* * Function GATTC_UpdateUserAttMtuIfNeeded * * Description This function to be called when user requested MTU after * MTU Exchange has been already done. This will update data * length in the controller. * * Parameters remote_bda : peer device address. (input) * transport : physical transport of the GATT connection * (BR/EDR or LE) (input) * user_mtu: user request mtu * ******************************************************************************/ void GATTC_UpdateUserAttMtuIfNeeded(const RawAddress& remote_bda, tBT_TRANSPORT transport, uint16_t user_mtu) { LOG_INFO("%s, mtu=%hu", ADDRESS_TO_LOGGABLE_CSTR(remote_bda), user_mtu); tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(remote_bda, transport); if (!p_tcb) { LOG_WARN("Transport control block not found"); return; } LOG_INFO("%s, current mtu: %d, max_user_mtu:%d, user_mtu: %d", ADDRESS_TO_LOGGABLE_CSTR(remote_bda), p_tcb->payload_size, p_tcb->max_user_mtu, user_mtu); if (p_tcb->payload_size < user_mtu) { LOG_INFO("User requested more than what GATT can handle. Trim it."); user_mtu = p_tcb->payload_size; } if (p_tcb->max_user_mtu >= user_mtu) { return; } p_tcb->max_user_mtu = user_mtu; BTM_SetBleDataLength(remote_bda, user_mtu); } std::list<uint16_t> GATTC_GetAndRemoveListOfConnIdsWaitingForMtuRequest( const RawAddress& remote_bda) { std::list result = std::list<uint16_t>(); tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(remote_bda, BT_TRANSPORT_LE); if (!p_tcb || p_tcb->conn_ids_waiting_for_mtu_exchange.empty()) { return result; } result.swap(p_tcb->conn_ids_waiting_for_mtu_exchange); return result; } /******************************************************************************* Loading system/stack/gatt/gatt_cl.cc +24 −6 Original line number Diff line number Diff line Loading @@ -1099,14 +1099,32 @@ void gatt_process_mtu_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, uint16_t len, } else { STREAM_TO_UINT16(mtu, p_data); if (mtu < tcb.payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE) tcb.payload_size = mtu; LOG_INFO("Local pending MTU %d, Remote (%s) MTU %d", tcb.pending_user_mtu_exchange_value, tcb.peer_bda.ToString().c_str(), mtu); /* Aim for MAX as we did in the request */ if (mtu < GATT_DEF_BLE_MTU_SIZE) { tcb.payload_size = GATT_DEF_BLE_MTU_SIZE; } else { tcb.payload_size = std::min(mtu, (uint16_t)(GATT_MAX_MTU_SIZE)); } bluetooth::shim::arbiter::GetArbiter().OnIncomingMtuResp(tcb.tcb_idx, tcb.payload_size); BTM_SetBleDataLength(tcb.peer_bda, tcb.payload_size + L2CAP_PKT_OVERHEAD); /* This is just to track the biggest MTU requested by the user. * This value will be used in the BTM_SetBleDataLength */ if (tcb.pending_user_mtu_exchange_value > tcb.max_user_mtu) { tcb.max_user_mtu = std::min(tcb.pending_user_mtu_exchange_value, tcb.payload_size); } tcb.pending_user_mtu_exchange_value = 0; LOG_INFO("MTU Exchange resulted in: %d", tcb.payload_size); BTM_SetBleDataLength(tcb.peer_bda, tcb.max_user_mtu + L2CAP_PKT_OVERHEAD); } gatt_end_operation(p_clcb, status, NULL); } Loading Loading
system/bta/gatt/bta_gattc_act.cc +58 −14 Original line number Diff line number Diff line Loading @@ -62,10 +62,6 @@ static void bta_gattc_conn_cback(tGATT_IF gattc_if, const RawAddress& bda, static void bta_gattc_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE* p_data); static void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE* p_data); static void bta_gattc_deregister_cmpl(tBTA_GATTC_RCB* p_clreg); static void bta_gattc_enc_cmpl_cback(tGATT_IF gattc_if, const RawAddress& bda); static void bta_gattc_cong_cback(uint16_t conn_id, bool congested); Loading Loading @@ -742,6 +738,42 @@ void bta_gattc_restart_discover(tBTA_GATTC_CLCB* p_clcb, /** Configure MTU size on the GATT connection */ void bta_gattc_cfg_mtu(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) { uint16_t current_mtu = 0; auto result = GATTC_TryMtuRequest(p_clcb->bda, p_clcb->transport, p_clcb->bta_conn_id, ¤t_mtu); switch (result) { case MTU_EXCHANGE_DEVICE_DISCONNECTED: LOG_INFO("Device %s disconnected", ADDRESS_TO_LOGGABLE_CSTR(p_clcb->bda)); bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, GATT_NO_RESOURCES, NULL); bta_gattc_continue(p_clcb); return; case MTU_EXCHANGE_NOT_ALLOWED: LOG_INFO("Not allowed for BR/EDR devices %s", ADDRESS_TO_LOGGABLE_CSTR(p_clcb->bda)); bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, GATT_ERR_UNLIKELY, NULL); bta_gattc_continue(p_clcb); return; case MTU_EXCHANGE_ALREADY_DONE: /* Check if MTU is not already set, if so, just report it back to the user * and continue with other requests. */ GATTC_UpdateUserAttMtuIfNeeded(p_clcb->bda, p_clcb->transport, p_data->api_mtu.mtu); bta_gattc_send_mtu_response(p_clcb, p_data, current_mtu); return; case MTU_EXCHANGE_IN_PROGRESS: LOG_INFO("Enqueue MTU Request - waiting for response on p_clcb %p", p_clcb); bta_gattc_enqueue(p_clcb, p_data); return; case MTU_EXCHANGE_NOT_DONE_YET: /* OK to proceed */ break; } if (bta_gattc_enqueue(p_clcb, p_data) == ENQUEUED_FOR_LATER) return; tGATT_STATUS status = Loading Loading @@ -1171,18 +1203,31 @@ void bta_gattc_op_cmpl(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data) { } /* service handle change void the response, discard it */ if (op == GATTC_OPTYPE_READ) if (op == GATTC_OPTYPE_READ) { bta_gattc_read_cmpl(p_clcb, &p_data->op_cmpl); else if (op == GATTC_OPTYPE_WRITE) } else if (op == GATTC_OPTYPE_WRITE) { bta_gattc_write_cmpl(p_clcb, &p_data->op_cmpl); else if (op == GATTC_OPTYPE_EXE_WRITE) } else if (op == GATTC_OPTYPE_EXE_WRITE) { bta_gattc_exec_cmpl(p_clcb, &p_data->op_cmpl); else if (op == GATTC_OPTYPE_CONFIG) } else if (op == GATTC_OPTYPE_CONFIG) { bta_gattc_cfg_mtu_cmpl(p_clcb, &p_data->op_cmpl); /* If there are more clients waiting for the MTU results on the same device, * lets trigger them now. */ auto outstanding_conn_ids = GATTC_GetAndRemoveListOfConnIdsWaitingForMtuRequest(p_clcb->bda); for (auto conn_id : outstanding_conn_ids) { tBTA_GATTC_CLCB* p_clcb = bta_gattc_find_clcb_by_conn_id(conn_id); LOG_DEBUG("Continue MTU request clcb %p", p_clcb); if (p_clcb) { LOG_DEBUG("Continue MTU request for client conn_id=0x%04x", conn_id); bta_gattc_continue(p_clcb); } } } // If receive DATABASE_OUT_OF_SYNC error code, bta_gattc should start service // discovery immediately if (bta_gattc_is_robust_caching_enabled() && Loading Loading @@ -1542,9 +1587,8 @@ static void bta_gattc_cmpl_cback(uint16_t conn_id, tGATTC_OPTYPE op, } /** client operation complete send message */ static void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE* p_data) { void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE* p_data) { const size_t len = sizeof(tBTA_GATTC_OP_CMPL) + sizeof(tGATT_CL_COMPLETE); tBTA_GATTC_OP_CMPL* p_buf = (tBTA_GATTC_OP_CMPL*)osi_calloc(len); Loading
system/bta/gatt/bta_gattc_int.h +6 −0 Original line number Diff line number Diff line Loading @@ -445,6 +445,12 @@ extern BtaEnqueuedResult_t bta_gattc_enqueue(tBTA_GATTC_CLCB* p_clcb, extern bool bta_gattc_is_data_queued(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data); extern void bta_gattc_continue(tBTA_GATTC_CLCB* p_clcb); extern void bta_gattc_send_mtu_response(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data, uint16_t current_mtu); extern void bta_gattc_cmpl_sendmsg(uint16_t conn_id, tGATTC_OPTYPE op, tGATT_STATUS status, tGATT_CL_COMPLETE* p_data); extern bool bta_gattc_check_notif_registry(tBTA_GATTC_RCB* p_clreg, tBTA_GATTC_SERV* p_srcb, Loading
system/bta/gatt/bta_gattc_utils.cc +63 −7 Original line number Diff line number Diff line Loading @@ -359,6 +359,27 @@ tBTA_GATTC_SERV* bta_gattc_srcb_alloc(const RawAddress& bda) { return p_tcb; } void bta_gattc_send_mtu_response(tBTA_GATTC_CLCB* p_clcb, const tBTA_GATTC_DATA* p_data, uint16_t current_mtu) { GATT_CONFIGURE_MTU_OP_CB cb = p_data->api_mtu.mtu_cb; if (cb) { void* my_cb_data = p_data->api_mtu.mtu_cb_data; cb(p_clcb->bta_conn_id, GATT_SUCCESS, my_cb_data); } tBTA_GATTC cb_data; p_clcb->status = GATT_SUCCESS; cb_data.cfg_mtu.conn_id = p_clcb->bta_conn_id; cb_data.cfg_mtu.status = GATT_SUCCESS; cb_data.cfg_mtu.mtu = current_mtu; if (p_clcb->p_rcb) { (*p_clcb->p_rcb->p_cback)(BTA_GATTC_CFG_MTU_EVT, &cb_data); } } void bta_gattc_continue(tBTA_GATTC_CLCB* p_clcb) { if (p_clcb->p_q_cmd != NULL) { LOG_INFO("Already scheduled another request for conn_id = 0x%04x", Loading @@ -366,14 +387,49 @@ void bta_gattc_continue(tBTA_GATTC_CLCB* p_clcb) { return; } if (p_clcb->p_q_cmd_queue.empty()) { LOG_INFO("Nothing to do for conn_id = 0x%04x", p_clcb->bta_conn_id); while (!p_clcb->p_q_cmd_queue.empty()) { const tBTA_GATTC_DATA* p_q_cmd = p_clcb->p_q_cmd_queue.front(); if (p_q_cmd->hdr.event != BTA_GATTC_API_CFG_MTU_EVT) { p_clcb->p_q_cmd_queue.pop_front(); bta_gattc_sm_execute(p_clcb, p_q_cmd->hdr.event, p_q_cmd); return; } const tBTA_GATTC_DATA* p_q_cmd = p_clcb->p_q_cmd_queue.front(); /* The p_q_cmd is the MTU Request event. */ uint16_t current_mtu = 0; auto result = GATTC_TryMtuRequest(p_clcb->bda, p_clcb->transport, p_clcb->bta_conn_id, ¤t_mtu); switch (result) { case MTU_EXCHANGE_DEVICE_DISCONNECTED: bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, GATT_NO_RESOURCES, NULL); /* Handled, free command below and continue with a p_q_cmd_queue */ break; case MTU_EXCHANGE_NOT_ALLOWED: bta_gattc_cmpl_sendmsg(p_clcb->bta_conn_id, GATTC_OPTYPE_CONFIG, GATT_ERR_UNLIKELY, NULL); /* Handled, free command below and continue with a p_q_cmd_queue */ break; case MTU_EXCHANGE_ALREADY_DONE: bta_gattc_send_mtu_response(p_clcb, p_q_cmd, current_mtu); /* Handled, free command below and continue with a p_q_cmd_queue */ break; case MTU_EXCHANGE_IN_PROGRESS: LOG_WARN("Waiting p_clcb %p", p_clcb); return; case MTU_EXCHANGE_NOT_DONE_YET: p_clcb->p_q_cmd_queue.pop_front(); bta_gattc_sm_execute(p_clcb, p_q_cmd->hdr.event, p_q_cmd); return; } /* p_q_cmd was the MTU request and it was handled. * If MTU request was handled without actually ATT request, * it is ok to take another message from the queue and proceed. */ p_clcb->p_q_cmd_queue.pop_front(); osi_free_and_reset((void**)&p_q_cmd); } } bool bta_gattc_is_data_queued(tBTA_GATTC_CLCB* p_clcb, Loading
system/stack/gatt/gatt_api.cc +133 −4 Original line number Diff line number Diff line Loading @@ -713,15 +713,144 @@ tGATT_STATUS GATTC_ConfigureMTU(uint16_t conn_id, uint16_t mtu) { /* For this request only ATT CID is valid */ p_clcb->cid = L2CAP_ATT_CID; p_clcb->p_tcb->payload_size = mtu; p_clcb->operation = GATTC_OPTYPE_CONFIG; tGATT_CL_MSG gatt_cl_msg; gatt_cl_msg.mtu = mtu; LOG_DEBUG("Configuring ATT mtu size conn_id:%hu mtu:%hu", conn_id, mtu); bluetooth::shim::arbiter::GetArbiter().OnOutgoingMtuReq(tcb_idx); return attp_send_cl_msg(*p_clcb->p_tcb, p_clcb, GATT_REQ_MTU, &gatt_cl_msg); /* Since GATT MTU Exchange can be done only once, and it is impossible to * predict what MTU will be requested by other applications, let's use * max possible MTU in the request. */ gatt_cl_msg.mtu = GATT_MAX_MTU_SIZE; LOG_INFO("Configuring ATT mtu size conn_id:%hu mtu:%hu user mtu %hu", conn_id, gatt_cl_msg.mtu, mtu); auto result = attp_send_cl_msg(*p_clcb->p_tcb, p_clcb, GATT_REQ_MTU, &gatt_cl_msg); if (result == GATT_SUCCESS) { p_clcb->p_tcb->pending_user_mtu_exchange_value = mtu; } return result; } /****************************************************************************** * * Function GATTC_TryMtuRequest * * Description This function shall be called before calling * GATTC_ConfgureMTU in order to check if operation is * available to do. * * Parameters remote_bda : peer device address. (input) * transport : physical transport of the GATT connection * (BR/EDR or LE) (input) * conn_id : connection id (input) * current_mtu: current mtu on the link (output) * * Returns tGATTC_TryMtuRequestResult: * - MTU_EXCHANGE_NOT_DONE_YET: There was no MTU Exchange * procedure on the link. User can call GATTC_ConfigureMTU * now. * - MTU_EXCHANGE_NOT_ALLOWED : Not allowed for BR/EDR or if * link does not exist * - MTU_EXCHANGE_ALREADY_DONE: MTU Exchange is done. MTU * should be taken from current_mtu * - MTU_EXCHANGE_IN_PROGRESS : Other use is doing MTU * Exchange. Conn_id is stored for result. * ******************************************************************************/ tGATTC_TryMtuRequestResult GATTC_TryMtuRequest(const RawAddress& remote_bda, tBT_TRANSPORT transport, uint16_t conn_id, uint16_t* current_mtu) { LOG_INFO("%s conn_id=0x%04x", remote_bda.ToString().c_str(), conn_id); *current_mtu = GATT_DEF_BLE_MTU_SIZE; if (transport == BT_TRANSPORT_BR_EDR) { LOG_ERROR("Device %s connected over BR/EDR", ADDRESS_TO_LOGGABLE_CSTR(remote_bda)); return MTU_EXCHANGE_NOT_ALLOWED; } tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(remote_bda, transport); if (!p_tcb) { LOG_ERROR("Device %s is not connected ", ADDRESS_TO_LOGGABLE_CSTR(remote_bda)); return MTU_EXCHANGE_DEVICE_DISCONNECTED; } if (gatt_is_pending_mtu_exchange(p_tcb)) { LOG_DEBUG("Continue MTU pending for other client."); /* MTU Exchange is in progress, started by other GATT Client. * Wait until it is completed. */ gatt_set_conn_id_waiting_for_mtu_exchange(p_tcb, conn_id); return MTU_EXCHANGE_IN_PROGRESS; } uint16_t mtu = gatt_get_mtu(remote_bda, transport); if (mtu == GATT_DEF_BLE_MTU_SIZE || mtu == 0) { LOG_DEBUG("MTU not yet updated for %s", ADDRESS_TO_LOGGABLE_CSTR(remote_bda)); return MTU_EXCHANGE_NOT_DONE_YET; } *current_mtu = mtu; return MTU_EXCHANGE_ALREADY_DONE; } /******************************************************************************* * Function GATTC_UpdateUserAttMtuIfNeeded * * Description This function to be called when user requested MTU after * MTU Exchange has been already done. This will update data * length in the controller. * * Parameters remote_bda : peer device address. (input) * transport : physical transport of the GATT connection * (BR/EDR or LE) (input) * user_mtu: user request mtu * ******************************************************************************/ void GATTC_UpdateUserAttMtuIfNeeded(const RawAddress& remote_bda, tBT_TRANSPORT transport, uint16_t user_mtu) { LOG_INFO("%s, mtu=%hu", ADDRESS_TO_LOGGABLE_CSTR(remote_bda), user_mtu); tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(remote_bda, transport); if (!p_tcb) { LOG_WARN("Transport control block not found"); return; } LOG_INFO("%s, current mtu: %d, max_user_mtu:%d, user_mtu: %d", ADDRESS_TO_LOGGABLE_CSTR(remote_bda), p_tcb->payload_size, p_tcb->max_user_mtu, user_mtu); if (p_tcb->payload_size < user_mtu) { LOG_INFO("User requested more than what GATT can handle. Trim it."); user_mtu = p_tcb->payload_size; } if (p_tcb->max_user_mtu >= user_mtu) { return; } p_tcb->max_user_mtu = user_mtu; BTM_SetBleDataLength(remote_bda, user_mtu); } std::list<uint16_t> GATTC_GetAndRemoveListOfConnIdsWaitingForMtuRequest( const RawAddress& remote_bda) { std::list result = std::list<uint16_t>(); tGATT_TCB* p_tcb = gatt_find_tcb_by_addr(remote_bda, BT_TRANSPORT_LE); if (!p_tcb || p_tcb->conn_ids_waiting_for_mtu_exchange.empty()) { return result; } result.swap(p_tcb->conn_ids_waiting_for_mtu_exchange); return result; } /******************************************************************************* Loading
system/stack/gatt/gatt_cl.cc +24 −6 Original line number Diff line number Diff line Loading @@ -1099,14 +1099,32 @@ void gatt_process_mtu_rsp(tGATT_TCB& tcb, tGATT_CLCB* p_clcb, uint16_t len, } else { STREAM_TO_UINT16(mtu, p_data); if (mtu < tcb.payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE) tcb.payload_size = mtu; LOG_INFO("Local pending MTU %d, Remote (%s) MTU %d", tcb.pending_user_mtu_exchange_value, tcb.peer_bda.ToString().c_str(), mtu); /* Aim for MAX as we did in the request */ if (mtu < GATT_DEF_BLE_MTU_SIZE) { tcb.payload_size = GATT_DEF_BLE_MTU_SIZE; } else { tcb.payload_size = std::min(mtu, (uint16_t)(GATT_MAX_MTU_SIZE)); } bluetooth::shim::arbiter::GetArbiter().OnIncomingMtuResp(tcb.tcb_idx, tcb.payload_size); BTM_SetBleDataLength(tcb.peer_bda, tcb.payload_size + L2CAP_PKT_OVERHEAD); /* This is just to track the biggest MTU requested by the user. * This value will be used in the BTM_SetBleDataLength */ if (tcb.pending_user_mtu_exchange_value > tcb.max_user_mtu) { tcb.max_user_mtu = std::min(tcb.pending_user_mtu_exchange_value, tcb.payload_size); } tcb.pending_user_mtu_exchange_value = 0; LOG_INFO("MTU Exchange resulted in: %d", tcb.payload_size); BTM_SetBleDataLength(tcb.peer_bda, tcb.max_user_mtu + L2CAP_PKT_OVERHEAD); } gatt_end_operation(p_clcb, status, NULL); } Loading