Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 51f15833 authored by Henri Chataing's avatar Henri Chataing
Browse files

RootCanal: Address resolution failure in connection initiation

- the previous code had an incorrect interpretation of the specification
  regarding resolved address type:
  public addresses were resolved with the identity address type,
  which mismatched with device address type.

- TargetA addresses were incorrectly resolved using the peer IRK

- add relevant CON/INI tests to validate the fixes

Bug: 317747068
Test: atest rootcanal_ll_test
Flag: EXEMPT, rootcanal change
Change-Id: Ieb4c85cf496e2db7dda6b8cf2c0419642b2703c5
parent 609efa2e
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -309,6 +309,7 @@ python_test_host {
        "test/LL/CIS/CEN/*.py",
        "test/LL/CIS/CEN/*.py",
        "test/LL/CIS/PER/*.py",
        "test/LL/CIS/PER/*.py",
        "test/LL/CON_/CEN/*.py",
        "test/LL/CON_/CEN/*.py",
        "test/LL/CON_/INI/*.py",
        "test/LL/CON_/PER/*.py",
        "test/LL/CON_/PER/*.py",
        "test/LL/DDI/ADV/*.py",
        "test/LL/DDI/ADV/*.py",
        "test/LL/DDI/SCN/*.py",
        "test/LL/DDI/SCN/*.py",
+55 −65
Original line number Original line Diff line number Diff line
@@ -207,7 +207,7 @@ bool LinkLayerController::ResolvingListBusy() {
}
}


std::optional<AddressWithType> LinkLayerController::ResolvePrivateAddress(
std::optional<AddressWithType> LinkLayerController::ResolvePrivateAddress(
    AddressWithType address, IrkSelection irk) {
    AddressWithType address) {
  if (!address.IsRpa()) {
  if (!address.IsRpa()) {
    return address;
    return address;
  }
  }
@@ -217,17 +217,12 @@ std::optional<AddressWithType> LinkLayerController::ResolvePrivateAddress(
  }
  }


  for (auto& entry : le_resolving_list_) {
  for (auto& entry : le_resolving_list_) {
    std::array<uint8_t, LinkLayerController::kIrkSize> const& used_irk =
    if (address.IsRpaThatMatchesIrk(entry.peer_irk)) {
        irk == IrkSelection::Local ? entry.local_irk : entry.peer_irk;

    if (address.IsRpaThatMatchesIrk(used_irk)) {
      // Update the peer resolvable address used for the peer
      // Update the peer resolvable address used for the peer
      // with the returned identity address.
      // with the returned identity address.
      if (irk == IrkSelection::Peer) {
      entry.peer_resolvable_address = address.GetAddress();
      entry.peer_resolvable_address = address.GetAddress();
      }


      return PeerIdentityAddress(entry.peer_identity_address,
      return PeerDeviceAddress(entry.peer_identity_address,
                               entry.peer_identity_address_type);
                               entry.peer_identity_address_type);
    }
    }
  }
  }
@@ -235,6 +230,34 @@ std::optional<AddressWithType> LinkLayerController::ResolvePrivateAddress(
  return {};
  return {};
}
}


bool LinkLayerController::ResolveTargetA(AddressWithType target_a,
                                         AddressWithType adv_a) {
  if (!le_resolving_list_enabled_) {
    return false;
  }

  for (auto const& entry : le_resolving_list_) {
    if (adv_a == PeerDeviceAddress(entry.peer_identity_address,
                                   entry.peer_identity_address_type) &&
        target_a.IsRpaThatMatchesIrk(entry.local_irk)) {
      return true;
    }
  }

  return false;
}

bool LinkLayerController::ValidateTargetA(AddressWithType target_a,
                                          AddressWithType adv_a) {
  if (IsLocalPublicOrRandomAddress(target_a)) {
    return true;
  }
  if (target_a.IsRpa()) {
    return ResolveTargetA(target_a, adv_a);
  }
  return false;
}

