Loading system/gd/l2cap/classic/cert/cert_l2cap.py +76 −3 Original line number Diff line number Diff line Loading @@ -119,6 +119,10 @@ class CertL2cap(Closable): self.scid_to_dcid = {} self.support_ertm = True self.support_fcs = True self.basic_option = None self.ertm_option = None self.fcs_option = None Loading Loading @@ -159,6 +163,14 @@ class CertL2cap(Closable): def _get_acl_stream(self): return self._acl_manager.get_acl_stream() # Disable ERTM when exchange extened feature def disable_ertm(self): self.support_ertm = False # Disable FCS when exchange extened feature def disable_fcs(self): self.support_fcs = False def turn_on_ertm(self, tx_window_size=10, max_transmit=20): self.ertm_option = l2cap_packets.RetransmissionAndFlowControlConfigurationOption( ) Loading Loading @@ -196,6 +208,25 @@ class CertL2cap(Closable): CommandCode. CONNECTION_RESPONSE] = self._on_connection_response_configuration_request_with_continuation_flag # more of a hack for the moment def reply_with_basic_mode(self): self.control_table[ CommandCode. CONFIGURATION_REQUEST] = self._on_configuration_request_basic_mode # more of a hack for the moment def reply_with_nothing(self): self.control_table[ CommandCode. CONNECTION_RESPONSE] = self._on_connection_response_do_nothing # more of a hack for the moment # Send configuration request after receive configuration request def config_with_basic_mode(self): self.control_table[ CommandCode. CONFIGURATION_REQUEST] = self._on_configuration_request_send_configuration_request_basic_mode def _on_connection_request_default(self, l2cap_control_view): connection_request_view = l2cap_packets.ConnectionRequestView( l2cap_control_view) Loading @@ -220,7 +251,9 @@ class CertL2cap(Closable): self.scid_to_dcid[scid] = dcid options = [] if self.ertm_option is not None: if self.basic_option is not None: options.append(self.basic_option) elif self.ertm_option is not None: options.append(self.ertm_option) if self.fcs_option is not None: options.append(self.fcs_option) Loading Loading @@ -281,6 +314,14 @@ class CertL2cap(Closable): self.get_control_channel().send(config_request) return True def _on_connection_response_do_nothing(self, l2cap_control_view): connection_response_view = l2cap_packets.ConnectionResponseView( l2cap_control_view) sid = connection_response_view.GetIdentifier() scid = connection_response_view.GetSourceCid() dcid = connection_response_view.GetDestinationCid() self.scid_to_dcid[scid] = dcid def _on_configuration_request_default(self, l2cap_control_view): configuration_request = l2cap_packets.ConfigurationRequestView( l2cap_control_view) Loading Loading @@ -312,6 +353,38 @@ class CertL2cap(Closable): [mtu_opt, fcs_opt, rfc_opt]) self.control_channel.send(config_response) def _on_configuration_request_basic_mode(self, l2cap_control_view): configuration_request = l2cap_packets.ConfigurationRequestView( l2cap_control_view) sid = configuration_request.GetIdentifier() dcid = configuration_request.GetDestinationCid() basic_option = l2cap_packets.RetransmissionAndFlowControlConfigurationOption( ) basic_option.mode = l2cap_packets.RetransmissionAndFlowControlModeOption.L2CAP_BASIC config_response = l2cap_packets.ConfigurationResponseBuilder( sid, self.scid_to_dcid.get(dcid, 0), l2cap_packets.Continuation.END, l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS, [basic_option]) self.control_channel.send(config_response) def _on_configuration_request_send_configuration_request_basic_mode( self, l2cap_control_view): configuration_request = l2cap_packets.ConfigurationRequestView( l2cap_control_view) sid = configuration_request.GetIdentifier() dcid = configuration_request.GetDestinationCid() basic_option = l2cap_packets.RetransmissionAndFlowControlConfigurationOption( ) basic_option.mode = l2cap_packets.RetransmissionAndFlowControlModeOption.L2CAP_BASIC config_request = l2cap_packets.ConfigurationRequestBuilder( sid + 1, self.scid_to_dcid.get(dcid, 0), l2cap_packets.Continuation.END, [basic_option]) self.control_channel.send(config_request) def _on_configuration_response_default(self, l2cap_control_view): configuration_response = l2cap_packets.ConfigurationResponseView( l2cap_control_view) Loading Loading @@ -343,8 +416,8 @@ class CertL2cap(Closable): return if information_type == l2cap_packets.InformationRequestInfoType.EXTENDED_FEATURES_SUPPORTED: response = l2cap_packets.InformationResponseExtendedFeaturesBuilder( sid, l2cap_packets.InformationRequestResult.SUCCESS, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0) sid, l2cap_packets.InformationRequestResult.SUCCESS, 0, 0, 0, self.support_ertm, 0, self.support_fcs, 0, 0, 0, 0) self.control_channel.send(response) return if information_type == l2cap_packets.InformationRequestInfoType.FIXED_CHANNELS_SUPPORTED: Loading system/gd/l2cap/classic/cert/l2cap_test.py +70 −30 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ from bluetooth_packets_python3.l2cap_packets import SupervisoryFunction from bluetooth_packets_python3.l2cap_packets import Poll from bluetooth_packets_python3.l2cap_packets import InformationRequestInfoType from l2cap.classic.cert.cert_l2cap import CertL2cap from l2cap.classic.facade_pb2 import RetransmissionFlowControlMode # Assemble a sample packet. TODO: Use RawBuilder SAMPLE_PACKET = l2cap_packets.CommandRejectNotUnderstoodBuilder(1) Loading Loading @@ -78,19 +79,19 @@ class L2capTest(GdBaseTestClass): signal_id=1, scid=0x0101, psm=0x33, use_ertm=False): mode = l2cap_facade_pb2.RetransmissionFlowControlMode.BASIC if use_ertm: mode = l2cap_facade_pb2.RetransmissionFlowControlMode.ERTM mode=RetransmissionFlowControlMode.BASIC): dut_channel = self.dut_l2cap.open_channel(psm, mode) cert_channel = self.cert_l2cap.open_channel(signal_id, psm, scid) return (dut_channel, cert_channel) def _open_channel(self, signal_id=1, scid=0x0101, psm=0x33, use_ertm=False): result = self._open_unvalidated_channel(signal_id, scid, psm, use_ertm) def _open_channel(self, signal_id=1, scid=0x0101, psm=0x33, mode=RetransmissionFlowControlMode.BASIC): result = self._open_unvalidated_channel(signal_id, scid, psm, mode) assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.ConfigurationResponse(), Loading Loading @@ -129,7 +130,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc' * 34) assertThat(cert_channel).emits( Loading Loading @@ -322,7 +323,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') assertThat(cert_channel).emits( Loading @@ -339,7 +340,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_fcs() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') assertThat(cert_channel).emits( Loading @@ -356,7 +357,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_fcs() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') assertThat(cert_channel).emits( Loading @@ -371,7 +372,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') assertThat(cert_channel).emits( Loading Loading @@ -403,7 +404,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) for i in range(3): cert_channel.send_i_frame( Loading Loading @@ -441,7 +442,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) for i in range(3): cert_channel.send_i_frame( Loading @@ -462,7 +463,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm(tx_window_size=1) (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') dut_channel.send(b'def') Loading @@ -486,7 +487,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm(tx_window_size=1) (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') dut_channel.send(b'def') Loading Loading @@ -514,7 +515,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') # TODO: Always use their retransmission timeout value Loading @@ -532,7 +533,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) cert_channel.send_s_frame(req_seq=0, p=Poll.POLL) assertThat(cert_channel).emits( Loading @@ -548,7 +549,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') Loading @@ -568,7 +569,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0)) Loading @@ -586,7 +587,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm(tx_window_size=2, max_transmit=2) (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') dut_channel.send(b'abc') Loading Loading @@ -661,7 +662,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') Loading @@ -683,7 +684,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') Loading @@ -706,7 +707,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') Loading @@ -732,7 +733,7 @@ class L2capTest(GdBaseTestClass): ertm_tx_window_size = 5 (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x41, use_ertm=True) scid=0x41, psm=0x41, mode=RetransmissionFlowControlMode.ERTM) cert_channel.send_i_frame(tx_seq=0, req_seq=0, payload=SAMPLE_PACKET) assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=1)) Loading Loading @@ -761,7 +762,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') dut_channel.send(b'abc') Loading Loading @@ -791,7 +792,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') dut_channel.send(b'abc') Loading Loading @@ -819,7 +820,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') dut_channel.send(b'abc') Loading Loading @@ -848,7 +849,8 @@ class L2capTest(GdBaseTestClass): self._setup_link_from_cert() self.cert_l2cap.turn_on_ertm() self._open_unvalidated_channel(scid=0x41, psm=0x33, use_ertm=True) self._open_unvalidated_channel( scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) # TODO: Fix this test. It doesn't work so far with PDL struct Loading @@ -866,7 +868,7 @@ class L2capTest(GdBaseTestClass): self._setup_link_from_cert() psm = 1 scid = 0x0101 self.retransmission_mode = l2cap_facade_pb2.RetransmissionFlowControlMode.ERTM self.retransmission_mode = RetransmissionFlowControlMode.ERTM self.dut.l2cap.SetDynamicChannel( l2cap_facade_pb2.SetEnableDynamicChannelRequest( psm=psm, retransmission_mode=self.retransmission_mode)) Loading @@ -878,3 +880,41 @@ class L2capTest(GdBaseTestClass): # TODO: Verify that the type should be ERTM assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.ConfigurationResponse()) def test_respond_not_support_ertm_when_using_mandatory_ertm(self): """ L2CAP/CMC/BV-12-C """ self._setup_link_from_cert() self.dut.l2cap.OpenChannel( l2cap_facade_pb2.OpenChannelRequest( remote=self.cert_address, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)) assertThat(self.cert_l2cap.get_control_channel()).emitsNone( L2capMatchers.ConfigurationRequest()) def test_config_respond_basic_mode_when_using_mandatory_ertm(self): """ L2CAP/CMC/BI-01-C """ self._setup_link_from_cert() self.cert_l2cap.reply_with_nothing() self.cert_l2cap.reply_with_basic_mode() self._open_unvalidated_channel( scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.ConfigurationRequest(), L2capMatchers.DisconnectionRequest()).inOrder() def test_config_request_basic_mode_when_using_mandatory_ertm(self): """ L2CAP/CMC/BI-02-C """ self._setup_link_from_cert() self.cert_l2cap.reply_with_nothing() self.cert_l2cap.config_with_basic_mode() self._open_unvalidated_channel( scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.ConfigurationRequest(), L2capMatchers.DisconnectionRequest()).inOrder() system/gd/l2cap/classic/dynamic_channel_configuration_option.h +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ struct DynamicChannelConfigurationOption { enum class RetransmissionAndFlowControlMode { L2CAP_BASIC, ENHANCED_RETRANSMISSION, ENHANCED_RETRANSMISSION_OPTIONAL, }; /** * Retransmission and flow control mode. Currently L2CAP_BASIC and ENHANCED_RETRANSMISSION. Loading system/gd/l2cap/classic/dynamic_channel_manager.h +1 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ class DynamicChannelManager { FAIL_NO_SERVICE_REGISTERED = 1, // No service is registered FAIL_HCI_ERROR = 2, // See hci_error FAIL_L2CAP_ERROR = 3, // See l2cap_connection_response_result FAIL_REMOTE_NOT_SUPPORT = 4, // Remote not support required retansmission and flow control mode }; struct ConnectionResult { Loading system/gd/l2cap/classic/facade.cc +8 −10 Original line number Diff line number Diff line Loading @@ -113,16 +113,10 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service public: L2capDynamicChannelHelper(L2capClassicModuleFacadeService* service, L2capClassicModule* l2cap_layer, os::Handler* handler, Psm psm, RetransmissionFlowControlMode mode) : facade_service_(service), l2cap_layer_(l2cap_layer), handler_(handler), psm_(psm) { : facade_service_(service), l2cap_layer_(l2cap_layer), handler_(handler), psm_(psm), mode_(mode) { dynamic_channel_manager_ = l2cap_layer_->GetDynamicChannelManager(); DynamicChannelConfigurationOption configuration_option = {}; if (mode == RetransmissionFlowControlMode::BASIC) { configuration_option.channel_mode = DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC; } else if (mode == RetransmissionFlowControlMode::ERTM) { configuration_option.channel_mode = DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION; } configuration_option.channel_mode = (DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode)mode; dynamic_channel_manager_->RegisterService( psm, configuration_option, {}, common::BindOnce(&L2capDynamicChannelHelper::on_l2cap_service_registration_complete, Loading @@ -138,9 +132,12 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service } void Connect(hci::Address address) { // TODO: specify channel mode DynamicChannelConfigurationOption configuration_option = l2cap::classic::DynamicChannelConfigurationOption(); configuration_option.channel_mode = (DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode)mode_; dynamic_channel_manager_->ConnectChannel( address, {}, psm_, common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)), address, configuration_option, psm_, common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)), common::Bind(&L2capDynamicChannelHelper::on_connect_fail, common::Unretained(this)), handler_); } Loading Loading @@ -229,6 +226,7 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service std::unique_ptr<DynamicChannelService> service_; std::unique_ptr<DynamicChannel> channel_ = nullptr; Psm psm_; RetransmissionFlowControlMode mode_ = RetransmissionFlowControlMode::BASIC; std::condition_variable channel_open_cv_; std::mutex channel_open_cv_mutex_; }; Loading Loading
system/gd/l2cap/classic/cert/cert_l2cap.py +76 −3 Original line number Diff line number Diff line Loading @@ -119,6 +119,10 @@ class CertL2cap(Closable): self.scid_to_dcid = {} self.support_ertm = True self.support_fcs = True self.basic_option = None self.ertm_option = None self.fcs_option = None Loading Loading @@ -159,6 +163,14 @@ class CertL2cap(Closable): def _get_acl_stream(self): return self._acl_manager.get_acl_stream() # Disable ERTM when exchange extened feature def disable_ertm(self): self.support_ertm = False # Disable FCS when exchange extened feature def disable_fcs(self): self.support_fcs = False def turn_on_ertm(self, tx_window_size=10, max_transmit=20): self.ertm_option = l2cap_packets.RetransmissionAndFlowControlConfigurationOption( ) Loading Loading @@ -196,6 +208,25 @@ class CertL2cap(Closable): CommandCode. CONNECTION_RESPONSE] = self._on_connection_response_configuration_request_with_continuation_flag # more of a hack for the moment def reply_with_basic_mode(self): self.control_table[ CommandCode. CONFIGURATION_REQUEST] = self._on_configuration_request_basic_mode # more of a hack for the moment def reply_with_nothing(self): self.control_table[ CommandCode. CONNECTION_RESPONSE] = self._on_connection_response_do_nothing # more of a hack for the moment # Send configuration request after receive configuration request def config_with_basic_mode(self): self.control_table[ CommandCode. CONFIGURATION_REQUEST] = self._on_configuration_request_send_configuration_request_basic_mode def _on_connection_request_default(self, l2cap_control_view): connection_request_view = l2cap_packets.ConnectionRequestView( l2cap_control_view) Loading @@ -220,7 +251,9 @@ class CertL2cap(Closable): self.scid_to_dcid[scid] = dcid options = [] if self.ertm_option is not None: if self.basic_option is not None: options.append(self.basic_option) elif self.ertm_option is not None: options.append(self.ertm_option) if self.fcs_option is not None: options.append(self.fcs_option) Loading Loading @@ -281,6 +314,14 @@ class CertL2cap(Closable): self.get_control_channel().send(config_request) return True def _on_connection_response_do_nothing(self, l2cap_control_view): connection_response_view = l2cap_packets.ConnectionResponseView( l2cap_control_view) sid = connection_response_view.GetIdentifier() scid = connection_response_view.GetSourceCid() dcid = connection_response_view.GetDestinationCid() self.scid_to_dcid[scid] = dcid def _on_configuration_request_default(self, l2cap_control_view): configuration_request = l2cap_packets.ConfigurationRequestView( l2cap_control_view) Loading Loading @@ -312,6 +353,38 @@ class CertL2cap(Closable): [mtu_opt, fcs_opt, rfc_opt]) self.control_channel.send(config_response) def _on_configuration_request_basic_mode(self, l2cap_control_view): configuration_request = l2cap_packets.ConfigurationRequestView( l2cap_control_view) sid = configuration_request.GetIdentifier() dcid = configuration_request.GetDestinationCid() basic_option = l2cap_packets.RetransmissionAndFlowControlConfigurationOption( ) basic_option.mode = l2cap_packets.RetransmissionAndFlowControlModeOption.L2CAP_BASIC config_response = l2cap_packets.ConfigurationResponseBuilder( sid, self.scid_to_dcid.get(dcid, 0), l2cap_packets.Continuation.END, l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS, [basic_option]) self.control_channel.send(config_response) def _on_configuration_request_send_configuration_request_basic_mode( self, l2cap_control_view): configuration_request = l2cap_packets.ConfigurationRequestView( l2cap_control_view) sid = configuration_request.GetIdentifier() dcid = configuration_request.GetDestinationCid() basic_option = l2cap_packets.RetransmissionAndFlowControlConfigurationOption( ) basic_option.mode = l2cap_packets.RetransmissionAndFlowControlModeOption.L2CAP_BASIC config_request = l2cap_packets.ConfigurationRequestBuilder( sid + 1, self.scid_to_dcid.get(dcid, 0), l2cap_packets.Continuation.END, [basic_option]) self.control_channel.send(config_request) def _on_configuration_response_default(self, l2cap_control_view): configuration_response = l2cap_packets.ConfigurationResponseView( l2cap_control_view) Loading Loading @@ -343,8 +416,8 @@ class CertL2cap(Closable): return if information_type == l2cap_packets.InformationRequestInfoType.EXTENDED_FEATURES_SUPPORTED: response = l2cap_packets.InformationResponseExtendedFeaturesBuilder( sid, l2cap_packets.InformationRequestResult.SUCCESS, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0) sid, l2cap_packets.InformationRequestResult.SUCCESS, 0, 0, 0, self.support_ertm, 0, self.support_fcs, 0, 0, 0, 0) self.control_channel.send(response) return if information_type == l2cap_packets.InformationRequestInfoType.FIXED_CHANNELS_SUPPORTED: Loading
system/gd/l2cap/classic/cert/l2cap_test.py +70 −30 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ from bluetooth_packets_python3.l2cap_packets import SupervisoryFunction from bluetooth_packets_python3.l2cap_packets import Poll from bluetooth_packets_python3.l2cap_packets import InformationRequestInfoType from l2cap.classic.cert.cert_l2cap import CertL2cap from l2cap.classic.facade_pb2 import RetransmissionFlowControlMode # Assemble a sample packet. TODO: Use RawBuilder SAMPLE_PACKET = l2cap_packets.CommandRejectNotUnderstoodBuilder(1) Loading Loading @@ -78,19 +79,19 @@ class L2capTest(GdBaseTestClass): signal_id=1, scid=0x0101, psm=0x33, use_ertm=False): mode = l2cap_facade_pb2.RetransmissionFlowControlMode.BASIC if use_ertm: mode = l2cap_facade_pb2.RetransmissionFlowControlMode.ERTM mode=RetransmissionFlowControlMode.BASIC): dut_channel = self.dut_l2cap.open_channel(psm, mode) cert_channel = self.cert_l2cap.open_channel(signal_id, psm, scid) return (dut_channel, cert_channel) def _open_channel(self, signal_id=1, scid=0x0101, psm=0x33, use_ertm=False): result = self._open_unvalidated_channel(signal_id, scid, psm, use_ertm) def _open_channel(self, signal_id=1, scid=0x0101, psm=0x33, mode=RetransmissionFlowControlMode.BASIC): result = self._open_unvalidated_channel(signal_id, scid, psm, mode) assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.ConfigurationResponse(), Loading Loading @@ -129,7 +130,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc' * 34) assertThat(cert_channel).emits( Loading Loading @@ -322,7 +323,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') assertThat(cert_channel).emits( Loading @@ -339,7 +340,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_fcs() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') assertThat(cert_channel).emits( Loading @@ -356,7 +357,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_fcs() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') assertThat(cert_channel).emits( Loading @@ -371,7 +372,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') assertThat(cert_channel).emits( Loading Loading @@ -403,7 +404,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) for i in range(3): cert_channel.send_i_frame( Loading Loading @@ -441,7 +442,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) for i in range(3): cert_channel.send_i_frame( Loading @@ -462,7 +463,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm(tx_window_size=1) (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') dut_channel.send(b'def') Loading @@ -486,7 +487,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm(tx_window_size=1) (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') dut_channel.send(b'def') Loading Loading @@ -514,7 +515,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') # TODO: Always use their retransmission timeout value Loading @@ -532,7 +533,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) cert_channel.send_s_frame(req_seq=0, p=Poll.POLL) assertThat(cert_channel).emits( Loading @@ -548,7 +549,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') Loading @@ -568,7 +569,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0)) Loading @@ -586,7 +587,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm(tx_window_size=2, max_transmit=2) (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') dut_channel.send(b'abc') Loading Loading @@ -661,7 +662,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') Loading @@ -683,7 +684,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') Loading @@ -706,7 +707,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') Loading @@ -732,7 +733,7 @@ class L2capTest(GdBaseTestClass): ertm_tx_window_size = 5 (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x41, use_ertm=True) scid=0x41, psm=0x41, mode=RetransmissionFlowControlMode.ERTM) cert_channel.send_i_frame(tx_seq=0, req_seq=0, payload=SAMPLE_PACKET) assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=1)) Loading Loading @@ -761,7 +762,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') dut_channel.send(b'abc') Loading Loading @@ -791,7 +792,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') dut_channel.send(b'abc') Loading Loading @@ -819,7 +820,7 @@ class L2capTest(GdBaseTestClass): self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel( scid=0x41, psm=0x33, use_ertm=True) scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) dut_channel.send(b'abc') dut_channel.send(b'abc') Loading Loading @@ -848,7 +849,8 @@ class L2capTest(GdBaseTestClass): self._setup_link_from_cert() self.cert_l2cap.turn_on_ertm() self._open_unvalidated_channel(scid=0x41, psm=0x33, use_ertm=True) self._open_unvalidated_channel( scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) # TODO: Fix this test. It doesn't work so far with PDL struct Loading @@ -866,7 +868,7 @@ class L2capTest(GdBaseTestClass): self._setup_link_from_cert() psm = 1 scid = 0x0101 self.retransmission_mode = l2cap_facade_pb2.RetransmissionFlowControlMode.ERTM self.retransmission_mode = RetransmissionFlowControlMode.ERTM self.dut.l2cap.SetDynamicChannel( l2cap_facade_pb2.SetEnableDynamicChannelRequest( psm=psm, retransmission_mode=self.retransmission_mode)) Loading @@ -878,3 +880,41 @@ class L2capTest(GdBaseTestClass): # TODO: Verify that the type should be ERTM assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.ConfigurationResponse()) def test_respond_not_support_ertm_when_using_mandatory_ertm(self): """ L2CAP/CMC/BV-12-C """ self._setup_link_from_cert() self.dut.l2cap.OpenChannel( l2cap_facade_pb2.OpenChannelRequest( remote=self.cert_address, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)) assertThat(self.cert_l2cap.get_control_channel()).emitsNone( L2capMatchers.ConfigurationRequest()) def test_config_respond_basic_mode_when_using_mandatory_ertm(self): """ L2CAP/CMC/BI-01-C """ self._setup_link_from_cert() self.cert_l2cap.reply_with_nothing() self.cert_l2cap.reply_with_basic_mode() self._open_unvalidated_channel( scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.ConfigurationRequest(), L2capMatchers.DisconnectionRequest()).inOrder() def test_config_request_basic_mode_when_using_mandatory_ertm(self): """ L2CAP/CMC/BI-02-C """ self._setup_link_from_cert() self.cert_l2cap.reply_with_nothing() self.cert_l2cap.config_with_basic_mode() self._open_unvalidated_channel( scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM) assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.ConfigurationRequest(), L2capMatchers.DisconnectionRequest()).inOrder()
system/gd/l2cap/classic/dynamic_channel_configuration_option.h +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ struct DynamicChannelConfigurationOption { enum class RetransmissionAndFlowControlMode { L2CAP_BASIC, ENHANCED_RETRANSMISSION, ENHANCED_RETRANSMISSION_OPTIONAL, }; /** * Retransmission and flow control mode. Currently L2CAP_BASIC and ENHANCED_RETRANSMISSION. Loading
system/gd/l2cap/classic/dynamic_channel_manager.h +1 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ class DynamicChannelManager { FAIL_NO_SERVICE_REGISTERED = 1, // No service is registered FAIL_HCI_ERROR = 2, // See hci_error FAIL_L2CAP_ERROR = 3, // See l2cap_connection_response_result FAIL_REMOTE_NOT_SUPPORT = 4, // Remote not support required retansmission and flow control mode }; struct ConnectionResult { Loading
system/gd/l2cap/classic/facade.cc +8 −10 Original line number Diff line number Diff line Loading @@ -113,16 +113,10 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service public: L2capDynamicChannelHelper(L2capClassicModuleFacadeService* service, L2capClassicModule* l2cap_layer, os::Handler* handler, Psm psm, RetransmissionFlowControlMode mode) : facade_service_(service), l2cap_layer_(l2cap_layer), handler_(handler), psm_(psm) { : facade_service_(service), l2cap_layer_(l2cap_layer), handler_(handler), psm_(psm), mode_(mode) { dynamic_channel_manager_ = l2cap_layer_->GetDynamicChannelManager(); DynamicChannelConfigurationOption configuration_option = {}; if (mode == RetransmissionFlowControlMode::BASIC) { configuration_option.channel_mode = DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC; } else if (mode == RetransmissionFlowControlMode::ERTM) { configuration_option.channel_mode = DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION; } configuration_option.channel_mode = (DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode)mode; dynamic_channel_manager_->RegisterService( psm, configuration_option, {}, common::BindOnce(&L2capDynamicChannelHelper::on_l2cap_service_registration_complete, Loading @@ -138,9 +132,12 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service } void Connect(hci::Address address) { // TODO: specify channel mode DynamicChannelConfigurationOption configuration_option = l2cap::classic::DynamicChannelConfigurationOption(); configuration_option.channel_mode = (DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode)mode_; dynamic_channel_manager_->ConnectChannel( address, {}, psm_, common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)), address, configuration_option, psm_, common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)), common::Bind(&L2capDynamicChannelHelper::on_connect_fail, common::Unretained(this)), handler_); } Loading Loading @@ -229,6 +226,7 @@ class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service std::unique_ptr<DynamicChannelService> service_; std::unique_ptr<DynamicChannel> channel_ = nullptr; Psm psm_; RetransmissionFlowControlMode mode_ = RetransmissionFlowControlMode::BASIC; std::condition_variable channel_open_cv_; std::mutex channel_open_cv_mutex_; }; Loading