| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "garnet/drivers/bluetooth/lib/l2cap/bredr_command_handler.h" |
| |
| #include <lib/async/cpp/task.h> |
| #include <memory> |
| #include <unordered_map> |
| #include <vector> |
| |
| #include "garnet/drivers/bluetooth/lib/common/test_helpers.h" |
| #include "garnet/drivers/bluetooth/lib/l2cap/fake_signaling_channel.h" |
| #include "lib/gtest/test_loop_fixture.h" |
| |
| namespace btlib { |
| namespace l2cap { |
| namespace internal { |
| namespace { |
| |
| using common::BufferView; |
| using common::ByteBuffer; |
| using common::CreateStaticByteBuffer; |
| using common::LowerBits; |
| using common::UpperBits; |
| |
| constexpr uint16_t kPsm = 0x0001; |
| constexpr ChannelId kLocalCId = 0x0040; |
| constexpr ChannelId kRemoteCId = 0x60a3; |
| |
| class L2CAP_BrEdrCommandHandlerTest : public ::gtest::TestLoopFixture { |
| public: |
| L2CAP_BrEdrCommandHandlerTest() = default; |
| ~L2CAP_BrEdrCommandHandlerTest() override = default; |
| FXL_DISALLOW_COPY_AND_ASSIGN(L2CAP_BrEdrCommandHandlerTest); |
| |
| protected: |
| // TestLoopFixture overrides |
| void SetUp() override { |
| signaling_channel_ = |
| std::make_unique<testing::FakeSignalingChannel>(dispatcher()); |
| command_handler_ = std::make_unique<BrEdrCommandHandler>(fake_sig()); |
| } |
| |
| void TearDown() override { |
| signaling_channel_ = nullptr; |
| command_handler_ = nullptr; |
| } |
| |
| testing::FakeSignalingChannel* fake_sig() const { |
| return signaling_channel_.get(); |
| } |
| BrEdrCommandHandler* cmd_handler() const { return command_handler_.get(); } |
| |
| std::unique_ptr<testing::FakeSignalingChannel> signaling_channel_; |
| std::unique_ptr<BrEdrCommandHandler> command_handler_; |
| }; |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, OutboundConnReqRej) { |
| constexpr ChannelId kBadLocalCId = 0x0005; // Not a dynamic channel |
| |
| // Connection Request payload |
| auto expected_conn_req = CreateStaticByteBuffer( |
| // PSM |
| LowerBits(kPsm), UpperBits(kPsm), |
| |
| // Source CID |
| LowerBits(kBadLocalCId), UpperBits(kBadLocalCId)); |
| |
| // Command Reject payload |
| auto rej_rsp = CreateStaticByteBuffer( |
| // Reject Reason (invalid channel ID) |
| LowerBits(static_cast<uint16_t>(RejectReason::kInvalidCID)), |
| UpperBits(static_cast<uint16_t>(RejectReason::kInvalidCID)), |
| |
| // Local (relative to rejecter) CID |
| LowerBits(kInvalidChannelId), UpperBits(kInvalidChannelId), |
| |
| // Remote (relative to rejecter) CID |
| LowerBits(kBadLocalCId), UpperBits(kBadLocalCId)); |
| fake_sig()->AddOutbound( |
| kConnectionRequest, expected_conn_req.view(), |
| std::make_pair(SignalingChannel::Status::kReject, rej_rsp.view())); |
| |
| bool cb_called = false; |
| auto on_conn_rsp = [&cb_called, kBadLocalCId]( |
| const BrEdrCommandHandler::ConnectionResponse& rsp) { |
| cb_called = true; |
| EXPECT_EQ(BrEdrCommandHandler::Status::kReject, rsp.status()); |
| EXPECT_EQ(kInvalidChannelId, rsp.remote_cid()); |
| EXPECT_EQ(kBadLocalCId, rsp.local_cid()); |
| return false; |
| }; |
| |
| EXPECT_TRUE(cmd_handler()->SendConnectionRequest(kPsm, kBadLocalCId, |
| std::move(on_conn_rsp))); |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(cb_called); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, OutboundConnReqRspOk) { |
| // Connection Request payload |
| auto expected_conn_req = CreateStaticByteBuffer( |
| // PSM |
| LowerBits(kPsm), UpperBits(kPsm), |
| |
| // Source CID |
| LowerBits(kLocalCId), UpperBits(kLocalCId)); |
| |
| // Connection Response payload |
| auto ok_conn_rsp = CreateStaticByteBuffer( |
| // Destination CID |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId), |
| |
| // Source CID |
| LowerBits(kLocalCId), UpperBits(kLocalCId), |
| |
| // Result (Successful) |
| 0x00, 0x00, |
| |
| // Status (No further information available) |
| 0x00, 0x00); |
| fake_sig()->AddOutbound( |
| kConnectionRequest, expected_conn_req.view(), |
| std::make_pair(SignalingChannel::Status::kSuccess, ok_conn_rsp.view())); |
| |
| bool cb_called = false; |
| auto on_conn_rsp = |
| [&cb_called](const BrEdrCommandHandler::ConnectionResponse& rsp) { |
| cb_called = true; |
| EXPECT_EQ(BrEdrCommandHandler::Status::kSuccess, rsp.status()); |
| EXPECT_EQ(kRemoteCId, rsp.remote_cid()); |
| EXPECT_EQ(kLocalCId, rsp.local_cid()); |
| EXPECT_EQ(ConnectionResult::kSuccess, rsp.result()); |
| EXPECT_EQ(ConnectionStatus::kNoInfoAvailable, rsp.conn_status()); |
| return false; |
| }; |
| |
| EXPECT_TRUE(cmd_handler()->SendConnectionRequest(kPsm, kLocalCId, |
| std::move(on_conn_rsp))); |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(cb_called); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, OutboundConnReqRspPendingAuthThenOk) { |
| // Connection Request payload |
| auto expected_conn_req = CreateStaticByteBuffer( |
| // PSM |
| LowerBits(kPsm), UpperBits(kPsm), |
| |
| // Source CID |
| LowerBits(kLocalCId), UpperBits(kLocalCId)); |
| |
| // Connection Response payload |
| auto pend_conn_rsp = CreateStaticByteBuffer( |
| // Destination CID |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId), |
| |
| // Source CID |
| LowerBits(kLocalCId), UpperBits(kLocalCId), |
| |
| // Result (Pending) |
| 0x01, 0x00, |
| |
| // Status (Authorization pending) |
| 0x02, 0x00); |
| |
| auto ok_conn_rsp = CreateStaticByteBuffer( |
| // Destination CID |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId), |
| |
| // Source CID |
| LowerBits(kLocalCId), UpperBits(kLocalCId), |
| |
| // Result (Successful) |
| 0x00, 0x00, |
| |
| // Status (No further information available) |
| 0x00, 0x00); |
| fake_sig()->AddOutbound( |
| kConnectionRequest, expected_conn_req.view(), |
| std::make_pair(SignalingChannel::Status::kSuccess, pend_conn_rsp.view()), |
| std::make_pair(SignalingChannel::Status::kSuccess, ok_conn_rsp.view())); |
| |
| int cb_count = 0; |
| auto on_conn_rsp = |
| [&cb_count](const BrEdrCommandHandler::ConnectionResponse& rsp) { |
| cb_count++; |
| EXPECT_EQ(kRemoteCId, rsp.remote_cid()); |
| EXPECT_EQ(kLocalCId, rsp.local_cid()); |
| if (cb_count == 1) { |
| EXPECT_EQ(BrEdrCommandHandler::Status::kSuccess, rsp.status()); |
| EXPECT_EQ(ConnectionResult::kPending, rsp.result()); |
| EXPECT_EQ(ConnectionStatus::kAuthorizationPending, rsp.conn_status()); |
| return true; |
| } else if (cb_count == 2) { |
| EXPECT_EQ(BrEdrCommandHandler::Status::kSuccess, rsp.status()); |
| EXPECT_EQ(ConnectionResult::kSuccess, rsp.result()); |
| EXPECT_EQ(ConnectionStatus::kNoInfoAvailable, rsp.conn_status()); |
| } |
| return false; |
| }; |
| |
| EXPECT_TRUE(cmd_handler()->SendConnectionRequest(kPsm, kLocalCId, |
| std::move(on_conn_rsp))); |
| RunLoopUntilIdle(); |
| EXPECT_EQ(2, cb_count); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, InboundInfoReqRspNotSupported) { |
| BrEdrCommandHandler::InformationRequestCallback cb = [](InformationType type, |
| auto responder) { |
| EXPECT_EQ(InformationType::kConnectionlessMTU, type); |
| responder->SendNotSupported(); |
| }; |
| cmd_handler()->ServeInformationRequest(std::move(cb)); |
| |
| // Information Request payload |
| auto info_req = CreateStaticByteBuffer( |
| // Type = Connectionless MTU |
| 0x01, 0x00); |
| |
| // Information Response payload |
| auto expected_rsp = CreateStaticByteBuffer( |
| // Type = Connectionless MTU |
| 0x01, 0x00, |
| |
| // Result = Not supported |
| 0x01, 0x00); |
| |
| fake_sig()->ReceiveExpect(kInformationRequest, info_req, expected_rsp); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, InboundInfoReqRspConnlessMtu) { |
| BrEdrCommandHandler::InformationRequestCallback cb = [](InformationType type, |
| auto responder) { |
| EXPECT_EQ(InformationType::kConnectionlessMTU, type); |
| responder->SendConnectionlessMtu(0x02dc); |
| }; |
| cmd_handler()->ServeInformationRequest(std::move(cb)); |
| |
| // Information Request payload |
| auto info_req = CreateStaticByteBuffer( |
| // Type = Connectionless MTU |
| 0x01, 0x00); |
| |
| // Information Response payload |
| auto expected_rsp = CreateStaticByteBuffer( |
| // Type = Connectionless MTU |
| 0x01, 0x00, |
| |
| // Result = Success |
| 0x00, 0x00, |
| |
| // Data (MTU) |
| 0xdc, 0x02); |
| |
| fake_sig()->ReceiveExpect(kInformationRequest, info_req, expected_rsp); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, InboundInfoReqRspExtendedFeatures) { |
| BrEdrCommandHandler::InformationRequestCallback cb = [](InformationType type, |
| auto responder) { |
| EXPECT_EQ(InformationType::kExtendedFeaturesSupported, type); |
| responder->SendExtendedFeaturesSupported(0xfaceb00c); |
| }; |
| cmd_handler()->ServeInformationRequest(std::move(cb)); |
| |
| // Information Request payload |
| auto info_req = CreateStaticByteBuffer( |
| // Type = Features Mask |
| 0x02, 0x00); |
| |
| // Information Response payload |
| auto expected_rsp = CreateStaticByteBuffer( |
| // Type = Features Mask |
| 0x02, 0x00, |
| |
| // Result = Success |
| 0x00, 0x00, |
| |
| // Data (Mask) |
| 0x0c, 0xb0, 0xce, 0xfa); |
| |
| fake_sig()->ReceiveExpect(kInformationRequest, info_req, expected_rsp); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, InboundInfoReqRspFixedChannels) { |
| BrEdrCommandHandler::InformationRequestCallback cb = [](InformationType type, |
| auto responder) { |
| EXPECT_EQ(InformationType::kFixedChannelsSupported, type); |
| responder->SendFixedChannelsSupported(0xcafef00d4badc0deUL); |
| }; |
| cmd_handler()->ServeInformationRequest(std::move(cb)); |
| |
| // Information Request payload |
| auto info_req = CreateStaticByteBuffer( |
| // Type = Fixed Channels |
| 0x03, 0x00); |
| |
| // Configuration Response payload |
| auto expected_rsp = CreateStaticByteBuffer( |
| // Type = Fixed Channels |
| 0x03, 0x00, |
| |
| // Result = Success |
| 0x00, 0x00, |
| |
| // Data (Mask) |
| 0xde, 0xc0, 0xad, 0x4b, 0x0d, 0xf0, 0xfe, 0xca); |
| |
| fake_sig()->ReceiveExpect(kInformationRequest, info_req, expected_rsp); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, InboundConfigReqEmptyRspOkEmpty) { |
| BrEdrCommandHandler::ConfigurationRequestCallback cb = |
| [](ChannelId local_cid, uint16_t flags, auto& data, auto responder) { |
| EXPECT_EQ(kLocalCId, local_cid); |
| EXPECT_EQ(0x6006, flags); |
| EXPECT_EQ(0UL, data.size()); |
| responder->Send(kRemoteCId, 0x0001, ConfigurationResult::kPending, |
| BufferView()); |
| }; |
| cmd_handler()->ServeConfigurationRequest(std::move(cb)); |
| |
| // Configuration Request payload |
| auto config_req = CreateStaticByteBuffer( |
| // Destination Channel ID |
| LowerBits(kLocalCId), UpperBits(kLocalCId), |
| |
| // Flags |
| 0x06, 0x60); |
| |
| // Configuration Response payload |
| auto expected_rsp = CreateStaticByteBuffer( |
| // Destination Channel ID |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId), |
| |
| // Flags |
| 0x01, 0x00, |
| |
| // Result = Pending |
| 0x04, 0x00); |
| |
| fake_sig()->ReceiveExpect(kConfigurationRequest, config_req, expected_rsp); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, OutboundConfigReqRspPendingEmpty) { |
| // Configuration Request payload |
| auto expected_config_req = CreateStaticByteBuffer( |
| // Destination CID |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId), |
| |
| // Flags (non-zero to test encoding) |
| 0x01, 0x00, |
| |
| // Data |
| // TODO(NET-1084): Replace with real configuration options |
| 't', 'e', 's', 't'); |
| const BufferView& req_options = expected_config_req.view(4, 4); |
| |
| // Configuration Response payload |
| auto pending_config_req = CreateStaticByteBuffer( |
| // Source CID |
| LowerBits(kLocalCId), UpperBits(kLocalCId), |
| |
| // Flags (non-zero to test encoding) |
| 0x04, 0x00, |
| |
| // Result = Pending |
| 0x04, 0x00, |
| |
| // Data |
| // TODO(NET-1084): Replace with real configuration options |
| 'l', 'o', 'l', 'z'); |
| const BufferView& rsp_options = pending_config_req.view(6, 4); |
| |
| fake_sig()->AddOutbound(kConfigurationRequest, expected_config_req.view(), |
| std::make_pair(SignalingChannel::Status::kSuccess, |
| pending_config_req.view())); |
| |
| bool cb_called = false; |
| BrEdrCommandHandler::ConfigurationResponseCallback on_config_rsp = |
| [&cb_called, |
| &rsp_options](const BrEdrCommandHandler::ConfigurationResponse& rsp) { |
| cb_called = true; |
| EXPECT_EQ(SignalingChannel::Status::kSuccess, rsp.status()); |
| EXPECT_EQ(kLocalCId, rsp.local_cid()); |
| EXPECT_EQ(0x0004, rsp.flags()); |
| EXPECT_EQ(ConfigurationResult::kPending, rsp.result()); |
| EXPECT_TRUE(common::ContainersEqual(rsp_options, rsp.options())); |
| return false; |
| }; |
| |
| EXPECT_TRUE(cmd_handler()->SendConfigurationRequest( |
| kRemoteCId, 0x0001, req_options, std::move(on_config_rsp))); |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(cb_called); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, OutboundDisconReqRspOk) { |
| // Disconnect Request payload |
| auto expected_discon_req = CreateStaticByteBuffer( |
| // Destination CID |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId), |
| |
| // Source CID |
| LowerBits(kLocalCId), UpperBits(kLocalCId)); |
| |
| // Disconnect Response payload |
| // Channel endpoint roles (source, destination) are relative to requester so |
| // the response's payload should be the same as the request's |
| const ByteBuffer& ok_discon_rsp = expected_discon_req; |
| |
| fake_sig()->AddOutbound( |
| kDisconnectionRequest, expected_discon_req.view(), |
| std::make_pair(SignalingChannel::Status::kSuccess, ok_discon_rsp.view())); |
| |
| bool cb_called = false; |
| BrEdrCommandHandler::DisconnectionResponseCallback on_discon_req = |
| [&cb_called](const BrEdrCommandHandler::DisconnectionResponse& rsp) { |
| cb_called = true; |
| EXPECT_EQ(SignalingChannel::Status::kSuccess, rsp.status()); |
| EXPECT_EQ(kLocalCId, rsp.local_cid()); |
| EXPECT_EQ(kRemoteCId, rsp.remote_cid()); |
| return false; |
| }; |
| |
| EXPECT_TRUE(cmd_handler()->SendDisconnectionRequest( |
| kRemoteCId, kLocalCId, std::move(on_discon_req))); |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(cb_called); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, OutboundDisconReqRej) { |
| // Disconnect Request payload |
| auto expected_discon_req = CreateStaticByteBuffer( |
| // Destination CID (relative to requester) |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId), |
| |
| // Source CID (relative to requester) |
| LowerBits(kLocalCId), UpperBits(kLocalCId)); |
| |
| // Command Reject payload |
| auto rej_cid = CreateStaticByteBuffer( |
| // Reject Reason (invalid channel ID) |
| LowerBits(static_cast<uint16_t>(RejectReason::kInvalidCID)), |
| UpperBits(static_cast<uint16_t>(RejectReason::kInvalidCID)), |
| |
| // Source CID (relative to rejecter) |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId), |
| |
| // Destination CID (relative to rejecter) |
| LowerBits(kLocalCId), UpperBits(kLocalCId)); |
| |
| fake_sig()->AddOutbound( |
| kDisconnectionRequest, expected_discon_req.view(), |
| std::make_pair(SignalingChannel::Status::kReject, rej_cid.view())); |
| |
| bool cb_called = false; |
| BrEdrCommandHandler::DisconnectionResponseCallback on_discon_cb = |
| [&cb_called](const BrEdrCommandHandler::DisconnectionResponse& rsp) { |
| cb_called = true; |
| EXPECT_EQ(SignalingChannel::Status::kReject, rsp.status()); |
| EXPECT_EQ(RejectReason::kInvalidCID, rsp.reject_reason()); |
| EXPECT_EQ(kLocalCId, rsp.local_cid()); |
| EXPECT_EQ(kRemoteCId, rsp.remote_cid()); |
| return false; |
| }; |
| |
| EXPECT_TRUE(cmd_handler()->SendDisconnectionRequest(kRemoteCId, kLocalCId, |
| std::move(on_discon_cb))); |
| RunLoopUntilIdle(); |
| EXPECT_TRUE(cb_called); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, InboundDisconReqRspOk) { |
| BrEdrCommandHandler::DisconnectionRequestCallback cb = |
| [](ChannelId local_cid, ChannelId remote_cid, auto responder) { |
| EXPECT_EQ(kLocalCId, local_cid); |
| EXPECT_EQ(kRemoteCId, remote_cid); |
| responder->Send(); |
| }; |
| cmd_handler()->ServeDisconnectionRequest(std::move(cb)); |
| |
| // Disconnection Request payload |
| auto discon_req = CreateStaticByteBuffer( |
| // Destination CID (relative to requester) |
| LowerBits(kLocalCId), UpperBits(kLocalCId), |
| |
| // Source CID (relative to requester) |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId)); |
| |
| // Disconnection Response payload |
| auto expected_rsp = discon_req; |
| |
| fake_sig()->ReceiveExpect(kDisconnectionRequest, discon_req, expected_rsp); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, InboundDisconReqRej) { |
| BrEdrCommandHandler::DisconnectionRequestCallback cb = |
| [](ChannelId local_cid, ChannelId remote_cid, auto responder) { |
| EXPECT_EQ(kLocalCId, local_cid); |
| EXPECT_EQ(kRemoteCId, remote_cid); |
| responder->RejectInvalidChannelId(); |
| }; |
| cmd_handler()->ServeDisconnectionRequest(std::move(cb)); |
| |
| // Disconnection Request payload |
| auto discon_req = CreateStaticByteBuffer( |
| // Destination CID (relative to requester) |
| LowerBits(kLocalCId), UpperBits(kLocalCId), |
| |
| // Source CID (relative to requester) |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId)); |
| |
| // Disconnection Response payload |
| auto expected_rsp = discon_req; |
| |
| fake_sig()->ReceiveExpectRejectInvalidChannelId( |
| kDisconnectionRequest, discon_req, kLocalCId, kRemoteCId); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, InboundConnReqRspPending) { |
| BrEdrCommandHandler::ConnectionRequestCallback cb = |
| [](PSM psm, ChannelId remote_cid, auto responder) { |
| EXPECT_EQ(kPsm, psm); |
| EXPECT_EQ(kRemoteCId, remote_cid); |
| responder->Send(kLocalCId, ConnectionResult::kPending, |
| ConnectionStatus::kAuthorizationPending); |
| }; |
| cmd_handler()->ServeConnectionRequest(std::move(cb)); |
| |
| // Connection Request payload |
| auto conn_req = CreateStaticByteBuffer( |
| // PSM |
| LowerBits(kPsm), UpperBits(kPsm), |
| |
| // Source CID (relative to requester) |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId)); |
| |
| // Connection Response payload |
| auto conn_rsp = CreateStaticByteBuffer( |
| // Destination CID (relative to requester) |
| LowerBits(kLocalCId), UpperBits(kLocalCId), |
| |
| // Source CID (relative to requester) |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId), |
| |
| // Connection Result |
| LowerBits(static_cast<uint16_t>(ConnectionResult::kPending)), |
| UpperBits(static_cast<uint16_t>(ConnectionResult::kPending)), |
| |
| // Connection Status |
| LowerBits(static_cast<uint16_t>(ConnectionStatus::kAuthorizationPending)), |
| UpperBits( |
| static_cast<uint16_t>(ConnectionStatus::kAuthorizationPending))); |
| |
| fake_sig()->ReceiveExpect(kConnectionRequest, conn_req, conn_rsp); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, InboundConnReqBadPsm) { |
| constexpr uint16_t kBadPsm = 0x0002; |
| |
| // Request callback shouldn't even be called for an invalid PSM. |
| bool req_cb_called = false; |
| BrEdrCommandHandler::ConnectionRequestCallback cb = |
| [&req_cb_called](PSM psm, ChannelId remote_cid, auto responder) { |
| req_cb_called = true; |
| }; |
| cmd_handler()->ServeConnectionRequest(std::move(cb)); |
| |
| // Connection Request payload |
| auto conn_req = CreateStaticByteBuffer( |
| // PSM |
| LowerBits(kBadPsm), UpperBits(kBadPsm), |
| |
| // Source CID (relative to requester) |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId)); |
| |
| // Connection Response payload |
| auto conn_rsp = CreateStaticByteBuffer( |
| // Destination CID (relative to requester) |
| LowerBits(kInvalidChannelId), UpperBits(kInvalidChannelId), |
| |
| // Source CID (relative to requester) |
| LowerBits(kRemoteCId), UpperBits(kRemoteCId), |
| |
| // Connection Result |
| LowerBits(static_cast<uint16_t>(ConnectionResult::kPSMNotSupported)), |
| UpperBits(static_cast<uint16_t>(ConnectionResult::kPSMNotSupported)), |
| |
| // Connection Status |
| LowerBits(static_cast<uint16_t>(ConnectionStatus::kNoInfoAvailable)), |
| UpperBits(static_cast<uint16_t>(ConnectionStatus::kNoInfoAvailable))); |
| |
| fake_sig()->ReceiveExpect(kConnectionRequest, conn_req, conn_rsp); |
| EXPECT_FALSE(req_cb_called); |
| } |
| |
| TEST_F(L2CAP_BrEdrCommandHandlerTest, InboundConnReqNonDynamicSrcCId) { |
| // Request callback shouldn't even be called for an invalid Source Channel ID. |
| bool req_cb_called = false; |
| BrEdrCommandHandler::ConnectionRequestCallback cb = |
| [&req_cb_called](PSM psm, ChannelId remote_cid, auto responder) { |
| req_cb_called = true; |
| }; |
| cmd_handler()->ServeConnectionRequest(std::move(cb)); |
| |
| // Connection Request payload |
| auto conn_req = CreateStaticByteBuffer( |
| // PSM |
| LowerBits(kPsm), UpperBits(kPsm), |
| |
| // Source CID: fixed channel for Security Manager (relative to requester) |
| LowerBits(kSMPChannelId), UpperBits(kSMPChannelId)); |
| |
| // Connection Response payload |
| auto conn_rsp = CreateStaticByteBuffer( |
| // Destination CID (relative to requester) |
| LowerBits(kInvalidChannelId), UpperBits(kInvalidChannelId), |
| |
| // Source CID (relative to requester) |
| LowerBits(kSMPChannelId), UpperBits(kSMPChannelId), |
| |
| // Connection Result |
| LowerBits(static_cast<uint16_t>(ConnectionResult::kInvalidSourceCID)), |
| UpperBits(static_cast<uint16_t>(ConnectionResult::kInvalidSourceCID)), |
| |
| // Connection Status |
| LowerBits(static_cast<uint16_t>(ConnectionStatus::kNoInfoAvailable)), |
| UpperBits(static_cast<uint16_t>(ConnectionStatus::kNoInfoAvailable))); |
| |
| fake_sig()->ReceiveExpect(kConnectionRequest, conn_req, conn_rsp); |
| EXPECT_FALSE(req_cb_called); |
| } |
| |
| } // namespace |
| } // namespace internal |
| } // namespace l2cap |
| } // namespace btlib |