Loading system/gd/cert/matchers.py +5 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,11 @@ class L2capMatchers(object): def PacketPayloadRawData(payload): return lambda packet: payload in packet.payload # this is a hack - should be removed @staticmethod def PacketPayloadWithMatchingPsm(psm): return lambda packet: None if psm != packet.psm else packet @staticmethod def ExtractBasicFrame(scid): return lambda packet: L2capMatchers._basic_frame_for(packet, scid) Loading system/gd/cert/py_l2cap.py +19 −12 Original line number Diff line number Diff line Loading @@ -18,9 +18,11 @@ from l2cap.classic import facade_pb2 as l2cap_facade_pb2 from l2cap.le import facade_pb2 as l2cap_le_facade_pb2 from bluetooth_packets_python3 import l2cap_packets from bluetooth_packets_python3.l2cap_packets import ConnectionResponseResult from cert.event_stream import EventStream from cert.event_stream import FilteringEventStream from cert.event_stream import EventStream, IEventStream from cert.closable import Closable, safeClose from cert.truth import assertThat from cert.matchers import L2capMatchers from facade import common_pb2 as common from google.protobuf import empty_pb2 as empty_proto Loading Loading @@ -55,11 +57,18 @@ class PyL2cap(Closable): return PyL2capChannel(self._device, psm) class PyLeL2capChannel(object): class PyLeL2capChannel(IEventStream): def __init__(self, device, psm): def __init__(self, device, psm, l2cap_stream): self._device = device self._psm = psm self._le_l2cap_stream = l2cap_stream self._our_le_l2cap_view = FilteringEventStream( self._le_l2cap_stream, L2capMatchers.PacketPayloadWithMatchingPsm(self._psm)) def get_event_queue(self): return self._our_le_l2cap_view.get_event_queue() def send(self, payload): self._device.l2cap_le.SendDynamicChannelPacket( Loading @@ -72,10 +81,11 @@ class CreditBasedConnectionResponseFutureWrapper(object): create the corresponding PyLeL2capChannel object later """ def __init__(self, grpc_response_future, device, psm): def __init__(self, grpc_response_future, device, psm, le_l2cap_stream): self._grpc_response_future = grpc_response_future self._device = device self._psm = psm self._le_l2cap_stream = le_l2cap_stream def get_status(self): return l2cap_packets.LeCreditBasedConnectionResponseResult( Loading @@ -84,27 +94,24 @@ class CreditBasedConnectionResponseFutureWrapper(object): def get_channel(self): assertThat(self.get_status()).isEqualTo( l2cap_packets.LeCreditBasedConnectionResponseResult.SUCCESS) return PyLeL2capChannel(self._device, self._psm) return PyLeL2capChannel(self._device, self._psm, self._le_l2cap_stream) class PyLeL2cap(Closable): def __init__(self, device): self._device = device self.le_l2cap_stream = EventStream( self._le_l2cap_stream = EventStream( self._device.l2cap_le.FetchL2capData(empty_proto.Empty())) def close(self): safeClose(self.le_l2cap_stream) def get_le_l2cap_stream(self): return self.le_l2cap_stream safeClose(self._le_l2cap_stream) def register_coc(self, psm=0x33): self._device.l2cap_le.SetDynamicChannel( l2cap_le_facade_pb2.SetEnableDynamicChannelRequest( psm=psm, enable=True)) return PyLeL2capChannel(self._device, psm) return PyLeL2capChannel(self._device, psm, self._le_l2cap_stream) def connect_coc_to_cert(self, psm=0x33): """ Loading @@ -120,4 +127,4 @@ class PyLeL2cap(Closable): address=b"22:33:ff:ff:11:00")))) return CreditBasedConnectionResponseFutureWrapper( response_future, self._device, psm) response_future, self._device, psm, self._le_l2cap_stream) system/gd/l2cap/le/cert/le_l2cap_test.py +31 −3 Original line number Diff line number Diff line Loading @@ -144,7 +144,7 @@ class LeL2capTest(GdFacadeOnlyBaseTestClass): cert_channel.send_first_le_i_frame(sdu_size_for_two_sample_packet, SAMPLE_PACKET) cert_channel.send(SAMPLE_PACKET) assertThat(self.dut_l2cap.le_l2cap_stream).emits( assertThat(dut_channel).emits( L2capMatchers.PacketPayloadRawData(b'\x01\x01\x02\x00\x00\x00' * 2)) def test_data_receiving(self): Loading @@ -154,7 +154,35 @@ class LeL2capTest(GdFacadeOnlyBaseTestClass): self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_channel_from_cert() cert_channel.send_first_le_i_frame(6, SAMPLE_PACKET) assertThat(self.dut_l2cap.le_l2cap_stream).emits( assertThat(dut_channel).emits( L2capMatchers.PacketPayloadRawData(b'\x01\x01\x02\x00\x00\x00')) def test_multiple_channels_with_interleaved_data_streams(self): """ L2CAP/COS/CFC/BV-05-C """ self._setup_link_from_cert() (dut_channel_x, cert_channel_x) = self._open_channel_from_cert( signal_id=1, scid=0x0103, psm=0x33) (dut_channel_y, cert_channel_y) = self._open_channel_from_cert( signal_id=2, scid=0x0105, psm=0x35) (dut_channel_z, cert_channel_z) = self._open_channel_from_cert( signal_id=3, scid=0x0107, psm=0x37) cert_channel_y.send_first_le_i_frame(6, SAMPLE_PACKET) cert_channel_z.send_first_le_i_frame(6, SAMPLE_PACKET) cert_channel_y.send_first_le_i_frame(6, SAMPLE_PACKET) cert_channel_z.send_first_le_i_frame(6, SAMPLE_PACKET) cert_channel_y.send_first_le_i_frame(6, SAMPLE_PACKET) # TODO: We should assert two events in order, but it got stuck assertThat(dut_channel_y).emits( L2capMatchers.PacketPayloadRawData(b'\x01\x01\x02\x00\x00\x00'), at_least_times=3) assertThat(dut_channel_z).emits( L2capMatchers.PacketPayloadRawData(b'\x01\x01\x02\x00\x00\x00'), L2capMatchers.PacketPayloadRawData( b'\x01\x01\x02\x00\x00\x00')).inOrder() cert_channel_z.send_first_le_i_frame(6, SAMPLE_PACKET) assertThat(dut_channel_z).emits( L2capMatchers.PacketPayloadRawData(b'\x01\x01\x02\x00\x00\x00')) def test_reject_unknown_command_in_le_sigling_channel(self): Loading Loading @@ -220,7 +248,7 @@ class LeL2capTest(GdFacadeOnlyBaseTestClass): self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_channel_from_dut() cert_channel.send_first_le_i_frame(6, SAMPLE_PACKET) assertThat(self.dut_l2cap.le_l2cap_stream).emits( assertThat(dut_channel).emits( L2capMatchers.PacketPayloadRawData(b'\x01\x01\x02\x00\x00\x00')) def test_credit_based_connection_response_on_supported_le_psm(self): Loading system/gd/l2cap/le/facade.cc +1 −1 Original line number Diff line number Diff line Loading @@ -182,6 +182,7 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { auto packet = channel_->GetQueueUpEnd()->TryDequeue(); std::string data = std::string(packet->begin(), packet->end()); L2capPacket l2cap_data; l2cap_data.set_psm(psm_); l2cap_data.set_payload(data); facade_service_->pending_l2cap_data_.OnIncomingEvent(l2cap_data); } Loading Loading @@ -232,7 +233,6 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { os::Handler* facade_handler_; std::mutex channel_map_mutex_; std::map<Psm, std::unique_ptr<L2capDynamicChannelHelper>> dynamic_channel_helper_map_; bool fetch_l2cap_data_ = false; ::bluetooth::grpc::GrpcEventQueue<L2capPacket> pending_l2cap_data_{"FetchL2capData"}; }; Loading system/gd/l2cap/le/facade.proto +2 −3 Original line number Diff line number Diff line Loading @@ -16,9 +16,8 @@ service L2capLeModuleFacade { } message L2capPacket { facade.BluetoothAddressWithType remote = 1; uint32 channel = 2; bytes payload = 3; uint32 psm = 1; bytes payload = 2; } message DynamicChannelOpenEvent { Loading Loading
system/gd/cert/matchers.py +5 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,11 @@ class L2capMatchers(object): def PacketPayloadRawData(payload): return lambda packet: payload in packet.payload # this is a hack - should be removed @staticmethod def PacketPayloadWithMatchingPsm(psm): return lambda packet: None if psm != packet.psm else packet @staticmethod def ExtractBasicFrame(scid): return lambda packet: L2capMatchers._basic_frame_for(packet, scid) Loading
system/gd/cert/py_l2cap.py +19 −12 Original line number Diff line number Diff line Loading @@ -18,9 +18,11 @@ from l2cap.classic import facade_pb2 as l2cap_facade_pb2 from l2cap.le import facade_pb2 as l2cap_le_facade_pb2 from bluetooth_packets_python3 import l2cap_packets from bluetooth_packets_python3.l2cap_packets import ConnectionResponseResult from cert.event_stream import EventStream from cert.event_stream import FilteringEventStream from cert.event_stream import EventStream, IEventStream from cert.closable import Closable, safeClose from cert.truth import assertThat from cert.matchers import L2capMatchers from facade import common_pb2 as common from google.protobuf import empty_pb2 as empty_proto Loading Loading @@ -55,11 +57,18 @@ class PyL2cap(Closable): return PyL2capChannel(self._device, psm) class PyLeL2capChannel(object): class PyLeL2capChannel(IEventStream): def __init__(self, device, psm): def __init__(self, device, psm, l2cap_stream): self._device = device self._psm = psm self._le_l2cap_stream = l2cap_stream self._our_le_l2cap_view = FilteringEventStream( self._le_l2cap_stream, L2capMatchers.PacketPayloadWithMatchingPsm(self._psm)) def get_event_queue(self): return self._our_le_l2cap_view.get_event_queue() def send(self, payload): self._device.l2cap_le.SendDynamicChannelPacket( Loading @@ -72,10 +81,11 @@ class CreditBasedConnectionResponseFutureWrapper(object): create the corresponding PyLeL2capChannel object later """ def __init__(self, grpc_response_future, device, psm): def __init__(self, grpc_response_future, device, psm, le_l2cap_stream): self._grpc_response_future = grpc_response_future self._device = device self._psm = psm self._le_l2cap_stream = le_l2cap_stream def get_status(self): return l2cap_packets.LeCreditBasedConnectionResponseResult( Loading @@ -84,27 +94,24 @@ class CreditBasedConnectionResponseFutureWrapper(object): def get_channel(self): assertThat(self.get_status()).isEqualTo( l2cap_packets.LeCreditBasedConnectionResponseResult.SUCCESS) return PyLeL2capChannel(self._device, self._psm) return PyLeL2capChannel(self._device, self._psm, self._le_l2cap_stream) class PyLeL2cap(Closable): def __init__(self, device): self._device = device self.le_l2cap_stream = EventStream( self._le_l2cap_stream = EventStream( self._device.l2cap_le.FetchL2capData(empty_proto.Empty())) def close(self): safeClose(self.le_l2cap_stream) def get_le_l2cap_stream(self): return self.le_l2cap_stream safeClose(self._le_l2cap_stream) def register_coc(self, psm=0x33): self._device.l2cap_le.SetDynamicChannel( l2cap_le_facade_pb2.SetEnableDynamicChannelRequest( psm=psm, enable=True)) return PyLeL2capChannel(self._device, psm) return PyLeL2capChannel(self._device, psm, self._le_l2cap_stream) def connect_coc_to_cert(self, psm=0x33): """ Loading @@ -120,4 +127,4 @@ class PyLeL2cap(Closable): address=b"22:33:ff:ff:11:00")))) return CreditBasedConnectionResponseFutureWrapper( response_future, self._device, psm) response_future, self._device, psm, self._le_l2cap_stream)
system/gd/l2cap/le/cert/le_l2cap_test.py +31 −3 Original line number Diff line number Diff line Loading @@ -144,7 +144,7 @@ class LeL2capTest(GdFacadeOnlyBaseTestClass): cert_channel.send_first_le_i_frame(sdu_size_for_two_sample_packet, SAMPLE_PACKET) cert_channel.send(SAMPLE_PACKET) assertThat(self.dut_l2cap.le_l2cap_stream).emits( assertThat(dut_channel).emits( L2capMatchers.PacketPayloadRawData(b'\x01\x01\x02\x00\x00\x00' * 2)) def test_data_receiving(self): Loading @@ -154,7 +154,35 @@ class LeL2capTest(GdFacadeOnlyBaseTestClass): self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_channel_from_cert() cert_channel.send_first_le_i_frame(6, SAMPLE_PACKET) assertThat(self.dut_l2cap.le_l2cap_stream).emits( assertThat(dut_channel).emits( L2capMatchers.PacketPayloadRawData(b'\x01\x01\x02\x00\x00\x00')) def test_multiple_channels_with_interleaved_data_streams(self): """ L2CAP/COS/CFC/BV-05-C """ self._setup_link_from_cert() (dut_channel_x, cert_channel_x) = self._open_channel_from_cert( signal_id=1, scid=0x0103, psm=0x33) (dut_channel_y, cert_channel_y) = self._open_channel_from_cert( signal_id=2, scid=0x0105, psm=0x35) (dut_channel_z, cert_channel_z) = self._open_channel_from_cert( signal_id=3, scid=0x0107, psm=0x37) cert_channel_y.send_first_le_i_frame(6, SAMPLE_PACKET) cert_channel_z.send_first_le_i_frame(6, SAMPLE_PACKET) cert_channel_y.send_first_le_i_frame(6, SAMPLE_PACKET) cert_channel_z.send_first_le_i_frame(6, SAMPLE_PACKET) cert_channel_y.send_first_le_i_frame(6, SAMPLE_PACKET) # TODO: We should assert two events in order, but it got stuck assertThat(dut_channel_y).emits( L2capMatchers.PacketPayloadRawData(b'\x01\x01\x02\x00\x00\x00'), at_least_times=3) assertThat(dut_channel_z).emits( L2capMatchers.PacketPayloadRawData(b'\x01\x01\x02\x00\x00\x00'), L2capMatchers.PacketPayloadRawData( b'\x01\x01\x02\x00\x00\x00')).inOrder() cert_channel_z.send_first_le_i_frame(6, SAMPLE_PACKET) assertThat(dut_channel_z).emits( L2capMatchers.PacketPayloadRawData(b'\x01\x01\x02\x00\x00\x00')) def test_reject_unknown_command_in_le_sigling_channel(self): Loading Loading @@ -220,7 +248,7 @@ class LeL2capTest(GdFacadeOnlyBaseTestClass): self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_channel_from_dut() cert_channel.send_first_le_i_frame(6, SAMPLE_PACKET) assertThat(self.dut_l2cap.le_l2cap_stream).emits( assertThat(dut_channel).emits( L2capMatchers.PacketPayloadRawData(b'\x01\x01\x02\x00\x00\x00')) def test_credit_based_connection_response_on_supported_le_psm(self): Loading
system/gd/l2cap/le/facade.cc +1 −1 Original line number Diff line number Diff line Loading @@ -182,6 +182,7 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { auto packet = channel_->GetQueueUpEnd()->TryDequeue(); std::string data = std::string(packet->begin(), packet->end()); L2capPacket l2cap_data; l2cap_data.set_psm(psm_); l2cap_data.set_payload(data); facade_service_->pending_l2cap_data_.OnIncomingEvent(l2cap_data); } Loading Loading @@ -232,7 +233,6 @@ class L2capLeModuleFacadeService : public L2capLeModuleFacade::Service { os::Handler* facade_handler_; std::mutex channel_map_mutex_; std::map<Psm, std::unique_ptr<L2capDynamicChannelHelper>> dynamic_channel_helper_map_; bool fetch_l2cap_data_ = false; ::bluetooth::grpc::GrpcEventQueue<L2capPacket> pending_l2cap_data_{"FetchL2capData"}; }; Loading
system/gd/l2cap/le/facade.proto +2 −3 Original line number Diff line number Diff line Loading @@ -16,9 +16,8 @@ service L2capLeModuleFacade { } message L2capPacket { facade.BluetoothAddressWithType remote = 1; uint32 channel = 2; bytes payload = 3; uint32 psm = 1; bytes payload = 2; } message DynamicChannelOpenEvent { Loading