std::optional<AddressWithType>
std::optional<AddressWithType>
LinkLayerController::GenerateResolvablePrivateAddress(AddressWithType address,
LinkLayerController::GenerateResolvablePrivateAddress(AddressWithType address,
                                                      IrkSelection irk) {
                                                      IrkSelection irk) {
@@ -2897,11 +2920,7 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu(
  // address. The scanner’s filter policy shall then determine if the scanner
  // address. The scanner’s filter policy shall then determine if the scanner
  // responds with a scan request.
  // responds with a scan request.
  AddressWithType resolved_advertising_address =
  AddressWithType resolved_advertising_address =
      ResolvePrivateAddress(advertising_address, IrkSelection::Peer)
      ResolvePrivateAddress(advertising_address).value_or(advertising_address);
          .value_or(advertising_address);

  std::optional<AddressWithType> resolved_target_address =
      ResolvePrivateAddress(target_address, IrkSelection::Peer);


  if (resolved_advertising_address != advertising_address) {
  if (resolved_advertising_address != advertising_address) {
    DEBUG(id_, "Resolved the advertising address {} to {}", advertising_address,
    DEBUG(id_, "Resolved the advertising address {} to {}", advertising_address,
@@ -2944,8 +2963,7 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu(
      //  resolution is enabled, and the address is resolved successfully
      //  resolution is enabled, and the address is resolved successfully
      case bluetooth::hci::LeScanningFilterPolicy::ACCEPT_ALL:
      case bluetooth::hci::LeScanningFilterPolicy::ACCEPT_ALL:
      case bluetooth::hci::LeScanningFilterPolicy::FILTER_ACCEPT_LIST_ONLY:
      case bluetooth::hci::LeScanningFilterPolicy::FILTER_ACCEPT_LIST_ONLY:
        if (!IsLocalPublicOrRandomAddress(target_address) &&
        if (!ValidateTargetA(target_address, resolved_advertising_address)) {
            !(target_address.IsRpa() && resolved_target_address)) {
          DEBUG(id_,
          DEBUG(id_,
                "Legacy advertising ignored by scanner because the directed "
                "Legacy advertising ignored by scanner because the directed "
                "address {} does not match the current device or cannot be "
                "address {} does not match the current device or cannot be "
@@ -2971,7 +2989,8 @@ void LinkLayerController::ScanIncomingLeLegacyAdvertisingPdu(
          return;
          return;
        }
        }
        should_send_directed_advertising_report =
        should_send_directed_advertising_report =
            target_address.IsRpa() && !resolved_target_address;
            target_address.IsRpa() &&
            !ResolveTargetA(target_address, resolved_advertising_address);
        break;
        break;
    }
    }
  }
  }
@@ -3202,12 +3221,7 @@ void LinkLayerController::ConnectIncomingLeLegacyAdvertisingPdu(
      static_cast<AddressType>(pdu.GetTargetAddressType())};
      static_cast<AddressType>(pdu.GetTargetAddressType())};


  AddressWithType resolved_advertising_address =
  AddressWithType resolved_advertising_address =
      ResolvePrivateAddress(advertising_address, IrkSelection::Peer)
      ResolvePrivateAddress(advertising_address).value_or(advertising_address);
          .value_or(advertising_address);

  AddressWithType resolved_target_address =
      ResolvePrivateAddress(target_address, IrkSelection::Peer)
          .value_or(target_address);


  // Vol 6, Part B § 4.3.5 Initiator filter policy.
  // Vol 6, Part B § 4.3.5 Initiator filter policy.
  switch (initiator_.initiator_filter_policy) {
  switch (initiator_.initiator_filter_policy) {
@@ -3240,14 +3254,14 @@ void LinkLayerController::ConnectIncomingLeLegacyAdvertisingPdu(
  // contain Public or Static addresses for the target’s address (TargetA
  // contain Public or Static addresses for the target’s address (TargetA
  // field).
  // field).
  if (directed_advertising) {
  if (directed_advertising) {
    if (!IsLocalPublicOrRandomAddress(resolved_target_address)) {
    if (!ValidateTargetA(target_address, resolved_advertising_address)) {
      DEBUG(id_,
      DEBUG(id_,
            "Directed legacy advertising ignored by initiator because the "
            "Directed legacy advertising ignored by initiator because the "
            "target address {} does not match the current device addresses",
            "target address {} does not match the current device addresses",
            resolved_advertising_address);
            target_address);
      return;
      return;
    }
    }
    if (resolved_target_address == target_address &&
    if (!target_address.IsRpa() &&
        (initiator_.own_address_type ==
        (initiator_.own_address_type ==
             OwnAddressType::RESOLVABLE_OR_PUBLIC_ADDRESS ||
             OwnAddressType::RESOLVABLE_OR_PUBLIC_ADDRESS ||
         initiator_.own_address_type ==
         initiator_.own_address_type ==
@@ -3256,7 +3270,7 @@ void LinkLayerController::ConnectIncomingLeLegacyAdvertisingPdu(
            "Directed legacy advertising ignored by initiator because the "
            "Directed legacy advertising ignored by initiator because the "
            "target address {} is static or public and the initiator is "
            "target address {} is static or public and the initiator is "
            "configured to use resolvable addresses",
            "configured to use resolvable addresses",
            resolved_advertising_address);
            target_address);
      return;
      return;
    }
    }
  }
  }
@@ -3370,11 +3384,7 @@ void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu(
  // address. The scanner’s filter policy shall then determine if the scanner
  // address. The scanner’s filter policy shall then determine if the scanner
  // responds with a scan request.
  // responds with a scan request.
  AddressWithType resolved_advertising_address =
  AddressWithType resolved_advertising_address =
      ResolvePrivateAddress(advertising_address, IrkSelection::Peer)
      ResolvePrivateAddress(advertising_address).value_or(advertising_address);
          .value_or(advertising_address);

  std::optional<AddressWithType> resolved_target_address =
      ResolvePrivateAddress(target_address, IrkSelection::Peer);


  if (resolved_advertising_address != advertising_address) {
  if (resolved_advertising_address != advertising_address) {
    DEBUG(id_, "Resolved the advertising address {} to {}", advertising_address,
    DEBUG(id_, "Resolved the advertising address {} to {}", advertising_address,
@@ -3411,8 +3421,7 @@ void LinkLayerController::ScanIncomingLeExtendedAdvertisingPdu(
      //    resolution is enabled, and the address is resolved successfully
      //    resolution is enabled, and the address is resolved successfully
      case bluetooth::hci::LeScanningFilterPolicy::ACCEPT_ALL:
      case bluetooth::hci::LeScanningFilterPolicy::ACCEPT_ALL:
      case bluetooth::hci::LeScanningFilterPolicy::FILTER_ACCEPT_LIST_ONLY:
      case bluetooth::hci::LeScanningFilterPolicy::FILTER_ACCEPT_LIST_ONLY:
        if (!IsLocalPublicOrRandomAddress(target_address) &&
        if (!ValidateTargetA(target_address, resolved_advertising_address)) {
            !(target_address.IsRpa() && resolved_target_address)) {
          DEBUG(id_,
          DEBUG(id_,
                "Extended advertising ignored by scanner because the directed "
                "Extended advertising ignored by scanner because the directed "
                "address {} does not match the current device or cannot be "
                "address {} does not match the current device or cannot be "
@@ -3631,12 +3640,7 @@ void LinkLayerController::ConnectIncomingLeExtendedAdvertisingPdu(
      static_cast<AddressType>(pdu.GetTargetAddressType())};
      static_cast<AddressType>(pdu.GetTargetAddressType())};


  AddressWithType resolved_advertising_address =
  AddressWithType resolved_advertising_address =
      ResolvePrivateAddress(advertising_address, IrkSelection::Peer)
      ResolvePrivateAddress(advertising_address).value_or(advertising_address);
          .value_or(advertising_address);

  AddressWithType resolved_target_address =
      ResolvePrivateAddress(target_address, IrkSelection::Peer)
          .value_or(target_address);


  // Vol 6, Part B § 4.3.5 Initiator filter policy.
  // Vol 6, Part B § 4.3.5 Initiator filter policy.
  switch (initiator_.initiator_filter_policy) {
  switch (initiator_.initiator_filter_policy) {
@@ -3669,14 +3673,14 @@ void LinkLayerController::ConnectIncomingLeExtendedAdvertisingPdu(
  // contain Public or Static addresses for the target’s address (TargetA
  // contain Public or Static addresses for the target’s address (TargetA
  // field).
  // field).
  if (pdu.GetDirected()) {
  if (pdu.GetDirected()) {
    if (!IsLocalPublicOrRandomAddress(resolved_target_address)) {
    if (!ValidateTargetA(target_address, resolved_advertising_address)) {
      DEBUG(id_,
      DEBUG(id_,
            "Directed extended advertising ignored by initiator because the "
            "Directed extended advertising ignored by initiator because the "
            "target address {} does not match the current device addresses",
            "target address {} does not match the current device addresses",
            resolved_advertising_address);
            target_address);
      return;
      return;
    }
    }
    if (resolved_target_address == target_address &&
    if (!target_address.IsRpa() &&
        (initiator_.own_address_type ==
        (initiator_.own_address_type ==
             OwnAddressType::RESOLVABLE_OR_PUBLIC_ADDRESS ||
             OwnAddressType::RESOLVABLE_OR_PUBLIC_ADDRESS ||
         initiator_.own_address_type ==
         initiator_.own_address_type ==
@@ -3685,7 +3689,7 @@ void LinkLayerController::ConnectIncomingLeExtendedAdvertisingPdu(
            "Directed extended advertising ignored by initiator because the "
            "Directed extended advertising ignored by initiator because the "
            "target address {} is static or public and the initiator is "
            "target address {} is static or public and the initiator is "
            "configured to use resolvable addresses",
            "configured to use resolvable addresses",
            resolved_advertising_address);
            target_address);
      return;
      return;
    }
    }
  }
  }
@@ -3792,8 +3796,7 @@ void LinkLayerController::IncomingLePeriodicAdvertisingPdu(
  // address. The scanner's periodic sync establishment filter policy shall
  // address. The scanner's periodic sync establishment filter policy shall
  // determine if the scanner processes the advertising packet.
  // determine if the scanner processes the advertising packet.
  AddressWithType resolved_advertiser_address =
  AddressWithType resolved_advertiser_address =
      ResolvePrivateAddress(advertiser_address, IrkSelection::Peer)
      ResolvePrivateAddress(advertiser_address).value_or(advertiser_address);
          .value_or(advertiser_address);


  bluetooth::hci::AdvertiserAddressType advertiser_address_type;
  bluetooth::hci::AdvertiserAddressType advertiser_address_type;
  switch (resolved_advertiser_address.GetAddressType()) {
  switch (resolved_advertiser_address.GetAddressType()) {
@@ -4234,16 +4237,7 @@ uint16_t LinkLayerController::HandleLeConnection(
    AddressType peer_address_type = address.GetAddressType();
    AddressType peer_address_type = address.GetAddressType();
    if (peer_resolved_address != AddressWithType()) {
    if (peer_resolved_address != AddressWithType()) {
      peer_resolvable_private_address = address.GetAddress();
      peer_resolvable_private_address = address.GetAddress();
      if (peer_resolved_address.GetAddressType() ==
      peer_address_type = peer_resolved_address.GetAddressType();
          AddressType::PUBLIC_DEVICE_ADDRESS) {
        peer_address_type = AddressType::PUBLIC_IDENTITY_ADDRESS;
      } else if (peer_resolved_address.GetAddressType() ==
                 AddressType::RANDOM_DEVICE_ADDRESS) {
        peer_address_type = AddressType::RANDOM_IDENTITY_ADDRESS;
      } else {
        WARNING(id_, "Unhandled resolved address type {} -> {}", address,
                peer_resolved_address);
      }
      connection_address = peer_resolved_address.GetAddress();
      connection_address = peer_resolved_address.GetAddress();
    }
    }
    Address local_resolved_address = own_address.GetAddress();
    Address local_resolved_address = own_address.GetAddress();
@@ -4324,8 +4318,7 @@ bool LinkLayerController::ProcessIncomingLegacyConnectRequest(
  // The advertising filter policy shall then determine if the
  // The advertising filter policy shall then determine if the
  // advertiser establishes a connection.
  // advertiser establishes a connection.
  AddressWithType resolved_initiating_address =
  AddressWithType resolved_initiating_address =
      ResolvePrivateAddress(initiating_address, IrkSelection::Peer)
      ResolvePrivateAddress(initiating_address).value_or(initiating_address);
          .value_or(initiating_address);


  if (resolved_initiating_address != initiating_address) {
  if (resolved_initiating_address != initiating_address) {
    DEBUG(id_, "Resolved the initiating address {} to {}", initiating_address,
    DEBUG(id_, "Resolved the initiating address {} to {}", initiating_address,
@@ -4436,8 +4429,7 @@ bool LinkLayerController::ProcessIncomingExtendedConnectRequest(
  // The advertising filter policy shall then determine if the
  // The advertising filter policy shall then determine if the
  // advertiser establishes a connection.
  // advertiser establishes a connection.
  AddressWithType resolved_initiating_address =
  AddressWithType resolved_initiating_address =
      ResolvePrivateAddress(initiating_address, IrkSelection::Peer)
      ResolvePrivateAddress(initiating_address).value_or(initiating_address);
          .value_or(initiating_address);


  if (resolved_initiating_address != initiating_address) {
  if (resolved_initiating_address != initiating_address) {
    DEBUG(id_, "Resolved the initiating address {} to {}", initiating_address,
    DEBUG(id_, "Resolved the initiating address {} to {}", initiating_address,
@@ -4871,8 +4863,7 @@ void LinkLayerController::IncomingLeScanPacket(
  // address. The advertising filter policy shall then determine if
  // address. The advertising filter policy shall then determine if
  // the advertiser processes the scan request.
  // the advertiser processes the scan request.
  AddressWithType resolved_scanning_address =
  AddressWithType resolved_scanning_address =
      ResolvePrivateAddress(scanning_address, IrkSelection::Peer)
      ResolvePrivateAddress(scanning_address).value_or(scanning_address);
          .value_or(scanning_address);


  if (resolved_scanning_address != scanning_address) {
  if (resolved_scanning_address != scanning_address) {
    DEBUG(id_, "Resolved the scanning address {} to {}", scanning_address,
    DEBUG(id_, "Resolved the scanning address {} to {}", scanning_address,
@@ -4921,8 +4912,7 @@ void LinkLayerController::IncomingLeScanResponsePacket(
  }
  }


  AddressWithType resolved_advertising_address =
  AddressWithType resolved_advertising_address =
      ResolvePrivateAddress(advertising_address, IrkSelection::Peer)
      ResolvePrivateAddress(advertising_address).value_or(advertising_address);
          .value_or(advertising_address);


  if (advertising_address != resolved_advertising_address) {
  if (advertising_address != resolved_advertising_address) {
    DEBUG(id_, "Resolved the advertising address {} to {}", advertising_address,
    DEBUG(id_, "Resolved the advertising address {} to {}", advertising_address,
+11 −2
Original line number Original line Diff line number Diff line
@@ -228,8 +228,17 @@ class LinkLayerController {
  // resolve the address using the resolving list. If the address cannot
  // resolve the address using the resolving list. If the address cannot
  // be resolved none is returned. If the address is not a Resolvable
  // be resolved none is returned. If the address is not a Resolvable
  // Private Address, the original address is returned.
  // Private Address, the original address is returned.
  std::optional<AddressWithType> ResolvePrivateAddress(AddressWithType address,
  std::optional<AddressWithType> ResolvePrivateAddress(AddressWithType address);
                                                       IrkSelection irk);

  // Returns true if the input address resolves with the local IRK
  // associated with the given peer identity address.
  bool ResolveTargetA(AddressWithType target_a, AddressWithType adv_a);

  // Returns true if either:
  //  • TargetA is identical to the device address, or
  //  • TargetA is a resolvable private address, address
  //    resolution is enabled, and the address is resolved successfully
  bool ValidateTargetA(AddressWithType target_a, AddressWithType adv_a);


  // Generate a Resolvable Private for the selected peer.
  // Generate a Resolvable Private for the selected peer.
  // If the address is not found in the resolving list none is returned.
  // If the address is not found in the resolving list none is returned.
+144 −0
Original line number Original line Diff line number Diff line
# Copyright 2023 Google LLC
#
# 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
#
#     https://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.

import hci_packets as hci
import link_layer_packets as ll
import unittest
from hci_packets import ErrorCode
from py.bluetooth import Address
from py.controller import ControllerTest, generate_rpa


class Test(ControllerTest):

    LL_initiator_scanInterval_MIN = 0x2000
    LL_initiator_scanInterval_MAX = 0x2000
    LL_initiator_scanWindow_MIN = 0x200
    LL_initiator_scanWindow_MAX = 0x200
    LL_initiator_Adv_Channel_Map = 0x7
    LL_initiator_Channel_Map = 0x7

    # LL/CON/INI/BV-08-C [Network Privacy – Connection Establishment responding
    # to connectable undirected advertising, Initiator]
    async def test(self):
        # Test parameters.
        controller = self.controller
        local_irk = bytes([1] * 16)
        peer_address = Address('aa:bb:cc:dd:ee:ff')

        if not controller.le_features.ll_privacy:
            self.skipTest("LL privacy not supported")

        # 1. Configure the Lower Tester to advertise using a valid public or static random address (identity
        # address).

        # 2. The Upper Tester adds the Identity Address of the Lower Tester to the Resolving List with all zero
        # peer IRK, and with a local IRK.
        controller.send_cmd(
            hci.LeAddDeviceToResolvingList(
                peer_irk=bytes([0] * 16),
                local_irk=local_irk,
                peer_identity_address=peer_address,
                peer_identity_address_type=hci.PeerAddressType.PUBLIC_DEVICE_OR_IDENTITY_ADDRESS))

        await self.expect_evt(
            hci.LeAddDeviceToResolvingListComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

        controller.send_cmd(hci.LeSetResolvablePrivateAddressTimeout(rpa_timeout=0x10))

        await self.expect_evt(
            hci.LeSetResolvablePrivateAddressTimeoutComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

        controller.send_cmd(hci.LeSetAddressResolutionEnable(address_resolution_enable=hci.Enable.ENABLED))

        await self.expect_evt(
            hci.LeSetAddressResolutionEnableComplete(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

        # 3. The Upper Tester enables the initiator state in the IUT.
        controller.send_cmd(
            hci.LeCreateConnection(le_scan_interval=Test.LL_initiator_scanInterval_MIN,
                                   le_scan_window=Test.LL_initiator_scanWindow_MIN,
                                   initiator_filter_policy=hci.InitiatorFilterPolicy.USE_PEER_ADDRESS,
                                   peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS,
                                   peer_address=peer_address,
                                   own_address_type=hci.OwnAddressType.RESOLVABLE_OR_PUBLIC_ADDRESS,
                                   connection_interval_min=0x200,
                                   connection_interval_max=0x200,
                                   max_latency=0x6,
                                   supervision_timeout=0xc80,
                                   min_ce_length=0,
                                   max_ce_length=0))

        await self.expect_evt(hci.LeCreateConnectionStatus(status=ErrorCode.SUCCESS, num_hci_command_packets=1))

        # 4. Lower Tester sends ADV_IND packets, each advertising event on the selected advertising
        # channel, using the selected advertising interval.
        controller.send_ll(ll.LeLegacyAdvertisingPdu(source_address=peer_address,
                                                     advertising_address_type=ll.AddressType.PUBLIC,
                                                     advertising_type=ll.LegacyAdvertisingType.ADV_IND,
                                                     advertising_data=[1, 2, 3]),
                           rssi=-16)

        # 5. The Lower Tester receives a CONNECT_IND packet T_IFS after any of the ADV_IND packets.
        # The InitA field contains a resolvable private address from the IUT.
        connect_ind = await self.expect_ll(
            ll.LeConnect(source_address=self.Any,
                         destination_address=peer_address,
                         initiating_address_type=ll.AddressType.RANDOM,
                         advertising_address_type=ll.AddressType.PUBLIC,
                         conn_interval=0x200,
                         conn_peripheral_latency=0x6,
                         conn_supervision_timeout=0xc80))

        self.assertTrue(connect_ind.source_address.is_resolvable())
        self.assertTrue(connect_ind.source_address != controller.address)

        controller.send_ll(
            ll.LeConnectComplete(source_address=peer_address,
                                 destination_address=connect_ind.source_address,
                                 initiating_address_type=ll.AddressType.RANDOM,
                                 advertising_address_type=ll.AddressType.PUBLIC,
                                 conn_interval=0x200,
                                 conn_peripheral_latency=0x6,
                                 conn_supervision_timeout=0xc80))

        # 6. Upper Tester receives an HCI_LE_Enhanced_Connection_Complete event from the IUT
        # including the Lower Tester address and connection interval selected.
        connect_complete = await self.expect_evt(
            hci.LeEnhancedConnectionComplete(status=ErrorCode.SUCCESS,
                                             connection_handle=self.Any,
                                             role=hci.Role.CENTRAL,
                                             peer_address_type=hci.AddressType.PUBLIC_DEVICE_ADDRESS,
                                             peer_address=peer_address,
                                             connection_interval=0x200,
                                             peripheral_latency=0x6,
                                             supervision_timeout=0xc80,
                                             local_resolvable_private_address=connect_ind.source_address,
                                             central_clock_accuracy=hci.ClockAccuracy.PPM_500))

        # 7. After the CONNECT_IND has been received, the Lower Tester receives the first correctly
        # formatted LL Data Channel PDU on the data channel.

        # 8. The Lower Tester sends a correctly formatted LL Data Channel PDU to the IUT on the same data
        # channel using the acknowledgement scheme.

        controller.send_ll(
            ll.Disconnect(source_address=peer_address,
                          destination_address=connect_ind.source_address,
                          reason=hci.ErrorCode.REMOTE_USER_TERMINATED_CONNECTION))

        await self.expect_evt(
            hci.DisconnectionComplete(status=hci.ErrorCode.SUCCESS,
                                      connection_handle=connect_complete.connection_handle,
                                      reason=hci.ErrorCode.REMOTE_USER_TERMINATED_CONNECTION))
+179 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading