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

Commit a8747544 authored by Rahul Arya's avatar Rahul Arya Committed by Gerrit Code Review
Browse files

Merge changes Ib63878b0,I399bb1f2,Ida0b0218,I80ab16df,I9dfdca7c

* changes:
  [Connection Manager] Create API skeleton
  [Connection Manager] Expose AddressWithType over FFI
  [Connection Manager] Add new_cyclic to SharedBox
  [Connection Manager] Clean up build.rs
  [Connection Manager] Fix IsPublic() method
parents 36e4fb4c d120724e
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@ fn main() {
    let dest_file = File::create(dest_path).unwrap();

    let pdl = Command::new("pdl")
        .args(&["--output-format", "rust_no_alloc", "src/packets.pdl"])
        .args(["--output-format", "rust_no_alloc", "src/packets.pdl"])
        .stdout(Stdio::piped())
        .spawn()
        .unwrap();
@@ -22,7 +22,7 @@ fn main() {
    rustfmt.wait().unwrap();

    if let Some(err) = rustfmt.stderr {
        panic!("{:?}", err);
        panic!("{err:?}");
    }

    println!("cargo:rerun-if-changed=build.rs");
+156 −0
Original line number Diff line number Diff line
//! This module manages LE connection requests and active
//! LE connections. In particular, it de-duplicates connection requests,
//! avoids duplicate connections to the same devices (even with different RPAs),
//! and retries failed connections

use std::{fmt::Debug, hash::Hash, ops::Deref};

use crate::{
    core::{
        address::AddressWithType,
        shared_box::{SharedBox, WeakBox},
    },
    gatt::ids::ServerId,
};

use self::le_manager::{
    ErrorCode, InactiveLeAclManager, LeAclManager, LeAclManagerConnectionCallbacks,
};

pub mod le_manager;

/// Possible errors returned when making a connection attempt
#[derive(Debug)]
pub enum CreateConnectionFailure {
    /// This client is already making a connection of the same type
    /// to the same address.
    ConnectionAlreadyPending,
}

/// Errors returned if a connection successfully starts but fails afterwards.
#[derive(Debug)]
pub enum ConnectionFailure {
    /// The connection attempt was cancelled
    Cancelled,
}

/// Errors returned if the client fails to cancel their connection attempt
#[derive(Debug)]
pub enum CancelConnectFailure {
    /// The connection attempt does not exist
    ConnectionNotPending,
}

/// Unique identifiers for a client of the connection manager
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum ConnectionManagerClient {
    /// A GATT client with given client ID
    GattClient(u8),
    /// A GATT server with given server ID
    GattServer(ServerId),
}

/// An active connection
#[derive(Copy, Clone, Debug)]
pub struct LeConnection {
    /// The address of the peer device, as reported in the connection complete event
    pub remote_address: AddressWithType,
}

/// Responsible for managing the initiator state and the list of
/// devices on the filter accept list
#[derive(Debug)]
pub struct ConnectionManager {
    _le_manager: Box<dyn LeAclManager>,
}

struct ConnectionManagerCallbackHandler(WeakBox<ConnectionManager>);

impl LeAclManagerConnectionCallbacks for ConnectionManagerCallbackHandler {
    fn on_le_connect_success(&self, conn: LeConnection) {
        self.with_manager(|manager| manager.on_le_connect_success(conn))
    }

    fn on_le_connect_fail(&self, address: AddressWithType, status: ErrorCode) {
        self.with_manager(|manager| manager.on_le_connect_fail(address, status))
    }

    fn on_disconnect(&self, address: AddressWithType) {
        self.with_manager(|manager| manager.on_disconnect(address))
    }
}

impl ConnectionManagerCallbackHandler {
    fn with_manager(&self, f: impl FnOnce(&ConnectionManager)) {
        self.0.with(|manager| f(manager.expect("got connection event after stack died").deref()))
    }
}

impl ConnectionManager {
    /// Constructor
    pub fn new(le_manager: impl InactiveLeAclManager) -> SharedBox<Self> {
        SharedBox::new_cyclic(|weak| Self {
            _le_manager: Box::new(
                le_manager.register_callbacks(ConnectionManagerCallbackHandler(weak)),
            ),
        })
    }

    /// Start a direct connection to a peer device from a specified client.
    pub fn start_direct_connection(
        &self,
        _client: ConnectionManagerClient,
        _address: AddressWithType,
    ) -> Result<(), CreateConnectionFailure> {
        todo!()
    }

    /// Cancel direct connection attempts from this client to the specified address.
    pub fn cancel_direct_connection(
        &self,
        _client: ConnectionManagerClient,
        _address: AddressWithType,
    ) -> Result<(), CancelConnectFailure> {
        todo!()
    }

    /// Start a background connection to a peer device with given parameters from a specified client.
    pub fn add_background_connection(
        &self,
        _client: ConnectionManagerClient,
        _address: AddressWithType,
    ) -> Result<(), CreateConnectionFailure> {
        todo!()
    }

    /// Cancel background connection attempts from this client to the specified address.
    pub fn remove_background_connection(
        &self,
        _client: ConnectionManagerClient,
        _address: AddressWithType,
    ) -> Result<(), CancelConnectFailure> {
        todo!()
    }

    /// Cancel all connection attempts to this address
    pub fn cancel_unconditionally(&self, _address: AddressWithType) {
        todo!()
    }

    /// Cancel all connection attempts from this client
    pub fn remove_client(&self, _client: ConnectionManagerClient) {
        todo!()
    }

    fn on_le_connect_success(&self, _conn: LeConnection) {
        todo!()
    }

    fn on_le_connect_fail(&self, _address: AddressWithType, _status: ErrorCode) {
        todo!()
    }

    fn on_disconnect(&self, _address: AddressWithType) {
        todo!()
    }
}
+64 −0
Original line number Diff line number Diff line
//! This trait represents the lower-level operations
//! made available to the connection manager. In particular,
//! we can add devices to either the "direct" or "background"
//! connect list, which are in turn mapped to an appropriate choice
//! of scan parameters / the filter accept list.
//!
//! Note that the ACL manager is unaware of address resolution,
//! so this must be handled by the connection manager. Conversely, the connection
//! manager does not need to consider the HCI state machine, and can send requests
//! at any time.
//!
//! In addition to the supplied API, when a connection completes to a peer device,
//! it is removed from the "direct" connect list (based on exact address match).

use std::fmt::Debug;

use crate::core::address::AddressWithType;

use super::LeConnection;

/// An HCI Error Code from the controller
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct ErrorCode(pub u8);

impl ErrorCode {
    /// Operation completed successfully
    pub const SUCCESS: Self = ErrorCode(0);
}

/// The LeAclManager before callbacks are registered
pub trait InactiveLeAclManager {
    /// The type implementing LeAclManager once callbacks are registered
    type ActiveManager: LeAclManager + 'static;

    /// Register callbacks for connection events, and produuce an ActiveManager
    fn register_callbacks(
        self,
        callbacks: impl LeAclManagerConnectionCallbacks + 'static,
    ) -> Self::ActiveManager;
}

/// The operations provided by GD AclManager to the connection manager
pub trait LeAclManager: Debug {
    /// Adds an address to the direct connect list, if not already connected.
    /// WARNING: the connection timeout is set the FIRST time the address is added, and is
    /// NOT RESET! TODO(aryarahul): remove connection timeout from le_impl since it belongs here instead
    /// Precondition: Must NOT be currently connected to this adddress (if connected due to race, is a no-op)
    fn add_to_direct_list(&self, address: AddressWithType); // CreateLeConnection(is_direct=true)
    /// Adds an address to the background connect list
    fn add_to_background_list(&self, address: AddressWithType); // CreateLeConnection(is_direct=false)
    /// Removes address from both the direct + background connect lists
    /// Due to races, it is possible to call this, and THEN get a connection complete with us as central
    fn remove_from_all_lists(&self, address: AddressWithType); // CancelLeConnect
}

/// The callbacks invoked by the LeAclManager in response to events from the controller
pub trait LeAclManagerConnectionCallbacks {
    /// Invoked when an LE connection to a given address completes
    fn on_le_connect_success(&self, conn: LeConnection);
    /// Invoked when an LE connection attempt has failed / times out
    fn on_le_connect_fail(&self, address: AddressWithType, status: ErrorCode);
    /// Invoked when a peer device disconnects from us
    fn on_disconnect(&self, address: AddressWithType);
}
+26 −0
Original line number Diff line number Diff line
//! An address with type (public / random)

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
#[repr(C)]
/// The type of an LE address (see: 5.3 Vol 6B 1.3 Device Axddress)
pub enum AddressType {
    /// A public address
    Public = 0x0,
    /// A random address (either random static or private)
    Random = 0x1,
}

/// An LE address
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
#[repr(C)]
pub struct AddressWithType {
    /// The 6 address bytes stored in little-endian format
    pub address: [u8; 6],
    /// The address type, either public or random
    pub address_type: AddressType,
}

impl AddressWithType {
    /// An empty/invalid address
    pub const EMPTY: Self = Self { address: [0, 0, 0, 0, 0, 0], address_type: AddressType::Public };
}
+17 −0
Original line number Diff line number Diff line
@@ -24,9 +24,26 @@ unsafe impl ExternType for Uuid {
    type Kind = cxx::kind::Trivial;
}

unsafe impl ExternType for AddressWithType {
    type Id = type_id!("bluetooth::core::AddressWithType");
    type Kind = cxx::kind::Trivial;
}

#[allow(dead_code, missing_docs)]
#[cxx::bridge]
mod inner {
    #[derive(Debug)]
    pub enum AddressTypeForFFI {
        Public,
        Random,
    }

    #[namespace = "bluetooth::core"]
    extern "C++" {
        include!("src/core/ffi/types.h");
        type AddressWithType = crate::core::address::AddressWithType;
    }

    #[namespace = "bluetooth"]
    extern "C++" {
        include!("bluetooth/uuid.h");
Loading