def test_multiple_channels_with_interleaved_data_streams(self): """ Verify that an IUT can create multiple channels and receives data streams on the channels when the streams are interleaved. """ 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(4, SAMPLE_PACKET) cert_channel_z.send_first_le_i_frame(4, SAMPLE_PACKET) cert_channel_y.send_first_le_i_frame(4, SAMPLE_PACKET) cert_channel_z.send_first_le_i_frame(4, SAMPLE_PACKET) cert_channel_y.send_first_le_i_frame(4, SAMPLE_PACKET) # TODO: We should assert two events in order, but it got stuck assertThat(dut_channel_y).emits( L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'), at_least_times=3) assertThat(dut_channel_z).emits( L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'), L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17')).inOrder() cert_channel_z.send_first_le_i_frame(4, SAMPLE_PACKET) assertThat(dut_channel_z).emits( L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
def test_receiving_scid_over_bredr_and_le(self): """ Test that the L2CAP entity can receive the same SCID in L2CAP connect requests on both the BR/EDR and LE links. """ self._setup_acl_link_from_cert() # TODO: We should let LE use public address, same as classic link. # TODO: Update AclManager::impl::create_le_connection self._setup_le_link_from_cert() (dut_channel, cert_channel) = self._open_channel_from_cert(0x33, 0x70) (le_dut_channel, le_cert_channel) = self._open_le_coc_from_cert(0x35, 0x70) dut_channel.send(b'abc') assertThat(cert_channel).emits(L2capMatchers.Data(b'abc')) le_dut_channel.send(b'hello') assertThat(le_cert_channel).emits( L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5)) le_cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET) assertThat(le_dut_channel).emits( L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17')) cert_channel.disconnect_and_verify() le_cert_channel.disconnect_and_verify()
def test_handle_duplicate_srej(self): """ L2CAP/ERM/BI-03-C [Handle Duplicate S-Frame [SREJ]] Verify the IUT will only retransmit the requested I-frame once after receiving a duplicate SREJ. """ self._setup_link_from_cert() self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel(scid=0x41, psm=0x33, use_ertm=True) dut_channel.send(b'abc') dut_channel.send(b'abc') assertThat(cert_channel).emits( L2capMatchers.IFrame(tx_seq=0), L2capMatchers.IFrame(tx_seq=1), L2capMatchers.SFrame(p=Poll.POLL)).inOrder() cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.SELECT_REJECT) assertThat(cert_channel).emitsNone(timeout=timedelta(seconds=0.5)) cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.SELECT_REJECT, f=Final.POLL_RESPONSE) assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
def test_handle_rej_and_i_frame_with_f_set(self): """ L2CAP/ERM/BI-05-C [Handle receipt of S-Frame [REJ] and I-Frame [F=1] that Both Require Retransmission of the Same I-Frames] Verify the IUT will only retransmit the requested I-frames once after receiving an S-frame [REJ] followed by an I-frame with the Final bit set that indicates the same I-frames should be retransmitted. """ self._setup_link_from_cert() self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel(scid=0x41, psm=0x33, use_ertm=True) dut_channel.send(b'abc') dut_channel.send(b'abc') assertThat(cert_channel).emits( L2capMatchers.IFrame(tx_seq=0), L2capMatchers.IFrame(tx_seq=1), L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL)).inOrder() # Send SREJ with F not set cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.SELECT_REJECT) assertThat(cert_channel).emitsNone(timeout=timedelta(seconds=0.5)) cert_channel.send_i_frame(tx_seq=0, req_seq=0, f=Final.POLL_RESPONSE, payload=SAMPLE_PACKET) assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0)) assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1))
def test_receive_i_frame_final_bit_set(self): """ L2CAP/ERM/BV-19-C [Receive I-Frame Final Bit = 1] Verify the IUT will retransmit any previously sent I-frames unacknowledged by receipt of an I-frame with the final bit set. """ self._setup_link_from_cert() self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel(scid=0x41, psm=0x33, use_ertm=True) dut_channel.send(b'abc') # TODO: Always use their retransmission timeout value time.sleep(2) assertThat(cert_channel).emits(L2capMatchers.SFrame(p=Poll.POLL)) cert_channel.send_i_frame(tx_seq=0, req_seq=0, f=Final.POLL_RESPONSE, payload=SAMPLE_PACKET) assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
def test_sent_rej_lost(self): """ L2CAP/ERM/BI-01-C [S-Frame [REJ] Lost or Corrupted] Verify the IUT can handle receipt of an S-=frame [RR] Poll = 1 if the S-frame [REJ] sent from the IUT is lost. """ self._setup_link_from_cert() self.cert_l2cap.turn_on_ertm(tx_window_size=5) ertm_tx_window_size = 5 (dut_channel, cert_channel) = self._open_channel(scid=0x41, psm=0x41, use_ertm=True) cert_channel.send_i_frame(tx_seq=0, req_seq=0, payload=SAMPLE_PACKET) assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=1)) cert_channel.send_i_frame(tx_seq=ertm_tx_window_size - 1, req_seq=0, payload=SAMPLE_PACKET) assertThat(cert_channel).emits( L2capMatchers.SFrame(s=SupervisoryFunction.REJECT)) cert_channel.send_s_frame(req_seq=0, p=Poll.POLL) assertThat(cert_channel).emits( L2capMatchers.SFrame(req_seq=1, f=l2cap_packets.Final.POLL_RESPONSE)) for i in range(1, ertm_tx_window_size): cert_channel.send_i_frame(tx_seq=i, req_seq=0, payload=SAMPLE_PACKET) assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=i + 1))
def test_receive_i_frames(self): """ L2CAP/ERM/BV-02-C [Receive I-Frames] Verify the IUT can receive in-sequence valid I-frames and deliver L2CAP SDUs to the Upper Tester """ self._setup_link_from_cert() self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel(scid=0x41, psm=0x33, use_ertm=True) for i in range(3): cert_channel.send_i_frame(tx_seq=i, req_seq=0, payload=SAMPLE_PACKET) assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=i + 1)) cert_channel.send_i_frame(tx_seq=3, req_seq=0, sar=SegmentationAndReassembly.START, payload=SAMPLE_PACKET) assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=4)) cert_channel.send_i_frame(tx_seq=4, req_seq=0, sar=SegmentationAndReassembly.CONTINUATION, payload=SAMPLE_PACKET) assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=5)) cert_channel.send_i_frame(tx_seq=5, req_seq=0, sar=SegmentationAndReassembly.END, payload=SAMPLE_PACKET) assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=6))
def test_resume_transmitting_when_acknowledge_previously_sent(self): """ L2CAP/ERM/BV-06-C [Resume Transmitting I-Frames when an I-Frame is Received] Verify the IUT will cease transmission of I-frames when the negotiated TxWindow is full. Verify the IUT will resume transmission of I-frames when an I-frame is received that acknowledges previously sent I-frames. """ self._setup_link_from_cert() self.cert_l2cap.turn_on_ertm(tx_window_size=1) (dut_channel, cert_channel) = self._open_channel(scid=0x41, psm=0x33, use_ertm=True) dut_channel.send(b'abc') dut_channel.send(b'def') assertThat(cert_channel).emits( L2capMatchers.IFrame(tx_seq=0, payload=b'abc')) # TODO: If 1 second is greater than their retransmit timeout, use a smaller timeout assertThat(cert_channel).emitsNone(L2capMatchers.IFrame( tx_seq=1, payload=b'abc'), timeout=timedelta(seconds=1)) cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET) assertThat(cert_channel).emits( L2capMatchers.IFrame(tx_seq=1, payload=b'def')) cert_channel.send_i_frame(tx_seq=1, req_seq=2, payload=SAMPLE_PACKET)
def test_transmit_i_frames(self): """ L2CAP/ERM/BV-01-C [Transmit I-frames] """ self._setup_link_from_cert() self.cert_l2cap.turn_on_ertm() (dut_channel, cert_channel) = self._open_channel(scid=0x41, psm=0x33, use_ertm=True) dut_channel.send(b'abc') assertThat(cert_channel).emits( L2capMatchers.IFrame(tx_seq=0, payload=b"abc")) # Assemble a sample packet. TODO: Use RawBuilder SAMPLE_PACKET = l2cap_packets.CommandRejectNotUnderstoodBuilder(1) # todo: verify packet received? cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET) dut_channel.send(b'abc') assertThat(cert_channel).emits( L2capMatchers.IFrame(tx_seq=1, payload=b"abc")) cert_channel.send_i_frame(tx_seq=1, req_seq=2, payload=SAMPLE_PACKET) dut_channel.send(b'abc') assertThat(cert_channel).emits(L2capMatchers.PartialData(b"abc")) cert_channel.send_i_frame(tx_seq=2, req_seq=3, payload=SAMPLE_PACKET)
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) assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.ConfigurationResponse(), L2capMatchers.ConfigurationRequest()).inAnyOrder() return result
def test_segmentation(self): """ Verify that the IUT can send data segments which are larger than the LE frame size. """ self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_channel_from_cert(mtu=1000, mps=102) dut_channel.send(b'hello' * 20 + b'world') # The first LeInformation packet contains 2 bytes of SDU size. # The packet is divided into first 100 bytes from 'hellohello....' # and remaining 5 bytes 'world' assertThat(cert_channel).emits( L2capMatchers.FirstLeIFrame(b'hello' * 20, sdu_size=105), L2capMatchers.Data(b'world')).inOrder()
def test_retry_config_after_rejection(self): """ L2CAP/COS/CFD/BV-02-C """ self._setup_link_from_cert() self.cert_l2cap.reply_with_unacceptable_parameters() self._open_unvalidated_channel(scid=0x41, psm=0x33) assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.ConfigurationResponse(), L2capMatchers.ConfigurationRequest(), L2capMatchers.ConfigurationRequest()).inAnyOrder()
def test_credit_exchange_receiving_incremental_credits(self): """ Verify the IUT handles flow control correctly, by handling the LE Flow Control Credit sent by the peer. """ self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_channel_from_cert(initial_credit=0) for _ in range(4): dut_channel.send(b'hello') cert_channel.send_credits(1) assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5)) cert_channel.send_credits(1) assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5)) cert_channel.send_credits(2) assertThat(cert_channel).emits( L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5), L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
def test_connect_dynamic_channel_and_send_data(self): self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_channel(scid=0x41, psm=0x33) dut_channel.send(b'abc') assertThat(cert_channel).emits(L2capMatchers.Data(b'abc'))
def __init__(self, device, cid, l2cap_stream): self._device = device self._cid = cid self._le_l2cap_stream = l2cap_stream self._our_le_l2cap_view = FilteringEventStream( self._le_l2cap_stream, L2capMatchers.PacketPayloadWithMatchingCid(self._cid))
def test_fixed_channel_receive(self): self.dut_l2cap.enable_fixed_channel(4) self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_fixed_channel(4) cert_channel.send(SAMPLE_PACKET) assertThat(dut_channel).emits( L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
def test_command_reject_reserved_pdu_codes(self): """ Verify that an IUT receiving a PDU with a reserved command code sends a command reject. """ self._setup_link_from_cert() self.cert_l2cap.get_control_channel().send(l2cap_packets.MoveChannelRequestBuilder(2, 0, 0)) assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.LeCommandReject())
def test_data_receiving_dut_is_central(self): """ L2CAP/COS/CFC/BV-04-C """ (dut_channel, cert_channel) = self._set_link_from_dut_and_open_channel() cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET) assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
def test_no_segmentation_dut_is_central(self): """ L2CAP/COS/CFC/BV-02-C """ (dut_channel, cert_channel) = self._set_link_from_dut_and_open_channel() dut_channel.send(b'hello' * 40) assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello' * 40, sdu_size=200))
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 test_no_segmentation(self): """ Verify that the IUT can send data segments which do not require segmentation. """ self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_channel_from_cert(mtu=1000, mps=202) dut_channel.send(b'hello' * 40) assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello' * 40, sdu_size=200))
def test_reject_connection_parameter_update_request(self): """ Verify that the IUT is able to reject a request for connection parameter update in peripheral mode. """ self._setup_link_from_cert() self.cert_l2cap.get_control_channel().send( l2cap_packets.ConnectionParameterUpdateRequestBuilder(2, 0x10, 0x10, 0x0a, 0x64)) assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.LeCommandReject())
def test_credit_based_connection_response_on_supported_le_psm(self): """ Verify that an IUT receiving a valid LE Credit Based Connection Request from a peer will send an LE Credit Based Connection Response and establish the channel. """ self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_channel_from_cert() dut_channel.send(b'hello') assertThat(cert_channel).emits(L2capMatchers.FirstLeIFrame(b'hello', sdu_size=5))
def test_le_credit_based_connection_request_on_supported_le_psm(self): """ Verify that an IUT sending an LE Credit Based Connection Request to a peer will establish the channel upon receiving the LE Credit Based Connection Response. """ self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_channel_from_dut() cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET) assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
def test_data_receiving(self): """ Verify that the IUT can receive unsegmented data correctly. """ self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_channel_from_cert() cert_channel.send_first_le_i_frame(4, SAMPLE_PACKET) assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17'))
def disconnect_and_verify(self): assertThat(self._scid).isNotEqualTo(1) self._control_channel.send( l2cap_packets.LeDisconnectionRequestBuilder( 1, self._dcid, self._scid)) assertThat(self._control_channel).emits( L2capMatchers.LeDisconnectionResponse(self._scid, self._dcid))
def test_reject_unknown_command_in_le_sigling_channel(self): """ Verify that the IUT is able to reject unknown command. """ self._setup_link_from_cert() self.cert_l2cap.get_control_channel().send( l2cap_packets.InformationRequestBuilder( 2, l2cap_packets.InformationRequestInfoType.EXTENDED_FEATURES_SUPPORTED)) assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.LeCommandReject())
def test_request_refused_due_to_source_cid_already_allocated_responder(self): """ Verify that an IUT receiving an LE Credit Based Connection Request for a second channel will refuse the connection with result "0x000A - Connection refused – Source CID already allocated" if it receives a Source CID which is already in use. """ self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_channel_from_cert(psm=0x33, scid=0x0101) self.dut_l2cap.register_coc(self.cert_address, psm=0x35) self.cert_l2cap.get_control_channel().send( l2cap_packets.LeCreditBasedConnectionRequestBuilder(2, 0x35, 0x0101, 1000, 1000, 1000)) assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.CreditBasedConnectionResponseUsedCid())
def test_credit_based_connection_request_unsupported_le_psm(self): """ Verify that an IUT receiving an LE Credit Based Connection Request on an unsupported LE_PSM will respond with an LE Credit Based Connection Response refusing the connection. """ self._setup_link_from_cert() self.cert_l2cap.get_control_channel().send( l2cap_packets.LeCreditBasedConnectionRequestBuilder(1, 0x34, 0x0101, 2000, 1000, 1000)) assertThat(self.cert_l2cap.get_control_channel()).emits( L2capMatchers.CreditBasedConnectionResponse( result=LeCreditBasedConnectionResponseResult.LE_PSM_NOT_SUPPORTED))
def test_reassembling(self): """ Verify that the IUT can correctly reassemble data received from the Lower Tester which is greater than the IUT LE-frame size. """ self._setup_link_from_cert() (dut_channel, cert_channel) = self._open_channel_from_cert() sdu_size_for_two_sample_packet = 8 cert_channel.send_first_le_i_frame(sdu_size_for_two_sample_packet, SAMPLE_PACKET) cert_channel.send(SAMPLE_PACKET) assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(b'\x19\x26\x08\x17' * 2))