Loading system/gd/l2cap/classic/cert/api.proto +19 −2 Original line number Diff line number Diff line Loading @@ -9,10 +9,13 @@ service L2capModuleCert { rpc SendL2capPacket(L2capPacket) returns (google.protobuf.Empty) {} rpc FetchL2capData(facade.EventStreamRequest) returns (stream L2capPacket) {} rpc FetchConnectionComplete(facade.EventStreamRequest) returns (stream ConnectionCompleteEvent) {} rpc SetOnIncomingConnectionRequest(SetOnIncomingConnectionRequestRequest) returns (SetOnIncomingConnectionRequestResponse) {} rpc DisconnectLink(DisconnectLinkRequest) returns (google.protobuf.Empty) {} rpc SendConnectionRequest(ConnectionRequest) returns (google.protobuf.Empty) {} rpc SendConfigurationRequest(ConfigurationRequest) returns (SendConfigurationRequestResult) {} rpc SendDisconnectionRequest(DisconnectionRequest) returns (google.protobuf.Empty) {} rpc FetchOpenedChannels(FetchOpenedChannelsRequest) returns (FetchOpenedChannelsResponse) {} } message L2capPacket { Loading @@ -25,17 +28,25 @@ message ConnectionCompleteEvent { facade.BluetoothAddress remote = 1; } message SetOnIncomingConnectionRequestRequest { bool accept = 1; } message SetOnIncomingConnectionRequestResponse {} message DisconnectLinkRequest { facade.BluetoothAddress remote = 1; } message ConnectionRequest { facade.BluetoothAddress remote = 1; uint32 dcid = 2; uint32 psm = 2; uint32 scid = 3; } message ConfigurationRequest {} message ConfigurationRequest { uint32 scid = 1; } message SendConfigurationRequestResult {} Loading @@ -44,3 +55,9 @@ message DisconnectionRequest { uint32 dcid = 2; uint32 scid = 3; } message FetchOpenedChannelsRequest {} message FetchOpenedChannelsResponse { repeated uint32 cid = 1; } No newline at end of file system/gd/l2cap/classic/cert/cert.cc +79 −3 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include "grpc/grpc_event_stream.h" #include "hci/acl_manager.h" #include "hci/cert/cert.h" #include "hci/hci_packets.h" #include "l2cap/classic/cert/api.grpc.pb.h" #include "l2cap/classic/l2cap_classic_module.h" #include "l2cap/l2cap_packets.h" Loading Loading @@ -74,6 +75,16 @@ class L2capModuleCertService : public L2capModuleCert::Service { return connection_complete_stream_.HandleRequest(context, request, writer); } ::grpc::Status SetOnIncomingConnectionRequest( ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::SetOnIncomingConnectionRequestRequest* request, ::bluetooth::l2cap::classic::cert::SetOnIncomingConnectionRequestResponse* response) override { accept_incoming_connection_ = request->accept(); return ::grpc::Status::OK; } bool accept_incoming_connection_ = true; ::grpc::Status SendL2capPacket(::grpc::ServerContext* context, const L2capPacket* request, ::google::protobuf::Empty* response) override { std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>(); Loading @@ -90,7 +101,7 @@ class L2capModuleCertService : public L2capModuleCert::Service { ::grpc::Status SendConnectionRequest(::grpc::ServerContext* context, const cert::ConnectionRequest* request, ::google::protobuf::Empty* response) override { auto builder = ConnectionRequestBuilder::Create(1, 1, 101); auto builder = ConnectionRequestBuilder::Create(1, 1, request->scid()); auto l2cap_builder = BasicFrameBuilder::Create(1, std::move(builder)); outgoing_packet_queue_.push(std::move(l2cap_builder)); if (outgoing_packet_queue_.size() == 1) { Loading @@ -104,7 +115,7 @@ class L2capModuleCertService : public L2capModuleCert::Service { ::grpc::Status SendConfigurationRequest( ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::ConfigurationRequest* request, ::bluetooth::l2cap::classic::cert::SendConfigurationRequestResult* response) override { auto builder = ConfigurationRequestBuilder::Create(1, 0x40, Continuation::END, {}); auto builder = ConfigurationRequestBuilder::Create(1, request->scid(), Continuation::END, {}); auto l2cap_builder = BasicFrameBuilder::Create(1, std::move(builder)); outgoing_packet_queue_.push(std::move(l2cap_builder)); if (outgoing_packet_queue_.size() == 1) { Loading @@ -127,6 +138,14 @@ class L2capModuleCertService : public L2capModuleCert::Service { return ::grpc::Status::OK; } ::grpc::Status FetchOpenedChannels( ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::FetchOpenedChannelsRequest* request, ::bluetooth::l2cap::classic::cert::FetchOpenedChannelsResponse* response) override { response->mutable_cid()->Add(open_channels_.begin(), open_channels_.end()); return ::grpc::Status::OK; } std::vector<uint16_t> open_channels_; std::unique_ptr<packet::BasePacketBuilder> enqueue_packet_to_acl() { auto basic_frame_builder = std::move(outgoing_packet_queue_.front()); outgoing_packet_queue_.pop(); Loading Loading @@ -159,6 +178,58 @@ class L2capModuleCertService : public L2capModuleCert::Service { l2cap_packet.set_payload(data); l2cap_packet.set_channel(basic_frame_view.GetChannelId()); l2cap_stream_.OnIncomingEvent(l2cap_packet); if (basic_frame_view.GetChannelId() == kClassicSignallingCid) { ControlView control_view = ControlView::Create(basic_frame_view.GetPayload()); ASSERT(control_view.IsValid()); handle_signalling_packet(control_view); } } void handle_signalling_packet(ControlView control_view) { auto code = control_view.GetCode(); switch (code) { case CommandCode::CONNECTION_REQUEST: { ConnectionRequestView view = ConnectionRequestView::Create(control_view); ASSERT(view.IsValid()); open_channels_.push_back(view.GetSourceCid()); auto builder = ConnectionResponseBuilder::Create( view.GetIdentifier(), view.GetSourceCid(), view.GetSourceCid(), accept_incoming_connection_ ? ConnectionResponseResult::SUCCESS : ConnectionResponseResult::INVALID_CID, ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE); auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder)); outgoing_packet_queue_.push(std::move(l2cap_builder)); if (outgoing_packet_queue_.size() == 1) { acl_connection_->GetAclQueueEnd()->RegisterEnqueue( handler_, common::Bind(&L2capModuleCertService::enqueue_packet_to_acl, common::Unretained(this))); } break; } case CommandCode::CONNECTION_RESPONSE: { ConnectionResponseView view = ConnectionResponseView::Create(control_view); ASSERT(view.IsValid()); open_channels_.push_back(view.GetSourceCid()); break; } case CommandCode::CONFIGURATION_REQUEST: { ConfigurationRequestView view = ConfigurationRequestView::Create(control_view); ASSERT(view.IsValid()); auto builder = ConfigurationResponseBuilder::Create(view.GetIdentifier(), view.GetDestinationCid(), Continuation::END, ConfigurationResponseResult::SUCCESS, {}); auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder)); outgoing_packet_queue_.push(std::move(l2cap_builder)); if (outgoing_packet_queue_.size() == 1) { acl_connection_->GetAclQueueEnd()->RegisterEnqueue( handler_, common::Bind(&L2capModuleCertService::enqueue_packet_to_acl, common::Unretained(this))); } break; } default: return; } } std::queue<std::unique_ptr<BasePacketBuilder>> outgoing_packet_queue_; Loading @@ -177,12 +248,17 @@ class L2capModuleCertService : public L2capModuleCert::Service { module_->acl_connection_->RegisterDisconnectCallback(common::BindOnce([](hci::ErrorCode) {}), module_->handler_); module_->acl_connection_->GetAclQueueEnd()->RegisterDequeue( module_->handler_, common::Bind(&L2capModuleCertService::on_incoming_packet, common::Unretained(module_))); dequeue_registered_ = true; } void OnConnectFail(hci::Address address, hci::ErrorCode reason) override {} ~AclCallbacks() { if (dequeue_registered_) { module_->acl_connection_->GetAclQueueEnd()->UnregisterDequeue(); } } bool dequeue_registered_ = false; L2capModuleCertService* module_; } acl_callbacks{this}; Loading system/gd/l2cap/classic/cert/simple_l2cap_test.py +24 −3 Original line number Diff line number Diff line Loading @@ -84,12 +84,15 @@ class SimpleL2capTest(GdBaseTestClass): ) dut_connection_stream.unsubscribe() self.cert_device.l2cap.SendConnectionRequest(l2cap_cert_pb2.ConnectionRequest()) self.cert_device.l2cap.SendConnectionRequest(l2cap_cert_pb2.ConnectionRequest(scid=0x101)) time.sleep(1) open_channels = self.cert_device.l2cap.FetchOpenedChannels(l2cap_cert_pb2.FetchOpenedChannelsRequest()) cid = open_channels.cid[0] dut_packet_stream.subscribe() cert_packet_stream.subscribe() self.cert_device.l2cap.SendConfigurationRequest(l2cap_cert_pb2.ConfigurationRequest()) self.cert_device.l2cap.SendConfigurationRequest(l2cap_cert_pb2.ConfigurationRequest(scid=cid)) self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=2, payload=b"abc")) dut_packet_stream.assert_event_occurs( Loading @@ -100,7 +103,7 @@ class SimpleL2capTest(GdBaseTestClass): lambda packet: b"123" in packet.payload ) self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=64, payload=b"123")) self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=cid, payload=b"123")) dut_packet_stream.assert_event_occurs( lambda packet: b"123" in packet.payload ) Loading @@ -114,3 +117,21 @@ class SimpleL2capTest(GdBaseTestClass): time.sleep(1) dut_packet_stream.unsubscribe() cert_packet_stream.unsubscribe() def test_basic_operation_request_connection(self): """ L2CAP/COS/CED/BV-01-C [Request Connection] Verify that the IUT is able to request the connection establishment for an L2CAP data channel and initiate the configuration procedure. """ self.device_under_test.l2cap.RegisterChannel(l2cap_facade_pb2.RegisterChannelRequest(channel=2)) cert_connection_stream = self.cert_device.l2cap.connection_complete_stream cert_connection_stream.subscribe() self.device_under_test.l2cap.Connect(self.cert_address) cert_connection_stream.assert_event_occurs( lambda device: device.remote == self.dut_address ) cert_connection_stream.unsubscribe() self.device_under_test.l2cap.OpenChannel(l2cap_facade_pb2.OpenChannelRequest(remote=self.cert_address, psm=0x01)) time.sleep(1) system/gd/l2cap/classic/facade.cc +20 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,18 @@ class L2capModuleFacadeService : public L2capModuleFacade::Service { return ::grpc::Status::OK; } ::grpc::Status OpenChannel(::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::OpenChannelRequest* request, ::google::protobuf::Empty* response) override { auto psm = request->psm(); dynamic_channel_helper_map_.emplace( psm, std::make_unique<L2capDynamicChannelHelper>(this, l2cap_layer_, facade_handler_, psm)); hci::Address peer; ASSERT(hci::Address::FromString(request->remote().address(), peer)); dynamic_channel_helper_map_[psm]->Connect(peer); return ::grpc::Status::OK; } ::grpc::Status FetchL2capData(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request, ::grpc::ServerWriter<classic::L2capPacket>* writer) override { return l2cap_stream_.HandleRequest(context, request, writer); Loading Loading @@ -189,6 +201,12 @@ class L2capModuleFacadeService : public L2capModuleFacade::Service { common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)), handler_); } void Connect(hci::Address address) { dynamic_channel_manager_->ConnectChannel( address, psm_, common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)), common::Bind(&L2capDynamicChannelHelper::on_connect_fail, common::Unretained(this)), handler_); } void on_l2cap_service_registration_complete(DynamicChannelManager::RegistrationResult registration_result, std::unique_ptr<DynamicChannelService> service) {} Loading @@ -199,6 +217,8 @@ class L2capModuleFacadeService : public L2capModuleFacade::Service { channel_ = std::move(channel); } void on_connect_fail(DynamicChannelManager::ConnectionResult result) {} void on_incoming_packet() { auto packet = channel_->GetQueueUpEnd()->TryDequeue(); std::string data = std::string(packet->begin(), packet->end()); Loading system/gd/l2cap/classic/internal/dynamic_channel_allocator.cc +35 −1 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateChannel(Psm } Cid cid = kFirstDynamicChannel; for (; cid <= kLastDynamicChannel; cid++) { if (channels_.find(cid) == channels_.end()) break; if (used_cid_.find(cid) == used_cid_.end()) break; } if (cid > kLastDynamicChannel) { LOG_WARN("All cid are used"); Loading @@ -51,9 +51,42 @@ std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateChannel(Psm link_->GetDevice().ToString().c_str()); ASSERT(elem.first->second != nullptr); used_remote_cid_.insert(remote_cid); used_cid_.insert(cid); return elem.first->second; } std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateReservedChannel(Cid reserved_cid, Psm psm, Cid remote_cid, SecurityPolicy security_policy) { ASSERT_LOG(!IsPsmUsed((psm)), "Psm 0x%x for device %s is already in use", psm, link_->GetDevice().ToString().c_str()); ASSERT_LOG(IsPsmValid(psm), "Psm 0x%x is invalid", psm); if (used_remote_cid_.find(remote_cid) != used_remote_cid_.end()) { LOG_INFO("Remote cid 0x%x is used", remote_cid); return nullptr; } auto elem = channels_.try_emplace( reserved_cid, std::make_shared<DynamicChannelImpl>(psm, reserved_cid, remote_cid, link_, l2cap_handler_)); ASSERT_LOG(elem.second, "Failed to create channel for psm 0x%x device %s", psm, link_->GetDevice().ToString().c_str()); ASSERT(elem.first->second != nullptr); used_remote_cid_.insert(remote_cid); return elem.first->second; } Cid DynamicChannelAllocator::ReserveChannel() { Cid cid = kFirstDynamicChannel; for (; cid <= kLastDynamicChannel; cid++) { if (used_cid_.find(cid) == used_cid_.end()) break; } if (cid > kLastDynamicChannel) { LOG_WARN("All cid are used"); return kInvalidCid; } used_cid_.insert(cid); return cid; } void DynamicChannelAllocator::FreeChannel(Cid cid) { auto channel = FindChannelByCid(cid); if (channel == nullptr) { Loading @@ -62,6 +95,7 @@ void DynamicChannelAllocator::FreeChannel(Cid cid) { } used_remote_cid_.erase(channel->GetRemoteCid()); channels_.erase(cid); used_cid_.erase(cid); } bool DynamicChannelAllocator::IsPsmUsed(Psm psm) const { Loading Loading
system/gd/l2cap/classic/cert/api.proto +19 −2 Original line number Diff line number Diff line Loading @@ -9,10 +9,13 @@ service L2capModuleCert { rpc SendL2capPacket(L2capPacket) returns (google.protobuf.Empty) {} rpc FetchL2capData(facade.EventStreamRequest) returns (stream L2capPacket) {} rpc FetchConnectionComplete(facade.EventStreamRequest) returns (stream ConnectionCompleteEvent) {} rpc SetOnIncomingConnectionRequest(SetOnIncomingConnectionRequestRequest) returns (SetOnIncomingConnectionRequestResponse) {} rpc DisconnectLink(DisconnectLinkRequest) returns (google.protobuf.Empty) {} rpc SendConnectionRequest(ConnectionRequest) returns (google.protobuf.Empty) {} rpc SendConfigurationRequest(ConfigurationRequest) returns (SendConfigurationRequestResult) {} rpc SendDisconnectionRequest(DisconnectionRequest) returns (google.protobuf.Empty) {} rpc FetchOpenedChannels(FetchOpenedChannelsRequest) returns (FetchOpenedChannelsResponse) {} } message L2capPacket { Loading @@ -25,17 +28,25 @@ message ConnectionCompleteEvent { facade.BluetoothAddress remote = 1; } message SetOnIncomingConnectionRequestRequest { bool accept = 1; } message SetOnIncomingConnectionRequestResponse {} message DisconnectLinkRequest { facade.BluetoothAddress remote = 1; } message ConnectionRequest { facade.BluetoothAddress remote = 1; uint32 dcid = 2; uint32 psm = 2; uint32 scid = 3; } message ConfigurationRequest {} message ConfigurationRequest { uint32 scid = 1; } message SendConfigurationRequestResult {} Loading @@ -44,3 +55,9 @@ message DisconnectionRequest { uint32 dcid = 2; uint32 scid = 3; } message FetchOpenedChannelsRequest {} message FetchOpenedChannelsResponse { repeated uint32 cid = 1; } No newline at end of file
system/gd/l2cap/classic/cert/cert.cc +79 −3 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ #include "grpc/grpc_event_stream.h" #include "hci/acl_manager.h" #include "hci/cert/cert.h" #include "hci/hci_packets.h" #include "l2cap/classic/cert/api.grpc.pb.h" #include "l2cap/classic/l2cap_classic_module.h" #include "l2cap/l2cap_packets.h" Loading Loading @@ -74,6 +75,16 @@ class L2capModuleCertService : public L2capModuleCert::Service { return connection_complete_stream_.HandleRequest(context, request, writer); } ::grpc::Status SetOnIncomingConnectionRequest( ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::SetOnIncomingConnectionRequestRequest* request, ::bluetooth::l2cap::classic::cert::SetOnIncomingConnectionRequestResponse* response) override { accept_incoming_connection_ = request->accept(); return ::grpc::Status::OK; } bool accept_incoming_connection_ = true; ::grpc::Status SendL2capPacket(::grpc::ServerContext* context, const L2capPacket* request, ::google::protobuf::Empty* response) override { std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>(); Loading @@ -90,7 +101,7 @@ class L2capModuleCertService : public L2capModuleCert::Service { ::grpc::Status SendConnectionRequest(::grpc::ServerContext* context, const cert::ConnectionRequest* request, ::google::protobuf::Empty* response) override { auto builder = ConnectionRequestBuilder::Create(1, 1, 101); auto builder = ConnectionRequestBuilder::Create(1, 1, request->scid()); auto l2cap_builder = BasicFrameBuilder::Create(1, std::move(builder)); outgoing_packet_queue_.push(std::move(l2cap_builder)); if (outgoing_packet_queue_.size() == 1) { Loading @@ -104,7 +115,7 @@ class L2capModuleCertService : public L2capModuleCert::Service { ::grpc::Status SendConfigurationRequest( ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::ConfigurationRequest* request, ::bluetooth::l2cap::classic::cert::SendConfigurationRequestResult* response) override { auto builder = ConfigurationRequestBuilder::Create(1, 0x40, Continuation::END, {}); auto builder = ConfigurationRequestBuilder::Create(1, request->scid(), Continuation::END, {}); auto l2cap_builder = BasicFrameBuilder::Create(1, std::move(builder)); outgoing_packet_queue_.push(std::move(l2cap_builder)); if (outgoing_packet_queue_.size() == 1) { Loading @@ -127,6 +138,14 @@ class L2capModuleCertService : public L2capModuleCert::Service { return ::grpc::Status::OK; } ::grpc::Status FetchOpenedChannels( ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::FetchOpenedChannelsRequest* request, ::bluetooth::l2cap::classic::cert::FetchOpenedChannelsResponse* response) override { response->mutable_cid()->Add(open_channels_.begin(), open_channels_.end()); return ::grpc::Status::OK; } std::vector<uint16_t> open_channels_; std::unique_ptr<packet::BasePacketBuilder> enqueue_packet_to_acl() { auto basic_frame_builder = std::move(outgoing_packet_queue_.front()); outgoing_packet_queue_.pop(); Loading Loading @@ -159,6 +178,58 @@ class L2capModuleCertService : public L2capModuleCert::Service { l2cap_packet.set_payload(data); l2cap_packet.set_channel(basic_frame_view.GetChannelId()); l2cap_stream_.OnIncomingEvent(l2cap_packet); if (basic_frame_view.GetChannelId() == kClassicSignallingCid) { ControlView control_view = ControlView::Create(basic_frame_view.GetPayload()); ASSERT(control_view.IsValid()); handle_signalling_packet(control_view); } } void handle_signalling_packet(ControlView control_view) { auto code = control_view.GetCode(); switch (code) { case CommandCode::CONNECTION_REQUEST: { ConnectionRequestView view = ConnectionRequestView::Create(control_view); ASSERT(view.IsValid()); open_channels_.push_back(view.GetSourceCid()); auto builder = ConnectionResponseBuilder::Create( view.GetIdentifier(), view.GetSourceCid(), view.GetSourceCid(), accept_incoming_connection_ ? ConnectionResponseResult::SUCCESS : ConnectionResponseResult::INVALID_CID, ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE); auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder)); outgoing_packet_queue_.push(std::move(l2cap_builder)); if (outgoing_packet_queue_.size() == 1) { acl_connection_->GetAclQueueEnd()->RegisterEnqueue( handler_, common::Bind(&L2capModuleCertService::enqueue_packet_to_acl, common::Unretained(this))); } break; } case CommandCode::CONNECTION_RESPONSE: { ConnectionResponseView view = ConnectionResponseView::Create(control_view); ASSERT(view.IsValid()); open_channels_.push_back(view.GetSourceCid()); break; } case CommandCode::CONFIGURATION_REQUEST: { ConfigurationRequestView view = ConfigurationRequestView::Create(control_view); ASSERT(view.IsValid()); auto builder = ConfigurationResponseBuilder::Create(view.GetIdentifier(), view.GetDestinationCid(), Continuation::END, ConfigurationResponseResult::SUCCESS, {}); auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder)); outgoing_packet_queue_.push(std::move(l2cap_builder)); if (outgoing_packet_queue_.size() == 1) { acl_connection_->GetAclQueueEnd()->RegisterEnqueue( handler_, common::Bind(&L2capModuleCertService::enqueue_packet_to_acl, common::Unretained(this))); } break; } default: return; } } std::queue<std::unique_ptr<BasePacketBuilder>> outgoing_packet_queue_; Loading @@ -177,12 +248,17 @@ class L2capModuleCertService : public L2capModuleCert::Service { module_->acl_connection_->RegisterDisconnectCallback(common::BindOnce([](hci::ErrorCode) {}), module_->handler_); module_->acl_connection_->GetAclQueueEnd()->RegisterDequeue( module_->handler_, common::Bind(&L2capModuleCertService::on_incoming_packet, common::Unretained(module_))); dequeue_registered_ = true; } void OnConnectFail(hci::Address address, hci::ErrorCode reason) override {} ~AclCallbacks() { if (dequeue_registered_) { module_->acl_connection_->GetAclQueueEnd()->UnregisterDequeue(); } } bool dequeue_registered_ = false; L2capModuleCertService* module_; } acl_callbacks{this}; Loading
system/gd/l2cap/classic/cert/simple_l2cap_test.py +24 −3 Original line number Diff line number Diff line Loading @@ -84,12 +84,15 @@ class SimpleL2capTest(GdBaseTestClass): ) dut_connection_stream.unsubscribe() self.cert_device.l2cap.SendConnectionRequest(l2cap_cert_pb2.ConnectionRequest()) self.cert_device.l2cap.SendConnectionRequest(l2cap_cert_pb2.ConnectionRequest(scid=0x101)) time.sleep(1) open_channels = self.cert_device.l2cap.FetchOpenedChannels(l2cap_cert_pb2.FetchOpenedChannelsRequest()) cid = open_channels.cid[0] dut_packet_stream.subscribe() cert_packet_stream.subscribe() self.cert_device.l2cap.SendConfigurationRequest(l2cap_cert_pb2.ConfigurationRequest()) self.cert_device.l2cap.SendConfigurationRequest(l2cap_cert_pb2.ConfigurationRequest(scid=cid)) self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=2, payload=b"abc")) dut_packet_stream.assert_event_occurs( Loading @@ -100,7 +103,7 @@ class SimpleL2capTest(GdBaseTestClass): lambda packet: b"123" in packet.payload ) self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=64, payload=b"123")) self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=cid, payload=b"123")) dut_packet_stream.assert_event_occurs( lambda packet: b"123" in packet.payload ) Loading @@ -114,3 +117,21 @@ class SimpleL2capTest(GdBaseTestClass): time.sleep(1) dut_packet_stream.unsubscribe() cert_packet_stream.unsubscribe() def test_basic_operation_request_connection(self): """ L2CAP/COS/CED/BV-01-C [Request Connection] Verify that the IUT is able to request the connection establishment for an L2CAP data channel and initiate the configuration procedure. """ self.device_under_test.l2cap.RegisterChannel(l2cap_facade_pb2.RegisterChannelRequest(channel=2)) cert_connection_stream = self.cert_device.l2cap.connection_complete_stream cert_connection_stream.subscribe() self.device_under_test.l2cap.Connect(self.cert_address) cert_connection_stream.assert_event_occurs( lambda device: device.remote == self.dut_address ) cert_connection_stream.unsubscribe() self.device_under_test.l2cap.OpenChannel(l2cap_facade_pb2.OpenChannelRequest(remote=self.cert_address, psm=0x01)) time.sleep(1)
system/gd/l2cap/classic/facade.cc +20 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,18 @@ class L2capModuleFacadeService : public L2capModuleFacade::Service { return ::grpc::Status::OK; } ::grpc::Status OpenChannel(::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::OpenChannelRequest* request, ::google::protobuf::Empty* response) override { auto psm = request->psm(); dynamic_channel_helper_map_.emplace( psm, std::make_unique<L2capDynamicChannelHelper>(this, l2cap_layer_, facade_handler_, psm)); hci::Address peer; ASSERT(hci::Address::FromString(request->remote().address(), peer)); dynamic_channel_helper_map_[psm]->Connect(peer); return ::grpc::Status::OK; } ::grpc::Status FetchL2capData(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request, ::grpc::ServerWriter<classic::L2capPacket>* writer) override { return l2cap_stream_.HandleRequest(context, request, writer); Loading Loading @@ -189,6 +201,12 @@ class L2capModuleFacadeService : public L2capModuleFacade::Service { common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)), handler_); } void Connect(hci::Address address) { dynamic_channel_manager_->ConnectChannel( address, psm_, common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)), common::Bind(&L2capDynamicChannelHelper::on_connect_fail, common::Unretained(this)), handler_); } void on_l2cap_service_registration_complete(DynamicChannelManager::RegistrationResult registration_result, std::unique_ptr<DynamicChannelService> service) {} Loading @@ -199,6 +217,8 @@ class L2capModuleFacadeService : public L2capModuleFacade::Service { channel_ = std::move(channel); } void on_connect_fail(DynamicChannelManager::ConnectionResult result) {} void on_incoming_packet() { auto packet = channel_->GetQueueUpEnd()->TryDequeue(); std::string data = std::string(packet->begin(), packet->end()); Loading
system/gd/l2cap/classic/internal/dynamic_channel_allocator.cc +35 −1 Original line number Diff line number Diff line Loading @@ -39,7 +39,7 @@ std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateChannel(Psm } Cid cid = kFirstDynamicChannel; for (; cid <= kLastDynamicChannel; cid++) { if (channels_.find(cid) == channels_.end()) break; if (used_cid_.find(cid) == used_cid_.end()) break; } if (cid > kLastDynamicChannel) { LOG_WARN("All cid are used"); Loading @@ -51,9 +51,42 @@ std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateChannel(Psm link_->GetDevice().ToString().c_str()); ASSERT(elem.first->second != nullptr); used_remote_cid_.insert(remote_cid); used_cid_.insert(cid); return elem.first->second; } std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateReservedChannel(Cid reserved_cid, Psm psm, Cid remote_cid, SecurityPolicy security_policy) { ASSERT_LOG(!IsPsmUsed((psm)), "Psm 0x%x for device %s is already in use", psm, link_->GetDevice().ToString().c_str()); ASSERT_LOG(IsPsmValid(psm), "Psm 0x%x is invalid", psm); if (used_remote_cid_.find(remote_cid) != used_remote_cid_.end()) { LOG_INFO("Remote cid 0x%x is used", remote_cid); return nullptr; } auto elem = channels_.try_emplace( reserved_cid, std::make_shared<DynamicChannelImpl>(psm, reserved_cid, remote_cid, link_, l2cap_handler_)); ASSERT_LOG(elem.second, "Failed to create channel for psm 0x%x device %s", psm, link_->GetDevice().ToString().c_str()); ASSERT(elem.first->second != nullptr); used_remote_cid_.insert(remote_cid); return elem.first->second; } Cid DynamicChannelAllocator::ReserveChannel() { Cid cid = kFirstDynamicChannel; for (; cid <= kLastDynamicChannel; cid++) { if (used_cid_.find(cid) == used_cid_.end()) break; } if (cid > kLastDynamicChannel) { LOG_WARN("All cid are used"); return kInvalidCid; } used_cid_.insert(cid); return cid; } void DynamicChannelAllocator::FreeChannel(Cid cid) { auto channel = FindChannelByCid(cid); if (channel == nullptr) { Loading @@ -62,6 +95,7 @@ void DynamicChannelAllocator::FreeChannel(Cid cid) { } used_remote_cid_.erase(channel->GetRemoteCid()); channels_.erase(cid); used_cid_.erase(cid); } bool DynamicChannelAllocator::IsPsmUsed(Psm psm) const { Loading