|
|
#
|
|
|
# Copyright 2019 - The Android Open Source Project
|
|
|
#
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
# You may obtain a copy of the License at
|
|
|
#
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
#
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
# See the License for the specific language governing permissions and
|
|
|
# limitations under the License.
|
|
|
|
|
|
from datetime import timedelta
|
|
|
|
|
|
from mobly import asserts
|
|
|
|
|
|
from bluetooth_packets_python3 import l2cap_packets
|
|
|
from bluetooth_packets_python3 import RawBuilder
|
|
|
from bluetooth_packets_python3.l2cap_packets import FcsType
|
|
|
from bluetooth_packets_python3.l2cap_packets import Final
|
|
|
from bluetooth_packets_python3.l2cap_packets import Poll
|
|
|
from bluetooth_packets_python3.l2cap_packets import SegmentationAndReassembly
|
|
|
from bluetooth_packets_python3.l2cap_packets import SupervisoryFunction
|
|
|
from cert.behavior import when, anything, wait_until
|
|
|
from cert.event_stream import EventStream
|
|
|
from cert.gd_base_test import GdBaseTestClass
|
|
|
from cert.matchers import L2capMatchers
|
|
|
from cert.metadata import metadata
|
|
|
from cert.py_l2cap import PyL2cap
|
|
|
from cert.truth import assertThat
|
|
|
from facade import common_pb2
|
|
|
from google.protobuf import empty_pb2 as empty_proto
|
|
|
from l2cap.classic.cert.cert_l2cap import CertL2cap
|
|
|
from l2cap.classic.facade_pb2 import RetransmissionFlowControlMode
|
|
|
from neighbor.facade import facade_pb2 as neighbor_facade
|
|
|
|
|
|
# Assemble a sample packet.
|
|
|
SAMPLE_PACKET_DATA = b"\x19\x26\x08\x17"
|
|
|
SAMPLE_PACKET = RawBuilder([x for x in SAMPLE_PACKET_DATA])
|
|
|
|
|
|
|
|
|
class L2capTestBase(GdBaseTestClass):
|
|
|
|
|
|
def setup_class(self):
|
|
|
super().setup_class(dut_module='L2CAP', cert_module='HCI_INTERFACES')
|
|
|
|
|
|
def setup_test(self):
|
|
|
super().setup_test()
|
|
|
|
|
|
self.dut_address = self.dut.hci_controller.GetMacAddressSimple()
|
|
|
cert_address = common_pb2.BluetoothAddress(
|
|
|
address=self.cert.controller_read_only_property.ReadLocalAddress(empty_proto.Empty()).address)
|
|
|
|
|
|
self.dut_l2cap = PyL2cap(self.dut, cert_address)
|
|
|
self.cert_l2cap = CertL2cap(self.cert)
|
|
|
|
|
|
def teardown_test(self):
|
|
|
self.cert_l2cap.close()
|
|
|
self.dut_l2cap.close()
|
|
|
super().teardown_test()
|
|
|
|
|
|
def _setup_link_from_cert(self):
|
|
|
self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
|
|
|
self.cert_l2cap.connect_acl(self.dut_address)
|
|
|
|
|
|
def _open_unconfigured_channel_from_cert(self,
|
|
|
signal_id=1,
|
|
|
scid=0x0101,
|
|
|
psm=0x33,
|
|
|
mode=RetransmissionFlowControlMode.BASIC,
|
|
|
fcs=None):
|
|
|
|
|
|
dut_channel = self.dut_l2cap.register_dynamic_channel(psm, mode)
|
|
|
cert_channel = self.cert_l2cap.open_channel(signal_id, psm, scid, fcs=fcs)
|
|
|
|
|
|
return (dut_channel, cert_channel)
|
|
|
|
|
|
def _open_channel_from_cert(self,
|
|
|
signal_id=1,
|
|
|
scid=0x0101,
|
|
|
psm=0x33,
|
|
|
mode=RetransmissionFlowControlMode.BASIC,
|
|
|
fcs=None,
|
|
|
req_config_options=None,
|
|
|
rsp_config_options=None):
|
|
|
request_matcher = L2capMatchers.ConfigurationRequestView(scid)
|
|
|
if rsp_config_options is not None:
|
|
|
when(self.cert_l2cap).on_config_req(request_matcher).then().send_configuration_response(
|
|
|
options=rsp_config_options)
|
|
|
if rsp_config_options is None and fcs is not None:
|
|
|
when(self.cert_l2cap).on_config_req(request_matcher).then().send_configuration_response(
|
|
|
options=CertL2cap.config_option_ertm(fcs=fcs))
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(signal_id, scid, psm, mode, fcs)
|
|
|
if req_config_options is None:
|
|
|
req_config_options = CertL2cap.config_option_ertm(
|
|
|
fcs=fcs) if mode == RetransmissionFlowControlMode.ERTM else []
|
|
|
|
|
|
cert_channel.send_configure_request(req_config_options)
|
|
|
|
|
|
cert_channel.verify_configuration_response()
|
|
|
|
|
|
wait_until(self.cert_l2cap).on_config_req(request_matcher).times(1)
|
|
|
|
|
|
assertThat(cert_channel.is_configured()).isTrue()
|
|
|
|
|
|
return (dut_channel, cert_channel)
|
|
|
|
|
|
def _open_channel_from_dut(self, psm=0x33, mode=RetransmissionFlowControlMode.BASIC):
|
|
|
dut_channel_future = self.dut_l2cap.connect_dynamic_channel_to_cert(psm, mode)
|
|
|
cert_channel = self.cert_l2cap.verify_and_respond_open_channel_from_remote(psm)
|
|
|
dut_channel = dut_channel_future.get_channel()
|
|
|
|
|
|
cert_channel.verify_configuration_request_and_respond()
|
|
|
outgoing_config = []
|
|
|
if mode == RetransmissionFlowControlMode.ERTM:
|
|
|
outgoing_config = CertL2cap.config_option_ertm()
|
|
|
cert_channel.send_configure_request(outgoing_config)
|
|
|
cert_channel.verify_configuration_response()
|
|
|
|
|
|
return (dut_channel, cert_channel)
|
|
|
|
|
|
|
|
|
class L2capTest(L2capTestBase):
|
|
|
|
|
|
def test_connect_dynamic_channel_and_send_data(self):
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert()
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(L2capMatchers.Data(b'abc'))
|
|
|
|
|
|
def test_receive_packet_from_unknown_channel(self):
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(scid=0x41, psm=0x33)
|
|
|
|
|
|
i_frame = l2cap_packets.EnhancedInformationFrameBuilder(
|
|
|
0x99, 0, Final.NOT_SET, 1, l2cap_packets.SegmentationAndReassembly.UNSEGMENTED, SAMPLE_PACKET)
|
|
|
self.cert_l2cap.send_acl(i_frame)
|
|
|
assertThat(cert_channel).emitsNone(L2capMatchers.SFrame(req_seq=4), timeout=timedelta(seconds=1))
|
|
|
|
|
|
def test_open_two_channels(self):
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
self._open_channel_from_cert(signal_id=1, scid=0x41, psm=0x41)
|
|
|
self._open_channel_from_cert(signal_id=2, scid=0x43, psm=0x43)
|
|
|
|
|
|
def test_connect_and_send_data_ertm_no_segmentation(self):
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
|
|
|
|
|
|
dut_channel.send(b'abc' * 34)
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc' * 34))
|
|
|
|
|
|
cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET)
|
|
|
# todo verify received?
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CED/BV-01-C", pts_test_name="Request Connection")
|
|
|
def test_basic_operation_request_connection(self):
|
|
|
"""
|
|
|
Verify that the IUT is able to request the connection establishment for
|
|
|
an L2CAP data channel and initiate the configuration procedure.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_dut()
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CED/BV-03-C", pts_test_name="Send data")
|
|
|
def test_send_data(self):
|
|
|
"""
|
|
|
Verify that the IUT is able to send DATA
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert()
|
|
|
dut_channel.send(b'hello')
|
|
|
assertThat(cert_channel).emits(L2capMatchers.Data(b'hello'))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CED/BV-04-C", pts_test_name="Disconnect")
|
|
|
def test_disconnect(self):
|
|
|
"""
|
|
|
Verify that the IUT is able to disconnect the data channel
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert()
|
|
|
dut_channel.close_channel()
|
|
|
cert_channel.verify_disconnect_request()
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CED/BV-05-C", pts_test_name="Accept connection")
|
|
|
def test_accept_connection(self):
|
|
|
"""
|
|
|
Also verify that DUT can send 48 bytes PDU (minimal MTU)
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert()
|
|
|
dut_channel.send(b'a' * 48)
|
|
|
assertThat(cert_channel).emits(L2capMatchers.Data(b'a' * 48))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CED/BV-07-C", pts_test_name="Accept Disconnect")
|
|
|
def test_accept_disconnect(self):
|
|
|
"""
|
|
|
Verify that the IUT is able to respond to the request to disconnect the
|
|
|
data channel
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert()
|
|
|
cert_channel.disconnect_and_verify()
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CED/BV-08-C", pts_test_name="Disconnect on Timeout")
|
|
|
def test_disconnect_on_timeout(self):
|
|
|
"""
|
|
|
Verify that the IUT disconnects the data channel and shuts down this
|
|
|
channel if no response occurs
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
|
|
|
|
|
|
assertThat(self.cert_l2cap.get_control_channel()).emitsNone(L2capMatchers.ConfigurationResponse())
|
|
|
# TODO: Verify that IUT sends disconnect request (not mandated)
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CED/BV-09-C", pts_test_name="Receive Multi-Command Packet")
|
|
|
def test_receive_multi_command_packet(self):
|
|
|
"""
|
|
|
Verify that the IUT is able to receive more than one signaling command in one L2CAP
|
|
|
packet.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
psm = 0x33
|
|
|
self.dut_l2cap.connect_dynamic_channel_to_cert(psm)
|
|
|
self.cert_l2cap.verify_and_respond_open_channel_from_remote_and_send_config_req(psm)
|
|
|
|
|
|
assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.ConfigurationResponse())
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CED/BV-11-C", pts_test_name="Configure MTU size")
|
|
|
def test_configure_mtu_size(self):
|
|
|
"""
|
|
|
Verify that the IUT is able to configure the supported MTU size
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
(dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
|
|
|
cert_channel.send_configure_request(CertL2cap.config_option_mtu_explicit(672))
|
|
|
cert_channel.verify_configuration_request_and_respond()
|
|
|
# TODO: Probably remove verify_configuration_request_and_respond
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CFD/BV-01-C", pts_test_name="Continuation Flag")
|
|
|
def test_continuation_flag(self):
|
|
|
"""
|
|
|
Verify the IUT is able to receive configuration requests that have the
|
|
|
continuation flag set
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
|
|
|
|
|
|
# Send configuration request with CONTINUE
|
|
|
mtu_opt = l2cap_packets.MtuConfigurationOption()
|
|
|
mtu_opt.mtu = 0x1234
|
|
|
cert_channel.send_configure_request([mtu_opt], 2, l2cap_packets.Continuation.CONTINUE)
|
|
|
|
|
|
flush_timeout_option = l2cap_packets.FlushTimeoutConfigurationOption()
|
|
|
flush_timeout_option.flush_timeout = 65535
|
|
|
cert_channel.send_configure_request([flush_timeout_option], 3, l2cap_packets.Continuation.END)
|
|
|
|
|
|
assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.ConfigurationResponse(), at_least_times=2)
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CFD/BV-02-C", pts_test_name="Negotiation with Reject")
|
|
|
def test_retry_config_after_rejection(self):
|
|
|
"""
|
|
|
Verify that the IUT is able to perform negotiation while the Lower
|
|
|
Tester rejects the proposed configuration parameter values
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
scid = 0x41
|
|
|
when(self.cert_l2cap).on_config_req(
|
|
|
L2capMatchers.ConfigurationRequestView(scid)).then().send_configuration_response(
|
|
|
result=l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS,
|
|
|
options=CertL2cap.config_option_mtu_explicit(200)).send_configuration_response(options=[])
|
|
|
(dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(scid=scid)
|
|
|
|
|
|
assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.ConfigurationRequest(), at_least_times=2)
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CFD/BV-03-C", pts_test_name="Send Requested Options")
|
|
|
def test_send_requested_options(self):
|
|
|
"""
|
|
|
Verify that the IUT can receive a configuration request with no options
|
|
|
and send the requested options to the Lower Tester
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(scid=0x41, psm=0x33)
|
|
|
|
|
|
# TODO(hsz) implement me!
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CFD/BV-08-C", pts_test_name="Non-blocking Config Response")
|
|
|
def test_non_blocking_config_response(self):
|
|
|
"""
|
|
|
Verify that the IUT does not block transmitting L2CAP_ConfigRsp while
|
|
|
waiting for L2CAP_ConfigRsp from the Lower Tester
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
|
|
|
|
|
|
cert_channel.send_configure_request([])
|
|
|
cert_channel.verify_configuration_response()
|
|
|
cert_channel.verify_configuration_request_and_respond()
|
|
|
|
|
|
# TODO(hsz) implement me!
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CFD/BV-09-C", pts_test_name="Mandatory 48 Byte MTU")
|
|
|
def test_mandatory_48_byte_mtu(self):
|
|
|
"""
|
|
|
Verify that the IUT can support mandatory 48 byte MTU
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
(dut_channel,
|
|
|
cert_channel) = self._open_channel_from_cert(req_config_options=CertL2cap.config_option_mtu_explicit(48))
|
|
|
|
|
|
dut_channel.send(b"a" * 44)
|
|
|
assertThat(cert_channel).emits(L2capMatchers.Data(b"a" * 44))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CFD/BV-11-C", pts_test_name="Negotiation of Unsupported Parameter")
|
|
|
def test_negotiation_of_unsupported_parameter(self):
|
|
|
"""
|
|
|
Verify that the IUT can negotiate when the Lower Tester proposes an unsupported configuration
|
|
|
parameter value.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
(dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
|
|
|
|
|
|
cert_channel.send_configure_request(CertL2cap.config_option_mtu_explicit(20))
|
|
|
# Invalid because minimum is 48
|
|
|
|
|
|
cert_channel.verify_configuration_response(l2cap_packets.ConfigurationResponseResult.UNACCEPTABLE_PARAMETERS)
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CFD/BV-12-C", pts_test_name="Unknown Option Response")
|
|
|
def test_config_unknown_options_with_hint(self):
|
|
|
"""
|
|
|
Verify that the IUT can give the appropriate error code when the Lower
|
|
|
Tester proposes any number of unknown options that are optional
|
|
|
NOTE: In GD stack, ExtendedWindowSizeOption in unsupported
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert()
|
|
|
|
|
|
unknown_opt_hint = l2cap_packets.ExtendedWindowSizeOption()
|
|
|
unknown_opt_hint.max_window_size = 20
|
|
|
unknown_opt_hint.is_hint = l2cap_packets.ConfigurationOptionIsHint.OPTION_IS_A_HINT
|
|
|
|
|
|
for i in range(10):
|
|
|
cert_channel.send_configure_request([unknown_opt_hint] * i)
|
|
|
cert_channel.verify_configuration_response(l2cap_packets.ConfigurationResponseResult.SUCCESS)
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CFD/BV-14-C", pts_test_name="Unknown Mandatory Options Request")
|
|
|
def test_unknown_mandatory_options_request(self):
|
|
|
"""
|
|
|
Verify that the IUT can give the appropriate error code when the Lower
|
|
|
Tester proposes any number of unknown options where at least one is
|
|
|
mandatory.
|
|
|
Note: GD stack doesn't support extended window size. For other stacks,
|
|
|
we may need to use some other config option
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(scid=0x41, psm=0x33)
|
|
|
|
|
|
unknown_opt = l2cap_packets.ExtendedWindowSizeOption()
|
|
|
unknown_opt.max_window_size = 20
|
|
|
|
|
|
unknown_opt_hint = l2cap_packets.ExtendedWindowSizeOption()
|
|
|
unknown_opt_hint.max_window_size = 20
|
|
|
unknown_opt_hint.is_hint = l2cap_packets.ConfigurationOptionIsHint.OPTION_IS_A_HINT
|
|
|
|
|
|
configuration_option_attempts = [[unknown_opt], [unknown_opt, unknown_opt_hint], [
|
|
|
unknown_opt, unknown_opt, unknown_opt
|
|
|
], [unknown_opt, unknown_opt_hint, unknown_opt_hint,
|
|
|
unknown_opt], [unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt], [
|
|
|
unknown_opt, unknown_opt_hint, unknown_opt_hint, unknown_opt, unknown_opt_hint, unknown_opt_hint
|
|
|
], [unknown_opt, unknown_opt, unknown_opt, unknown_opt, unknown_opt, unknown_opt, unknown_opt], [
|
|
|
unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint,
|
|
|
unknown_opt_hint, unknown_opt_hint, unknown_opt
|
|
|
], [
|
|
|
unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint,
|
|
|
unknown_opt_hint, unknown_opt_hint, unknown_opt, unknown_opt
|
|
|
], [
|
|
|
unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint,
|
|
|
unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt_hint, unknown_opt
|
|
|
]]
|
|
|
|
|
|
for option_list in configuration_option_attempts:
|
|
|
cert_channel.send_configure_request(option_list)
|
|
|
cert_channel.verify_configuration_response(l2cap_packets.ConfigurationResponseResult.UNKNOWN_OPTIONS)
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/ECH/BV-01-C", pts_test_name="Respond to Echo Request")
|
|
|
def test_respond_to_echo_request(self):
|
|
|
"""
|
|
|
Verify that the IUT responds to an echo request.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
echo_request = l2cap_packets.EchoRequestBuilder(100, RawBuilder([1, 2, 3]))
|
|
|
self.cert_l2cap.get_control_channel().send(echo_request)
|
|
|
|
|
|
assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.EchoResponse())
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/CED/BI-01-C", pts_test_name="Reject Unknown Command")
|
|
|
def test_reject_unknown_command(self):
|
|
|
"""
|
|
|
Verify that the IUT rejects an unknown signaling command
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
# Command code ff, Signal id 01, size 0000
|
|
|
invalid_command_packet = RawBuilder([0xff, 0x01, 0x00, 0x00])
|
|
|
self.cert_l2cap.get_control_channel().send(invalid_command_packet)
|
|
|
|
|
|
assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.CommandReject())
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/IEX/BV-01-C", pts_test_name="Query for 1.2 Features")
|
|
|
def test_query_for_1_2_features(self):
|
|
|
"""
|
|
|
Verify that the IUT transmits an information request command to solicit
|
|
|
if the remote device supports Specification 1.2 features.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
assertThat(self.cert_l2cap.get_control_channel()).emits(
|
|
|
L2capMatchers.InformationRequestWithType(
|
|
|
l2cap_packets.InformationRequestInfoType.EXTENDED_FEATURES_SUPPORTED))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/COS/IEX/BV-02-C", pts_test_name="Respond with 1.2 Features")
|
|
|
def test_respond_with_1_2_features(self):
|
|
|
"""
|
|
|
Verify that the IUT responds to an information request command
|
|
|
soliciting for Specification 1.2 features
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
control_channel = self.cert_l2cap.get_control_channel()
|
|
|
|
|
|
control_channel.send_extended_features_request()
|
|
|
|
|
|
assertThat(control_channel).emits(L2capMatchers.InformationResponseExtendedFeatures())
|
|
|
|
|
|
@metadata(
|
|
|
pts_test_id="L2CAP/EXF/BV-01-C",
|
|
|
pts_test_name="Extended Features Information Response for "
|
|
|
"Enhanced Retransmission Mode")
|
|
|
def test_extended_feature_info_response_ertm(self):
|
|
|
"""
|
|
|
Verify the IUT can format an Information Response for the information
|
|
|
type of Extended Features that correctly identifies that Enhanced
|
|
|
Retransmission Mode is locally supported
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
control_channel = self.cert_l2cap.get_control_channel()
|
|
|
|
|
|
control_channel.send_extended_features_request()
|
|
|
|
|
|
assertThat(control_channel).emits(L2capMatchers.InformationResponseExtendedFeatures(supports_ertm=True))
|
|
|
|
|
|
@metadata(
|
|
|
pts_test_id="L2CAP/EXF/BV-02-C", pts_test_name="Extended Features Information Response for "
|
|
|
"Streaming Mode")
|
|
|
def test_extended_feature_info_response_streaming(self):
|
|
|
"""
|
|
|
Verify the IUT can format an Information Response for the information
|
|
|
type of Extended Features that correctly identifies that Streaming Mode
|
|
|
is locally supported
|
|
|
"""
|
|
|
asserts.skip("Streaming not supported")
|
|
|
self._setup_link_from_cert()
|
|
|
control_channel = self.cert_l2cap.get_control_channel()
|
|
|
|
|
|
control_channel.send_extended_features_request()
|
|
|
|
|
|
assertThat(control_channel).emits(L2capMatchers.InformationResponseExtendedFeatures(supports_streaming=True))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/EXF/BV-03-C", pts_test_name="Extended Features Information Response for FCS " "Option")
|
|
|
def test_extended_feature_info_response_fcs(self):
|
|
|
"""
|
|
|
Verify the IUT can format an Information Response for the information
|
|
|
type of Extended Features that correctly identifies that the FCS Option
|
|
|
is locally supported.
|
|
|
|
|
|
Note: This is not mandated by L2CAP Spec
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
control_channel = self.cert_l2cap.get_control_channel()
|
|
|
|
|
|
control_channel.send_extended_features_request()
|
|
|
|
|
|
assertThat(control_channel).emits(L2capMatchers.InformationResponseExtendedFeatures(supports_fcs=True))
|
|
|
|
|
|
@metadata(
|
|
|
pts_test_id="L2CAP/EXF/BV-05-C", pts_test_name="Extended Features Information Response for Fixed "
|
|
|
"Channels")
|
|
|
def test_extended_feature_info_response_fixed_channels(self):
|
|
|
"""
|
|
|
Verify the IUT can format an Information Response for the information
|
|
|
type of Extended Features that correctly identifies that the Fixed
|
|
|
Channels option is locally supported
|
|
|
|
|
|
Note: This is not mandated by L2CAP Spec
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
control_channel = self.cert_l2cap.get_control_channel()
|
|
|
|
|
|
control_channel.send_extended_features_request()
|
|
|
|
|
|
assertThat(control_channel).emits(
|
|
|
L2capMatchers.InformationResponseExtendedFeatures(supports_fixed_channels=True))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/FIX/BV-01-C", pts_test_name="Fixed Channels Supported Information Request")
|
|
|
def test_fixed_channels_supported_information_request(self):
|
|
|
"""
|
|
|
Verify that the IUT can send an Information Request for the information
|
|
|
type of Fixed Channels Supported.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
assertThat(self.cert_l2cap.get_control_channel()).emits(
|
|
|
L2capMatchers.InformationRequestWithType(l2cap_packets.InformationRequestInfoType.FIXED_CHANNELS_SUPPORTED))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/FOC/BV-01-C", pts_test_name="IUT Initiated Configuration of the FCS Option")
|
|
|
def test_config_channel_not_use_FCS(self):
|
|
|
"""
|
|
|
Verify the IUT can configure a channel to not use FCS in I/S-frames.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/FOC/BV-02-C", pts_test_name="Lower Tester Explicitly Requests FCS should be " "Used")
|
|
|
def test_explicitly_request_use_FCS(self):
|
|
|
"""
|
|
|
Verify the IUT will include the FCS in I/S-frames if the Lower Tester
|
|
|
explicitly requests that FCS should be used
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.DEFAULT)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrameWithFcs(payload=b"abc"))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/FOC/BV-03-C", pts_test_name="Lower Tester Implicitly Requests FCS should be " "Used")
|
|
|
def test_implicitly_request_use_FCS(self):
|
|
|
"""
|
|
|
Verify the IUT will include the FCS in I/S-frames if the Lower Tester
|
|
|
implicitly requests that FCS should be used.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM,
|
|
|
fcs=FcsType.DEFAULT,
|
|
|
req_config_options=CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS))
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrameWithFcs(payload=b"abc"))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/OFS/BV-01-C", pts_test_name="Sending I-Frames without FCS for ERTM")
|
|
|
def test_sending_i_frames_without_fcs_for_ertm(self):
|
|
|
"""
|
|
|
Verify the IUT does not include the FCS in I-frames.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b"abc"))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/OFS/BV-02-C", pts_test_name="Receiving I-Frames without FCS for ERTM")
|
|
|
def test_receiving_i_frames_without_fcs_for_ertm(self):
|
|
|
"""
|
|
|
Verify the IUT can handle I-frames that do not contain the FCS.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
|
|
|
|
|
|
cert_channel.send_i_frame(tx_seq=0, req_seq=0, payload=SAMPLE_PACKET)
|
|
|
assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(SAMPLE_PACKET_DATA))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/OFS/BV-05-C", pts_test_name="Sending I-Frames with FCS for ERTM")
|
|
|
def test_sending_i_frames_with_fcs_for_ertm(self):
|
|
|
"""
|
|
|
Verify the IUT does include the FCS in I-frames.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.DEFAULT)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrameWithFcs(tx_seq=0, payload=b"abc"))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/OFS/BV-06-C", pts_test_name="Receiving I-Frames with FCS for ERTM")
|
|
|
def test_receiving_i_frames_with_fcs_for_ertm(self):
|
|
|
"""
|
|
|
Verify the IUT can handle I-frames that do contain the FCS.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.DEFAULT)
|
|
|
|
|
|
cert_channel.send_i_frame(tx_seq=0, req_seq=0, payload=SAMPLE_PACKET, fcs=FcsType.DEFAULT)
|
|
|
assertThat(dut_channel).emits(L2capMatchers.PacketPayloadRawData(SAMPLE_PACKET_DATA))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-01-C", pts_test_name="Transmit I-frames")
|
|
|
def test_transmit_i_frames(self):
|
|
|
"""
|
|
|
Verify the IUT can send correctly formatted sequential I-frames with
|
|
|
valid values for the enhanced control fields (SAR, F-bit, ReqSeq,
|
|
|
TxSeq)
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b"abc"))
|
|
|
|
|
|
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)
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-02-C", pts_test_name="Receive I-Frames")
|
|
|
def test_receive_i_frames(self):
|
|
|
"""
|
|
|
Verify the IUT can receive in-sequence valid I-frames and deliver L2CAP
|
|
|
SDUs to the Upper Tester
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
|
|
|
|
|
|
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))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-03-C", pts_test_name="Acknowledging Received I-Frames")
|
|
|
def test_acknowledging_received_i_frames(self):
|
|
|
"""
|
|
|
Verify the IUT sends S-frame [RR] with the Poll bit not set to
|
|
|
acknowledge data received from the Lower Tester
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
|
|
|
|
|
|
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))
|
|
|
|
|
|
assertThat(cert_channel).emitsNone(L2capMatchers.SFrame(req_seq=4), timeout=timedelta(seconds=1))
|
|
|
|
|
|
@metadata(
|
|
|
pts_test_id="L2CAP/ERM/BV-05-C",
|
|
|
pts_test_name="Resume Transmitting I-Frames when an S-Frame [RR] "
|
|
|
"is Received")
|
|
|
def test_resume_transmitting_when_received_rr(self):
|
|
|
"""
|
|
|
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 S-frame [RR] is received that acknowledges previously sent
|
|
|
I-frames
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=1)
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
dut_channel.send(b'def')
|
|
|
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
|
|
|
assertThat(cert_channel).emitsNone(L2capMatchers.IFrame(tx_seq=1, payload=b'def'))
|
|
|
|
|
|
cert_channel.send_s_frame(req_seq=1, f=Final.POLL_RESPONSE)
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1))
|
|
|
|
|
|
@metadata(
|
|
|
pts_test_id="L2CAP/ERM/BV-06-C", pts_test_name="Resume Transmitting I-Frames when an I-Frame is "
|
|
|
"Received")
|
|
|
def test_resume_transmitting_when_acknowledge_previously_sent(self):
|
|
|
"""
|
|
|
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()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=1)
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
dut_channel.send(b'def')
|
|
|
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
|
|
|
assertThat(cert_channel).emitsNone(
|
|
|
L2capMatchers.IFrame(tx_seq=1, payload=b'abc'), timeout=timedelta(seconds=0.5))
|
|
|
|
|
|
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)
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-07-C", pts_test_name="Send S-Frame [RNR]")
|
|
|
def test_send_s_frame_rnr(self):
|
|
|
"""
|
|
|
Verify the IUT sends an S-frame [RNR] when it detects local busy condition
|
|
|
NOTE: In GD stack, we enter local busy condition if client doesn't dequeue
|
|
|
and packets are accumulating in buffer
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=10)
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM,
|
|
|
fcs=FcsType.NO_FCS,
|
|
|
req_config_options=config,
|
|
|
rsp_config_options=config)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
|
|
|
cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET)
|
|
|
|
|
|
dut_channel.set_traffic_paused(True)
|
|
|
|
|
|
# Allow 1 additional packet in channel queue buffer
|
|
|
buffer_size = self.dut_l2cap.get_channel_queue_buffer_size() + 1
|
|
|
|
|
|
for i in range(buffer_size):
|
|
|
cert_channel.send_i_frame(tx_seq=i + 1, req_seq=1, payload=SAMPLE_PACKET)
|
|
|
assertThat(cert_channel).emits(L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_READY))
|
|
|
|
|
|
cert_channel.send_i_frame(tx_seq=buffer_size + 1, req_seq=1, payload=SAMPLE_PACKET)
|
|
|
assertThat(cert_channel).emits(L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_NOT_READY))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-08-C", pts_test_name="Send S-Frame [RR] with Poll Bit Set")
|
|
|
def test_transmit_s_frame_rr_with_poll_bit_set(self):
|
|
|
"""
|
|
|
Verify the IUT sends an S-frame [RR] with the Poll bit set when its
|
|
|
retransmission timer expires.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, retransmission_time_out=1500)
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM,
|
|
|
fcs=FcsType.NO_FCS,
|
|
|
req_config_options=config,
|
|
|
rsp_config_options=config)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-09-C", pts_test_name="Send S-Frame [RR] with Final Bit Set")
|
|
|
def test_transmit_s_frame_rr_with_final_bit_set(self):
|
|
|
"""
|
|
|
Verify the IUT responds with an S-frame [RR] with the Final bit set
|
|
|
after receiving an S-frame [RR] with the Poll bit set
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
|
|
|
|
|
|
cert_channel.send_s_frame(req_seq=0, p=Poll.POLL)
|
|
|
assertThat(cert_channel).emits(L2capMatchers.SFrame(f=Final.POLL_RESPONSE))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-10-C", pts_test_name="Retransmit S-Frame [RR] with Final Bit Set")
|
|
|
def test_retransmit_s_frame_rr_with_poll_bit_set(self):
|
|
|
"""
|
|
|
Verify the IUT will retransmit the S-frame [RR] with the Poll bit set
|
|
|
when the Monitor Timer expires
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
|
|
|
dut_channel.send(b'abc')
|
|
|
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
|
|
|
assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=0, p=Poll.POLL, f=Final.NOT_SET))
|
|
|
cert_channel.send_s_frame(req_seq=1, f=Final.POLL_RESPONSE)
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-11-C", pts_test_name="S-Frame Transmissions Exceed MaxTransmit")
|
|
|
def test_s_frame_transmissions_exceed_max_transmit(self):
|
|
|
"""
|
|
|
Verify the IUT will close the channel when the Monitor Timer expires.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=1, max_transmit=1, monitor_time_out=10)
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
cert_channel.verify_disconnect_request()
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-12-C", pts_test_name="I-Frame Transmissions Exceed MaxTransmit")
|
|
|
def test_i_frame_transmissions_exceed_max_transmit(self):
|
|
|
"""
|
|
|
Verify the IUT will close the channel when it receives an S-frame [RR]
|
|
|
with the final bit set that does not acknowledge the previous I-frame
|
|
|
sent by the IUT
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=1, max_transmit=1)
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0), L2capMatchers.SFrame(p=Poll.POLL)).inOrder()
|
|
|
|
|
|
cert_channel.send_s_frame(req_seq=0, f=Final.POLL_RESPONSE)
|
|
|
cert_channel.verify_disconnect_request()
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-13-C", pts_test_name="Respond to S-Frame [REJ]")
|
|
|
def test_respond_to_rej(self):
|
|
|
"""
|
|
|
Verify the IUT retransmits I-frames starting from the sequence number
|
|
|
specified in the S-frame [REJ]
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=2, max_transmit=2)
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(
|
|
|
L2capMatchers.IFrame(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc')).inOrder()
|
|
|
|
|
|
cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.REJECT)
|
|
|
|
|
|
assertThat(cert_channel).emits(
|
|
|
L2capMatchers.IFrame(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc')).inOrder()
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-14-C", pts_test_name="Respond to S-Frame [SREJ] POLL Bit Set")
|
|
|
def test_respond_to_srej_p_set(self):
|
|
|
"""
|
|
|
Verify the IUT responds with the correct I-frame when sent an SREJ
|
|
|
frame. Verify that the IUT processes the acknowledgment of previously
|
|
|
unacknowledged I-frames
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, max_transmit=2, tx_window_size=3)
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
|
|
|
|
|
|
for _ in range(4):
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(
|
|
|
L2capMatchers.IFrame(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc'),
|
|
|
L2capMatchers.IFrame(tx_seq=2, payload=b'abc')).inOrder()
|
|
|
|
|
|
cert_channel.send_s_frame(req_seq=1, p=Poll.POLL, s=SupervisoryFunction.SELECT_REJECT)
|
|
|
|
|
|
assertThat(cert_channel).emits(
|
|
|
L2capMatchers.IFrame(tx_seq=1, payload=b'abc', f=Final.POLL_RESPONSE),
|
|
|
L2capMatchers.IFrame(tx_seq=3, payload=b'abc')).inOrder()
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-15-C", pts_test_name="Respond to S-Frame [SREJ] POLL Bit Clear")
|
|
|
def test_respond_to_srej_p_clear(self):
|
|
|
"""
|
|
|
Verify the IUT responds with the correct I-frame when sent an SREJ frame
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, max_transmit=2, tx_window_size=3)
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
|
|
|
|
|
|
for _ in range(4):
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(
|
|
|
L2capMatchers.IFrame(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc'),
|
|
|
L2capMatchers.IFrame(tx_seq=2, payload=b'abc')).inOrder()
|
|
|
|
|
|
cert_channel.send_s_frame(req_seq=1, s=SupervisoryFunction.SELECT_REJECT)
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1, payload=b'abc', f=Final.NOT_SET))
|
|
|
cert_channel.send_s_frame(req_seq=3, s=SupervisoryFunction.RECEIVER_READY)
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=3, payload=b'abc', f=Final.NOT_SET))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-16-C", pts_test_name="Send S-Frame [REJ]")
|
|
|
def test_send_s_frame_rej(self):
|
|
|
"""
|
|
|
Verify the IUT can send an S-Frame [REJ] after receiving out of sequence
|
|
|
I-Frames
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
tx_window_size = 4
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=tx_window_size)
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
|
|
|
|
|
|
cert_channel.send_i_frame(tx_seq=0, req_seq=0, f=Final.NOT_SET, payload=SAMPLE_PACKET)
|
|
|
cert_channel.send_i_frame(tx_seq=2, req_seq=0, f=Final.NOT_SET, payload=SAMPLE_PACKET)
|
|
|
|
|
|
assertThat(cert_channel).emits(
|
|
|
L2capMatchers.SFrame(req_seq=1, f=Final.NOT_SET, s=SupervisoryFunction.REJECT, p=Poll.NOT_SET))
|
|
|
|
|
|
for i in range(1, tx_window_size):
|
|
|
cert_channel.send_i_frame(tx_seq=i, req_seq=0, f=Final.NOT_SET, payload=SAMPLE_PACKET)
|
|
|
assertThat(cert_channel).emits(
|
|
|
L2capMatchers.SFrame(req_seq=i + 1, f=Final.NOT_SET, s=SupervisoryFunction.RECEIVER_READY))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-18-C", pts_test_name="Receive S-Frame [RR] Final Bit = 1")
|
|
|
def test_receive_s_frame_rr_final_bit_set(self):
|
|
|
"""
|
|
|
Verify the IUT will retransmit any previously sent I-frames
|
|
|
unacknowledged by receipt of an S-Frame [RR] with the Final Bit set
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, retransmission_time_out=1500)
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
|
|
|
assertThat(cert_channel).emits(L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL))
|
|
|
|
|
|
cert_channel.send_s_frame(req_seq=0, f=Final.POLL_RESPONSE)
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-19-C", pts_test_name="Receive I-Frame Final Bit = 1")
|
|
|
def test_receive_i_frame_final_bit_set(self):
|
|
|
"""
|
|
|
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()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, retransmission_time_out=1500)
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
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))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-20-C", pts_test_name="Enter Remote Busy Condition")
|
|
|
def test_receive_rnr(self):
|
|
|
"""
|
|
|
Verify the IUT will not retransmit any I-frames when it receives a
|
|
|
remote busy indication from the Lower Tester (S-frame [RNR])
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, retransmission_time_out=1500)
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(L2capMatchers.SFrame(p=l2cap_packets.Poll.POLL))
|
|
|
|
|
|
cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.RECEIVER_NOT_READY, f=Final.POLL_RESPONSE)
|
|
|
assertThat(cert_channel).emitsNone(L2capMatchers.IFrame(tx_seq=0))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-22-C", pts_test_name="Exit Local Busy Condition")
|
|
|
def test_exit_local_busy_condition(self):
|
|
|
"""
|
|
|
Verify the IUT sends an S-frame [RR] Poll = 1 when the local busy condition is cleared
|
|
|
NOTE: In GD stack, we enter local busy condition if client doesn't dequeue
|
|
|
and packets are accumulating in buffer
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=10)
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM,
|
|
|
fcs=FcsType.NO_FCS,
|
|
|
req_config_options=config,
|
|
|
rsp_config_options=config)
|
|
|
|
|
|
dut_channel.send(b'abc')
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0, payload=b'abc'))
|
|
|
cert_channel.send_i_frame(tx_seq=0, req_seq=1, payload=SAMPLE_PACKET)
|
|
|
|
|
|
dut_channel.set_traffic_paused(True)
|
|
|
|
|
|
# Allow 1 additional packet in channel queue buffer
|
|
|
buffer_size = self.dut_l2cap.get_channel_queue_buffer_size() + 1
|
|
|
|
|
|
for i in range(buffer_size):
|
|
|
cert_channel.send_i_frame(tx_seq=i + 1, req_seq=1, payload=SAMPLE_PACKET)
|
|
|
assertThat(cert_channel).emits(L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_READY))
|
|
|
|
|
|
cert_channel.send_i_frame(tx_seq=buffer_size + 1, req_seq=1, payload=SAMPLE_PACKET)
|
|
|
assertThat(cert_channel).emits(L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_NOT_READY))
|
|
|
|
|
|
dut_channel.set_traffic_paused(False)
|
|
|
assertThat(cert_channel).emits(
|
|
|
L2capMatchers.SFrame(s=l2cap_packets.SupervisoryFunction.RECEIVER_READY, p=l2cap_packets.Poll.POLL))
|
|
|
cert_channel.send_s_frame(1, f=l2cap_packets.Final.POLL_RESPONSE)
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BV-23-C", pts_test_name="Transmit I-Frames using SAR")
|
|
|
def test_transmit_i_frames_using_sar(self):
|
|
|
"""
|
|
|
Verify the IUT can send correctly formatted sequential I-frames with
|
|
|
valid values for the enhanced control fields (SAR, F-bit, ReqSeq,
|
|
|
TxSeq) when performing SAR.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, mps=11)
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
|
|
|
|
|
|
dut_channel.send(b'abcabcabc')
|
|
|
# First IFrame should contain SDU size after control field
|
|
|
assertThat(cert_channel).emits(
|
|
|
L2capMatchers.IFrameStart(tx_seq=0, payload=b'abc'), L2capMatchers.IFrame(tx_seq=1, payload=b'abc'),
|
|
|
L2capMatchers.IFrame(tx_seq=2, payload=b'abc')).inOrder()
|
|
|
|
|
|
cert_channel.send_s_frame(req_seq=3, s=SupervisoryFunction.RECEIVER_READY)
|
|
|
|
|
|
dut_channel.send(b'defdefdef')
|
|
|
# First IFrame should contain SDU size after control field
|
|
|
assertThat(cert_channel).emits(
|
|
|
L2capMatchers.IFrameStart(tx_seq=3, payload=b'def'), L2capMatchers.IFrame(tx_seq=4, payload=b'def'),
|
|
|
L2capMatchers.IFrame(tx_seq=5, payload=b'def')).inOrder()
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BI-01-C", pts_test_name="S-Frame [REJ] Lost or Corrupted")
|
|
|
def test_sent_rej_lost(self):
|
|
|
"""
|
|
|
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()
|
|
|
ertm_tx_window_size = 5
|
|
|
|
|
|
config = CertL2cap.config_option_ertm(fcs=FcsType.NO_FCS, tx_window_size=ertm_tx_window_size)
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, req_config_options=config, rsp_config_options=config)
|
|
|
|
|
|
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))
|
|
|
|
|
|
@metadata(pts_test_id="L2CAP/ERM/BI-03-C", pts_test_name="Handle Duplicate S-Frame [SREJ]")
|
|
|
def test_handle_duplicate_srej(self):
|
|
|
"""
|
|
|
Verify the IUT will only retransmit the requested I-frame once after
|
|
|
receiving a duplicate SREJ
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
|
|
|
|
|
|
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))
|
|
|
|
|
|
@metadata(
|
|
|
pts_test_id="L2CAP/ERM/BI-04-C",
|
|
|
pts_test_name="Handle Receipt of S-Frame [REJ] and S-Frame "
|
|
|
"[RR, F=1] that Both Require Retransmission of the "
|
|
|
"Same I-Frames")
|
|
|
def test_handle_receipt_rej_and_rr_with_f_set(self):
|
|
|
"""
|
|
|
Verify the IUT will only retransmit the requested I-frames once after
|
|
|
receiving an S-frame [REJ] followed by an S-frame [RR] with the Final
|
|
|
bit set that indicates the same I-frames should be retransmitted
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
|
|
|
|
|
|
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()
|
|
|
|
|
|
cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.REJECT)
|
|
|
assertThat(cert_channel).emitsNone(timeout=timedelta(seconds=0.5))
|
|
|
|
|
|
# Send RR with F set
|
|
|
cert_channel.send_s_frame(req_seq=0, s=SupervisoryFunction.REJECT, f=Final.POLL_RESPONSE)
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=0))
|
|
|
assertThat(cert_channel).emits(L2capMatchers.IFrame(tx_seq=1))
|
|
|
|
|
|
@metadata(
|
|
|
pts_test_id="L2CAP/ERM/BI-05-C",
|
|
|
pts_test_name="Handle receipt of S-Frame [REJ] and I-Frame [F=1] "
|
|
|
"that Both Require Retransmission of the Same "
|
|
|
"I-Frames")
|
|
|
def test_handle_rej_and_i_frame_with_f_set(self):
|
|
|
"""
|
|
|
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()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
|
|
|
|
|
|
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))
|
|
|
|
|
|
@metadata(
|
|
|
pts_test_id="L2CAP/CMC/BV-01-C", pts_test_name="IUT Initiated Configuration of Enhanced "
|
|
|
"Retransmission Mode")
|
|
|
def test_initiated_configuration_request_ertm(self):
|
|
|
"""
|
|
|
Verify the IUT can send a Configuration Request command containing the
|
|
|
F&EC option that specifies Enhanced Retransmission Mode
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
self._open_unconfigured_channel_from_cert(scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
|
|
|
|
|
|
assertThat(self.cert_l2cap.get_control_channel()).emits(L2capMatchers.ConfigurationRequestWithErtm())
|
|
|
|
|
|
@metadata(
|
|
|
pts_test_id="L2CAP/CMC/BV-02-C",
|
|
|
pts_test_name="Lower Tester Initiated Configuration of Enhanced "
|
|
|
"Retransmission Mode")
|
|
|
def test_respond_configuration_request_ertm(self):
|
|
|
"""
|
|
|
Verify the IUT can accept a Configuration Request from the Lower Tester
|
|
|
containing an F&EC option that specifies Enhanced Retransmission Mode
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
self._open_channel_from_dut(psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
|
|
|
|
|
|
@metadata(
|
|
|
pts_test_id="L2CAP/CMC/BV-12-C",
|
|
|
pts_test_name="ERTM Not Supported by Lower Tester for Mandatory "
|
|
|
"ERTM channel")
|
|
|
def test_respond_not_support_ertm_when_using_mandatory_ertm(self):
|
|
|
"""
|
|
|
The IUT is initiating connection of an L2CAP channel that mandates use
|
|
|
of ERTM. Verify the IUT will not attempt to configure the connection to
|
|
|
ERTM if the Lower Tester has not indicated support for ERTM in the
|
|
|
Information Response [Extended Features]
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
self.cert_l2cap.claim_ertm_unsupported()
|
|
|
dut_channel_future = self.dut_l2cap.connect_dynamic_channel_to_cert(
|
|
|
psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
|
|
|
assertThat(self.cert_l2cap.get_control_channel()).emitsNone(L2capMatchers.ConnectionRequest(0x33))
|
|
|
|
|
|
@metadata(
|
|
|
pts_test_id="L2CAP/CMC/BI-01-C",
|
|
|
pts_test_name="Failed Configuration of Enhanced Retransmission "
|
|
|
"Mode when use of the Mode is Mandatory]")
|
|
|
def test_config_respond_basic_mode_when_using_mandatory_ertm(self):
|
|
|
"""
|
|
|
When creating a connection for a PSM that mandates the use of ERTM
|
|
|
verify the IUT can handle receipt (close the channel in accordance with
|
|
|
the specification) of a Configure Response indicating the peer L2CAP
|
|
|
entity doesn’t wish to use Enhanced Retransmission Mode (Configure
|
|
|
Response Result = Reject Unacceptable Parameters)
|
|
|
"""
|
|
|
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_channel_from_cert(
|
|
|
mode=RetransmissionFlowControlMode.ERTM,
|
|
|
req_config_options=CertL2cap.config_option_ertm(),
|
|
|
rsp_config_options=CertL2cap.config_option_basic_explicit())
|
|
|
|
|
|
cert_channel.verify_disconnect_request()
|
|
|
|
|
|
@metadata(
|
|
|
pts_test_id="L2CAP/CMC/BI-02-C",
|
|
|
pts_test_name="Configuration Mode mismatch when use of Enhanced "
|
|
|
"Retransmission Mode is Mandatory")
|
|
|
def test_config_request_basic_mode_when_using_mandatory_ertm(self):
|
|
|
"""
|
|
|
When creating a connection for a PSM that mandates the use of ERTM,
|
|
|
verify the IUT will close the channel if the Lower Tester attempts to
|
|
|
configure Basic Mode.
|
|
|
"""
|
|
|
self._setup_link_from_cert()
|
|
|
|
|
|
(dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(mode=RetransmissionFlowControlMode.ERTM)
|
|
|
cert_channel.send_configure_request(CertL2cap.config_option_basic_explicit())
|
|
|
cert_channel.verify_disconnect_request()
|
|
|
|
|
|
def test_initiate_connection_for_security(self):
|
|
|
"""
|
|
|
This will test the PyL2cap API for initiating a connection for security
|
|
|
via the security api
|
|
|
"""
|
|
|
self.dut.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
|
|
|
self.cert.neighbor.EnablePageScan(neighbor_facade.EnableMsg(enabled=True))
|
|
|
self.dut_l2cap.initiate_connection_for_security()
|
|
|
self.cert_l2cap.accept_incoming_connection()
|
|
|
self.dut_l2cap.verify_security_connection()
|