Loading system/gd/l2cap/le/cert/le_l2cap_test.py +11 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,17 @@ class LeL2capTest(GdFacadeOnlyBaseTestClass): dut_channel = response_future.get_channel() return (dut_channel, cert_channel) def test_reject_connection_parameter_update_request(self): """ L2CAP/LE/CPU/BI-02-C """ self._setup_link_from_cert() self.cert_l2cap.get_control_channel().send( l2cap_packets.ConnectionParameterUpdateRequestBuilder( 2, 100, 100, 512, 100)) assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.LeCommandReject()) def test_segmentation(self): """ L2CAP/COS/CFC/BV-01-C Loading system/gd/l2cap/le/internal/link.cc +1 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ void Link::Disconnect() { void Link::UpdateConnectionParameter(SignalId signal_id, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout) { // TODO: If we are slave and both only support legacy update connection parameter, use L2CAP acl_connection_->LeConnectionUpdate( conn_interval_min, conn_interval_max, conn_latency, supervision_timeout, common::BindOnce(&Link::on_connection_update_complete, common::Unretained(this), signal_id), l2cap_handler_); Loading system/gd/l2cap/le/internal/signalling_manager.cc +55 −15 Original line number Diff line number Diff line Loading @@ -56,9 +56,8 @@ LeSignallingManager::~LeSignallingManager() { } void LeSignallingManager::SendConnectionRequest(Psm psm, Cid local_cid, Mtu mtu) { PendingCommand pending_command = { next_signal_id_, LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST, psm, local_cid, {}, mtu, link_->GetMps(), link_->GetInitialCredit()}; PendingCommand pending_command = PendingCommand::CreditBasedConnectionRequest( next_signal_id_, psm, local_cid, mtu, link_->GetMps(), link_->GetInitialCredit()); next_signal_id_++; pending_commands_.push(pending_command); if (pending_commands_.size() == 1) { Loading @@ -66,9 +65,8 @@ void LeSignallingManager::SendConnectionRequest(Psm psm, Cid local_cid, Mtu mtu) } } void LeSignallingManager::SendDisconnectRequest(Cid local_cid, Cid remote_cid) { PendingCommand pending_command = { next_signal_id_, LeCommandCode::DISCONNECTION_REQUEST, {}, local_cid, remote_cid, {}, {}, {}}; void LeSignallingManager::SendDisconnectRequest(Cid scid, Cid dcid) { PendingCommand pending_command = PendingCommand::DisconnectionRequest(next_signal_id_, scid, dcid); next_signal_id_++; pending_commands_.push(pending_command); if (pending_commands_.size() == 1) { Loading @@ -78,7 +76,13 @@ void LeSignallingManager::SendDisconnectRequest(Cid local_cid, Cid remote_cid) { void LeSignallingManager::SendConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier) { LOG_ERROR("Not implemented"); PendingCommand pending_command = PendingCommand::ConnectionParameterUpdate( next_signal_id_, interval_min, interval_max, slave_latency, timeout_multiplier); next_signal_id_++; pending_commands_.push(pending_command); if (pending_commands_.size() == 1) { handle_send_next_command(); } } void LeSignallingManager::SendConnectionParameterUpdateResponse(SignalId signal_id, Loading Loading @@ -113,13 +117,41 @@ void LeSignallingManager::OnCommandReject(LeCommandRejectView command_reject_vie LOG_WARN("Command rejected"); } void LeSignallingManager::OnConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier) { LOG_ERROR("Not implemented"); void LeSignallingManager::OnConnectionParameterUpdateRequest(SignalId signal_id, uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier) { if (link_->GetRole() == hci::Role::SLAVE) { LOG_WARN("Received request from LL master"); auto builder = LeCommandRejectNotUnderstoodBuilder::Create(signal_id.Value()); enqueue_buffer_->Enqueue(std::move(builder), handler_); return; } if (interval_min < 6 || interval_min > 3200 || interval_max < 6 || interval_max > 3200 || slave_latency >= 500 || timeout_multiplier < 10 || timeout_multiplier > 3200) { LOG_WARN("Received invalid connection parameter update request from LL master"); auto builder = ConnectionParameterUpdateResponseBuilder::Create(signal_id.Value(), ConnectionParameterUpdateResponseResult::REJECTED); enqueue_buffer_->Enqueue(std::move(builder), handler_); return; } link_->UpdateConnectionParameter(signal_id, interval_min, interval_max, slave_latency, timeout_multiplier); } void LeSignallingManager::OnConnectionParameterUpdateResponse(ConnectionParameterUpdateResponseResult result) { LOG_ERROR("Not implemented"); void LeSignallingManager::OnConnectionParameterUpdateResponse(SignalId signal_id, ConnectionParameterUpdateResponseResult result) { if (signal_id != command_just_sent_.signal_id_) { LOG_WARN("Unexpected response: no pending request"); return; } if (command_just_sent_.command_code_ != LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST) { LOG_WARN("Unexpected response: no pending request"); return; } alarm_.Cancel(); command_just_sent_.signal_id_ = kInitialSignalId; if (result != ConnectionParameterUpdateResponseResult::ACCEPTED) { LOG_ERROR("Connection parameter update is not accepted"); } } void LeSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid, Mtu mtu, uint16_t mps, Loading Loading @@ -290,8 +322,9 @@ void LeSignallingManager::on_incoming_packet() { return; } OnConnectionParameterUpdateRequest( parameter_update_req_view.GetIntervalMin(), parameter_update_req_view.GetIntervalMax(), parameter_update_req_view.GetSlaveLatency(), parameter_update_req_view.GetTimeoutMultiplier()); parameter_update_req_view.GetIdentifier(), parameter_update_req_view.GetIntervalMin(), parameter_update_req_view.GetIntervalMax(), parameter_update_req_view.GetSlaveLatency(), parameter_update_req_view.GetTimeoutMultiplier()); return; } case LeCommandCode::CONNECTION_PARAMETER_UPDATE_RESPONSE: { Loading @@ -300,7 +333,8 @@ void LeSignallingManager::on_incoming_packet() { if (!parameter_update_rsp_view.IsValid()) { return; } OnConnectionParameterUpdateResponse(parameter_update_rsp_view.GetResult()); OnConnectionParameterUpdateResponse(parameter_update_rsp_view.GetIdentifier(), parameter_update_rsp_view.GetResult()); return; } case LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST: { Loading Loading @@ -411,6 +445,12 @@ void LeSignallingManager::handle_send_next_command() { alarm_.Schedule(common::BindOnce(&LeSignallingManager::on_command_timeout, common::Unretained(this)), kTimeout); break; } case LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST: { auto builder = ConnectionParameterUpdateRequestBuilder::Create(command_just_sent_.signal_id_.Value(), 0, 0, 0, 0); enqueue_buffer_->Enqueue(std::move(builder), handler_); alarm_.Schedule(common::BindOnce(&LeSignallingManager::on_command_timeout, common::Unretained(this)), kTimeout); break; } default: { LOG_WARN("Unsupported command code 0x%x", static_cast<int>(command_just_sent_.command_code_)); } Loading system/gd/l2cap/le/internal/signalling_manager.h +42 −3 Original line number Diff line number Diff line Loading @@ -49,6 +49,44 @@ struct PendingCommand { Mtu mtu_; uint16_t mps_; uint16_t credits_; uint16_t interval_min_; uint16_t interval_max_; uint16_t slave_latency_; uint16_t timeout_multiplier_; static PendingCommand CreditBasedConnectionRequest(SignalId signal_id, Psm psm, Cid scid, Mtu mtu, uint16_t mps, uint16_t initial_credits) { PendingCommand pending_command; pending_command.signal_id_ = signal_id; pending_command.command_code_ = LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST; pending_command.psm_ = psm; pending_command.source_cid_ = scid; pending_command.mtu_ = mtu; pending_command.mps_ = mps; pending_command.credits_ = initial_credits; return pending_command; } static PendingCommand DisconnectionRequest(SignalId signal_id, Cid scid, Cid dcid) { PendingCommand pending_command; pending_command.signal_id_ = signal_id; pending_command.command_code_ = LeCommandCode::DISCONNECTION_REQUEST; pending_command.source_cid_ = scid; pending_command.destination_cid_ = dcid; return pending_command; } static PendingCommand ConnectionParameterUpdate(SignalId signal_id, uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier) { PendingCommand pending_command; pending_command.signal_id_ = signal_id; pending_command.command_code_ = LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST; pending_command.interval_min_ = interval_min; pending_command.interval_max_ = interval_max; pending_command.slave_latency_ = slave_latency; pending_command.timeout_multiplier_ = timeout_multiplier; return pending_command; } }; class Link; Loading @@ -65,6 +103,7 @@ class LeSignallingManager { void SendDisconnectRequest(Cid local_cid, Cid remote_cid); // Note: Since Core 4.1, LL slave can send this through HCI command. void SendConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier); Loading @@ -76,9 +115,9 @@ class LeSignallingManager { void OnCommandReject(LeCommandRejectView command_reject_view); void OnConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier); void OnConnectionParameterUpdateResponse(ConnectionParameterUpdateResponseResult result); void OnConnectionParameterUpdateRequest(SignalId signal_id, uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier); void OnConnectionParameterUpdateResponse(SignalId signal_id, ConnectionParameterUpdateResponseResult result); void OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid, Mtu mtu, uint16_t mps, uint16_t initial_credits); Loading Loading
system/gd/l2cap/le/cert/le_l2cap_test.py +11 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,17 @@ class LeL2capTest(GdFacadeOnlyBaseTestClass): dut_channel = response_future.get_channel() return (dut_channel, cert_channel) def test_reject_connection_parameter_update_request(self): """ L2CAP/LE/CPU/BI-02-C """ self._setup_link_from_cert() self.cert_l2cap.get_control_channel().send( l2cap_packets.ConnectionParameterUpdateRequestBuilder( 2, 100, 100, 512, 100)) assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.LeCommandReject()) def test_segmentation(self): """ L2CAP/COS/CFC/BV-01-C Loading
system/gd/l2cap/le/internal/link.cc +1 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,7 @@ void Link::Disconnect() { void Link::UpdateConnectionParameter(SignalId signal_id, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout) { // TODO: If we are slave and both only support legacy update connection parameter, use L2CAP acl_connection_->LeConnectionUpdate( conn_interval_min, conn_interval_max, conn_latency, supervision_timeout, common::BindOnce(&Link::on_connection_update_complete, common::Unretained(this), signal_id), l2cap_handler_); Loading
system/gd/l2cap/le/internal/signalling_manager.cc +55 −15 Original line number Diff line number Diff line Loading @@ -56,9 +56,8 @@ LeSignallingManager::~LeSignallingManager() { } void LeSignallingManager::SendConnectionRequest(Psm psm, Cid local_cid, Mtu mtu) { PendingCommand pending_command = { next_signal_id_, LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST, psm, local_cid, {}, mtu, link_->GetMps(), link_->GetInitialCredit()}; PendingCommand pending_command = PendingCommand::CreditBasedConnectionRequest( next_signal_id_, psm, local_cid, mtu, link_->GetMps(), link_->GetInitialCredit()); next_signal_id_++; pending_commands_.push(pending_command); if (pending_commands_.size() == 1) { Loading @@ -66,9 +65,8 @@ void LeSignallingManager::SendConnectionRequest(Psm psm, Cid local_cid, Mtu mtu) } } void LeSignallingManager::SendDisconnectRequest(Cid local_cid, Cid remote_cid) { PendingCommand pending_command = { next_signal_id_, LeCommandCode::DISCONNECTION_REQUEST, {}, local_cid, remote_cid, {}, {}, {}}; void LeSignallingManager::SendDisconnectRequest(Cid scid, Cid dcid) { PendingCommand pending_command = PendingCommand::DisconnectionRequest(next_signal_id_, scid, dcid); next_signal_id_++; pending_commands_.push(pending_command); if (pending_commands_.size() == 1) { Loading @@ -78,7 +76,13 @@ void LeSignallingManager::SendDisconnectRequest(Cid local_cid, Cid remote_cid) { void LeSignallingManager::SendConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier) { LOG_ERROR("Not implemented"); PendingCommand pending_command = PendingCommand::ConnectionParameterUpdate( next_signal_id_, interval_min, interval_max, slave_latency, timeout_multiplier); next_signal_id_++; pending_commands_.push(pending_command); if (pending_commands_.size() == 1) { handle_send_next_command(); } } void LeSignallingManager::SendConnectionParameterUpdateResponse(SignalId signal_id, Loading Loading @@ -113,13 +117,41 @@ void LeSignallingManager::OnCommandReject(LeCommandRejectView command_reject_vie LOG_WARN("Command rejected"); } void LeSignallingManager::OnConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier) { LOG_ERROR("Not implemented"); void LeSignallingManager::OnConnectionParameterUpdateRequest(SignalId signal_id, uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier) { if (link_->GetRole() == hci::Role::SLAVE) { LOG_WARN("Received request from LL master"); auto builder = LeCommandRejectNotUnderstoodBuilder::Create(signal_id.Value()); enqueue_buffer_->Enqueue(std::move(builder), handler_); return; } if (interval_min < 6 || interval_min > 3200 || interval_max < 6 || interval_max > 3200 || slave_latency >= 500 || timeout_multiplier < 10 || timeout_multiplier > 3200) { LOG_WARN("Received invalid connection parameter update request from LL master"); auto builder = ConnectionParameterUpdateResponseBuilder::Create(signal_id.Value(), ConnectionParameterUpdateResponseResult::REJECTED); enqueue_buffer_->Enqueue(std::move(builder), handler_); return; } link_->UpdateConnectionParameter(signal_id, interval_min, interval_max, slave_latency, timeout_multiplier); } void LeSignallingManager::OnConnectionParameterUpdateResponse(ConnectionParameterUpdateResponseResult result) { LOG_ERROR("Not implemented"); void LeSignallingManager::OnConnectionParameterUpdateResponse(SignalId signal_id, ConnectionParameterUpdateResponseResult result) { if (signal_id != command_just_sent_.signal_id_) { LOG_WARN("Unexpected response: no pending request"); return; } if (command_just_sent_.command_code_ != LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST) { LOG_WARN("Unexpected response: no pending request"); return; } alarm_.Cancel(); command_just_sent_.signal_id_ = kInitialSignalId; if (result != ConnectionParameterUpdateResponseResult::ACCEPTED) { LOG_ERROR("Connection parameter update is not accepted"); } } void LeSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid, Mtu mtu, uint16_t mps, Loading Loading @@ -290,8 +322,9 @@ void LeSignallingManager::on_incoming_packet() { return; } OnConnectionParameterUpdateRequest( parameter_update_req_view.GetIntervalMin(), parameter_update_req_view.GetIntervalMax(), parameter_update_req_view.GetSlaveLatency(), parameter_update_req_view.GetTimeoutMultiplier()); parameter_update_req_view.GetIdentifier(), parameter_update_req_view.GetIntervalMin(), parameter_update_req_view.GetIntervalMax(), parameter_update_req_view.GetSlaveLatency(), parameter_update_req_view.GetTimeoutMultiplier()); return; } case LeCommandCode::CONNECTION_PARAMETER_UPDATE_RESPONSE: { Loading @@ -300,7 +333,8 @@ void LeSignallingManager::on_incoming_packet() { if (!parameter_update_rsp_view.IsValid()) { return; } OnConnectionParameterUpdateResponse(parameter_update_rsp_view.GetResult()); OnConnectionParameterUpdateResponse(parameter_update_rsp_view.GetIdentifier(), parameter_update_rsp_view.GetResult()); return; } case LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST: { Loading Loading @@ -411,6 +445,12 @@ void LeSignallingManager::handle_send_next_command() { alarm_.Schedule(common::BindOnce(&LeSignallingManager::on_command_timeout, common::Unretained(this)), kTimeout); break; } case LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST: { auto builder = ConnectionParameterUpdateRequestBuilder::Create(command_just_sent_.signal_id_.Value(), 0, 0, 0, 0); enqueue_buffer_->Enqueue(std::move(builder), handler_); alarm_.Schedule(common::BindOnce(&LeSignallingManager::on_command_timeout, common::Unretained(this)), kTimeout); break; } default: { LOG_WARN("Unsupported command code 0x%x", static_cast<int>(command_just_sent_.command_code_)); } Loading
system/gd/l2cap/le/internal/signalling_manager.h +42 −3 Original line number Diff line number Diff line Loading @@ -49,6 +49,44 @@ struct PendingCommand { Mtu mtu_; uint16_t mps_; uint16_t credits_; uint16_t interval_min_; uint16_t interval_max_; uint16_t slave_latency_; uint16_t timeout_multiplier_; static PendingCommand CreditBasedConnectionRequest(SignalId signal_id, Psm psm, Cid scid, Mtu mtu, uint16_t mps, uint16_t initial_credits) { PendingCommand pending_command; pending_command.signal_id_ = signal_id; pending_command.command_code_ = LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST; pending_command.psm_ = psm; pending_command.source_cid_ = scid; pending_command.mtu_ = mtu; pending_command.mps_ = mps; pending_command.credits_ = initial_credits; return pending_command; } static PendingCommand DisconnectionRequest(SignalId signal_id, Cid scid, Cid dcid) { PendingCommand pending_command; pending_command.signal_id_ = signal_id; pending_command.command_code_ = LeCommandCode::DISCONNECTION_REQUEST; pending_command.source_cid_ = scid; pending_command.destination_cid_ = dcid; return pending_command; } static PendingCommand ConnectionParameterUpdate(SignalId signal_id, uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier) { PendingCommand pending_command; pending_command.signal_id_ = signal_id; pending_command.command_code_ = LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST; pending_command.interval_min_ = interval_min; pending_command.interval_max_ = interval_max; pending_command.slave_latency_ = slave_latency; pending_command.timeout_multiplier_ = timeout_multiplier; return pending_command; } }; class Link; Loading @@ -65,6 +103,7 @@ class LeSignallingManager { void SendDisconnectRequest(Cid local_cid, Cid remote_cid); // Note: Since Core 4.1, LL slave can send this through HCI command. void SendConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier); Loading @@ -76,9 +115,9 @@ class LeSignallingManager { void OnCommandReject(LeCommandRejectView command_reject_view); void OnConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier); void OnConnectionParameterUpdateResponse(ConnectionParameterUpdateResponseResult result); void OnConnectionParameterUpdateRequest(SignalId signal_id, uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency, uint16_t timeout_multiplier); void OnConnectionParameterUpdateResponse(SignalId signal_id, ConnectionParameterUpdateResponseResult result); void OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid, Mtu mtu, uint16_t mps, uint16_t initial_credits); Loading