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

Commit d120724e authored by Rahul Arya's avatar Rahul Arya
Browse files

[Connection Manager] Create API skeleton

This is a basic API for the connection manager, very similar to what exists in
connection_manager.h right now. The implementation and remaining features (e.g.
targeted announcements) will be filled in future CLs.

Bug: 272572974
Test: compiles
Change-Id: Ib63878b08b5c91b12e066d5f39db1c0489582750
parent 594b9161
Loading
Loading
Loading
Loading
+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);
}
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ mod do_not_use {
    use bt_shim::*;
}

pub mod connection;
pub mod core;
pub mod gatt;
pub mod packets;