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

Commit c37ec4af authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "RootCanal: Add LE connection packets"

parents 5e98e7ed 707af3f4
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -71,6 +71,9 @@ class GdCertDevice(GdDeviceBase):
        self.l2cap = l2cap_cert_pb2_grpc.L2capModuleCertStub(self.grpc_channel)

        # Event streams
        self.hal.hci_event_stream = EventStream(self.hal.FetchHciEvent)
        self.hal.hci_acl_stream = EventStream(self.hal.FetchHciAcl)
        self.hal.hci_sco_stream = EventStream(self.hal.FetchHciSco)
        self.hci.connection_complete_stream = EventStream(self.hci.FetchConnectionComplete)
        self.hci.disconnection_stream = EventStream(self.hci.FetchDisconnection)
        self.hci.connection_failed_stream = EventStream(self.hci.FetchConnectionFailed)
+145 −0
Original line number Diff line number Diff line
@@ -56,6 +56,9 @@ class SimpleHalTest(GdBaseTestClass):
        self.cert_device.hal.SendHciResetCommand(empty_pb2.Empty())

        self.hci_event_stream = self.device_under_test.hal.hci_event_stream
        self.cert_hci_event_stream = self.cert_device.hal.hci_event_stream
        self.hci_acl_stream = self.device_under_test.hal.hci_acl_stream
        self.cert_hci_acl_stream = self.cert_device.hal.hci_acl_stream

    def teardown_test(self):
        self.device_under_test.rootservice.StopStack(
@@ -64,6 +67,8 @@ class SimpleHalTest(GdBaseTestClass):
        self.cert_device.rootservice.StopStack(
            cert_rootservice_pb2.StopStackRequest()
        )
        self.hci_event_stream.clear_event_buffer()
        self.cert_hci_event_stream.clear_event_buffer()

    def test_none_event(self):
        self.hci_event_stream.clear_event_buffer()
@@ -109,3 +114,143 @@ class SimpleHalTest(GdBaseTestClass):
            # Expecting an HCI Event (code 0x02, length 0x0f)
        )
        self.hci_event_stream.unsubscribe()

    def test_le_ad_scan_cert_advertises(self):
        self.hci_event_stream.subscribe()

        # Set the LE Address to 0D:05:04:03:02:01
        self.device_under_test.hal.SendHciCommand(
            hal_facade_pb2.HciCommandPacket(
                payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0D'
            )
        )
        # Set the LE Scan parameters (active, 40ms, 20ms, Random, 
        self.device_under_test.hal.SendHciCommand(
            hal_facade_pb2.HciCommandPacket(
                payload=b'\x0B\x20\x07\x01\x40\x00\x20\x00\x01\x00'
            )
        )
        # Enable Scanning (Disable duplicate filtering)
        self.device_under_test.hal.SendHciCommand(
            hal_facade_pb2.HciCommandPacket(
               payload=b'\x0C\x20\x02\x01\x00'
            )
        )

        # Set the LE Address to 0C:05:04:03:02:01
        self.cert_device.hal.SendHciCommand(
            hal_facade_pb2.HciCommandPacket(
                payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0C'
            )
        )
        # Set LE Advertising parameters
        self.cert_device.hal.SendHciCommand(
            hal_facade_pb2.HciCommandPacket(
               payload=b'\x06\x20\x0F\x00\x02\x00\x03\x00\x01\x00\xA1\xA2\xA3\xA4\xA5\xA6\x07\x00'
            )
        )
        # Set LE Advertising data
        self.cert_device.hal.SendHciCommand(
            hal_facade_pb2.HciCommandPacket(
               payload=b'\x08\x20\x20\x0C\x0A\x09Im_A_Cert\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
            )
        )
        # Enable Advertising
        self.cert_device.hal.SendHciCommand(
            hal_facade_pb2.HciCommandPacket(
               payload=b'\x0A\x20\x01\x01'
            )
        )
        self.hci_event_stream.assert_event_occurs(
            lambda packet: b'Im_A_Cert' in packet.payload
            # Expecting an HCI Event (code 0x3e, length 0x13, subevent 0x01 )
        )
        # Disable Advertising
        self.cert_device.hal.SendHciCommand(
            hal_facade_pb2.HciCommandPacket(
               payload=b'\x0A\x20\x01\x00'
            )
        )
        # Disable Scanning
        self.device_under_test.hal.SendHciCommand(
            hal_facade_pb2.HciCommandPacket(
               payload=b'\x0C\x20\x02\x00\x00'
            )
        )
        self.hci_event_stream.unsubscribe()

    def test_le_connection_dut_advertises(self):
        self.hci_event_stream.subscribe()
        self.cert_hci_event_stream.subscribe()
        self.hci_acl_stream.subscribe()
        self.cert_hci_acl_stream.subscribe()

        # Set the CERT LE Address to 0C:05:04:03:02:01
        self.cert_device.hal.SendHciCommand(
            hal_cert_pb2.HciCommandPacket(
                payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0C'
            )
        )

        # Direct connect to 0D:05:04:03:02:01
        self.cert_device.hal.SendHciCommand(
            hal_cert_pb2.HciCommandPacket(
               payload=b'\x0D\x20\x19\x11\x01\x22\x02\x00\x01\x01\x02\x03\x04\x05\x0D\x01\x06\x00\x70\x0C\x40\x00\x03\x07\x01\x00\x02\x00'
            )
        )

        # Set the LE Address to 0D:05:04:03:02:01
        self.device_under_test.hal.SendHciCommand(
            hal_facade_pb2.HciCommandPacket(
                payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0D'
            )
        )
        # Set LE Advertising parameters
        self.device_under_test.hal.SendHciCommand(
            hal_facade_pb2.HciCommandPacket(
               payload=b'\x06\x20\x0F\x80\x00\x00\x04\x00\x01\x00\xA1\xA2\xA3\xA4\xA5\xA6\x07\x00'
            )
        )
        # Set LE Advertising data
        self.device_under_test.hal.SendHciCommand(
            hal_facade_pb2.HciCommandPacket(
               payload=b'\x08\x20\x20\x0C\x0B\x09Im_The_DUT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
            )
        )
        # Enable Advertising
        self.device_under_test.hal.SendHciCommand(
            hal_facade_pb2.HciCommandPacket(
               payload=b'\x0A\x20\x01\x01'
            )
        )
        # LeConnectionComplete TODO: Extract the handle
        self.cert_hci_event_stream.assert_event_occurs(
            lambda packet: b'\x3e\x13\x01' in packet.payload
        )
        # LeConnectionComplete TODO: Extract the handle
        self.hci_event_stream.assert_event_occurs(
            lambda packet: b'\x3e\x13\x01' in packet.payload
        )
        # Send ACL Data
        self.device_under_test.hal.SendHciAcl(
            hal_facade_pb2.HciAclPacket(
               payload=b'\xfe\x0e\x0b\x00SomeAclData'
            )
        )
        # Send ACL Data
        self.cert_device.hal.SendHciAcl(
            hal_facade_pb2.HciAclPacket(
               payload=b'\xfe\x0e\x0f\x00SomeMoreAclData'
            )
        )
        self.cert_hci_acl_stream.assert_event_occurs(
            lambda packet: b'\xfe\x0e\x0b\x00SomeAclData' in packet.payload
        )
        self.hci_acl_stream.assert_event_occurs(
            lambda packet: b'\xfe\x0e\x0f\x00SomeMoreAclData' in packet.payload
        )

        self.hci_event_stream.unsubscribe()
        self.cert_hci_event_stream.unsubscribe()
        self.hci_acl_stream.unsubscribe()
        self.cert_hci_acl_stream.unsubscribe()
+2 −0
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@ class Link {
    IO_CAPABILITY_RESPONSE,
    IO_CAPABILITY_NEGATIVE_RESPONSE,
    LE_ADVERTISEMENT,
    LE_CONNECT,
    LE_CONNECT_COMPLETE,
    LE_SCAN,
    LE_SCAN_RESPONSE,
    PAGE,
+19 −12
Original line number Diff line number Diff line
@@ -25,17 +25,10 @@ namespace test_vendor_lib {
// Model the connection of a device to the controller.
class AclConnection {
 public:
  AclConnection(const Address& addr) : address_(addr), connected_(false), encrypted_(false) {}
  AclConnection(Address addr) : address_(addr), address_type_(0), own_address_type_(0) {}

  virtual ~AclConnection() = default;

  void SetConnected(bool connected) {
    connected_ = connected;
  };
  bool IsConnected() const {
    return connected_;
  };

  void Encrypt() {
    encrypted_ = true;
  };
@@ -43,19 +36,33 @@ class AclConnection {
    return encrypted_;
  };

  const Address& GetAddress() const {
  Address GetAddress() const {
    return address_;
  }
  void SetAddress(const Address& address) {
  void SetAddress(Address address) {
    address_ = address;
  }

  uint8_t GetAddressType() const {
    return address_type_;
  }
  void SetAddressType(uint8_t address_type) {
    address_type_ = address_type;
  }
  uint8_t GetOwnAddressType() const {
    return own_address_type_;
  }
  void SetOwnAddressType(uint8_t address_type) {
    own_address_type_ = address_type;
  }

 private:
  Address address_;
  uint8_t address_type_;
  uint8_t own_address_type_;

  // State variables
  bool connected_;
  bool encrypted_;
  bool encrypted_{false};
};

}  // namespace test_vendor_lib
+87 −25
Original line number Diff line number Diff line
@@ -35,40 +35,82 @@ bool AclConnectionHandler::HasHandle(uint16_t handle) const {
}

uint16_t AclConnectionHandler::GetUnusedHandle() {
  static uint16_t sNextHandle = acl::kReservedHandle - 2;
  while (acl_connections_.count(sNextHandle) == 1) {
    sNextHandle = (sNextHandle + 1) % acl::kReservedHandle;
  while (acl_connections_.count(last_handle_) == 1) {
    last_handle_ = (last_handle_ + 1) % acl::kReservedHandle;
  }
  uint16_t unused_handle = sNextHandle;
  sNextHandle = (sNextHandle + 1) % acl::kReservedHandle;
  uint16_t unused_handle = last_handle_;
  last_handle_ = (last_handle_ + 1) % acl::kReservedHandle;
  return unused_handle;
}

bool AclConnectionHandler::CreatePendingConnection(const Address& addr) {
  if ((pending_connections_.size() + 1 > max_pending_connections_) || HasPendingConnection(addr)) {
bool AclConnectionHandler::CreatePendingConnection(Address addr) {
  if (classic_connection_pending_) {
    return false;
  }
  pending_connections_.insert(addr);
  classic_connection_pending_ = true;
  pending_connection_address_ = addr;
  return true;
}

bool AclConnectionHandler::HasPendingConnection(const Address& addr) {
  return pending_connections_.count(addr) == 1;
bool AclConnectionHandler::HasPendingConnection(Address addr) {
  return classic_connection_pending_ && pending_connection_address_ == addr;
}

bool AclConnectionHandler::CancelPendingConnection(const Address& addr) {
  if (!HasPendingConnection(addr)) {
bool AclConnectionHandler::CancelPendingConnection(Address addr) {
  if (!classic_connection_pending_ || pending_connection_address_ != addr) {
    return false;
  }
  pending_connections_.erase(addr);
  classic_connection_pending_ = false;
  pending_connection_address_ = Address::kEmpty;
  return true;
}

uint16_t AclConnectionHandler::CreateConnection(const Address& addr) {
bool AclConnectionHandler::CreatePendingLeConnection(Address addr, uint8_t address_type) {
  if (IsDeviceConnected(addr, address_type)) {
    LOG_INFO(LOG_TAG, "%s: %s (type %hhx) is already connected", __func__, addr.ToString().c_str(), address_type);
    return false;
  }
  if (le_connection_pending_) {
    LOG_INFO(LOG_TAG, "%s: connection already pending", __func__);
    return false;
  }
  le_connection_pending_ = true;
  pending_le_connection_address_ = addr;
  pending_le_connection_address_type_ = address_type;
  return true;
}

bool AclConnectionHandler::HasPendingLeConnection(Address addr, uint8_t address_type) {
  return le_connection_pending_ && pending_le_connection_address_ == addr &&
         pending_le_connection_address_type_ == address_type;
}

bool AclConnectionHandler::CancelPendingLeConnection(Address addr, uint8_t address_type) {
  if (!le_connection_pending_ || pending_le_connection_address_ != addr ||
      pending_le_connection_address_type_ != address_type) {
    return false;
  }
  le_connection_pending_ = false;
  pending_le_connection_address_ = Address::kEmpty;
  pending_le_connection_address_type_ = 0xba;
  return true;
}

uint16_t AclConnectionHandler::CreateConnection(Address addr) {
  if (CancelPendingConnection(addr)) {
    uint16_t handle = GetUnusedHandle();
    acl_connections_.emplace(handle, addr);
    SetConnected(handle, true);
    return handle;
  }
  return acl::kReservedHandle;
}

uint16_t AclConnectionHandler::CreateLeConnection(Address addr, uint8_t address_type, uint8_t own_address_type) {
  if (CancelPendingLeConnection(addr, address_type)) {
    uint16_t handle = GetUnusedHandle();
    acl_connections_.emplace(handle, addr);
    set_own_address_type(handle, own_address_type);
    SetAddress(handle, addr, address_type);
    return handle;
  }
  return acl::kReservedHandle;
@@ -78,7 +120,7 @@ bool AclConnectionHandler::Disconnect(uint16_t handle) {
  return acl_connections_.erase(handle) > 0;
}

uint16_t AclConnectionHandler::GetHandle(const Address& addr) const {
uint16_t AclConnectionHandler::GetHandle(Address addr) const {
  for (auto pair : acl_connections_) {
    if (std::get<AclConnection>(pair).GetAddress() == addr) {
      return std::get<0>(pair);
@@ -87,23 +129,41 @@ uint16_t AclConnectionHandler::GetHandle(const Address& addr) const {
  return acl::kReservedHandle;
}

const Address& AclConnectionHandler::GetAddress(uint16_t handle) const {
Address AclConnectionHandler::GetAddress(uint16_t handle) const {
  CHECK(HasHandle(handle)) << "Handle unknown " << handle;
  return acl_connections_.at(handle).GetAddress();
}

void AclConnectionHandler::SetConnected(uint16_t handle, bool connected) {
  if (!HasHandle(handle)) {
    return;
uint8_t AclConnectionHandler::GetAddressType(uint16_t handle) const {
  CHECK(HasHandle(handle)) << "Handle unknown " << handle;
  return acl_connections_.at(handle).GetAddressType();
}
  acl_connections_.at(handle).SetConnected(connected);

void AclConnectionHandler::set_own_address_type(uint16_t handle, uint8_t address_type) {
  CHECK(HasHandle(handle)) << "Handle unknown " << handle;
  acl_connections_.at(handle).SetOwnAddressType(address_type);
}

uint8_t AclConnectionHandler::GetOwnAddressType(uint16_t handle) const {
  CHECK(HasHandle(handle)) << "Handle unknown " << handle;
  return acl_connections_.at(handle).GetOwnAddressType();
}

bool AclConnectionHandler::IsConnected(uint16_t handle) const {
  if (!HasHandle(handle)) {
    return false;
  }
  return acl_connections_.at(handle).IsConnected();
  return true;
}

bool AclConnectionHandler::IsDeviceConnected(Address addr, uint8_t address_type) const {
  for (auto pair : acl_connections_) {
    auto connection = std::get<AclConnection>(pair);
    if (connection.GetAddress() == addr && connection.GetAddressType() == address_type) {
      return true;
    }
  }
  return false;
}

void AclConnectionHandler::Encrypt(uint16_t handle) {
@@ -120,11 +180,13 @@ bool AclConnectionHandler::IsEncrypted(uint16_t handle) const {
  return acl_connections_.at(handle).IsEncrypted();
}

void AclConnectionHandler::SetAddress(uint16_t handle, const Address& address) {
void AclConnectionHandler::SetAddress(uint16_t handle, Address address, uint8_t address_type) {
  if (!HasHandle(handle)) {
    return;
  }
  acl_connections_.at(handle).SetAddress(address);
  auto connection = acl_connections_.at(handle);
  connection.SetAddress(address);
  connection.SetAddressType(address_type);
}

}  // namespace test_vendor_lib
Loading