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

Commit f5dcab4b authored by Abhishek Pandit-Subedi's avatar Abhishek Pandit-Subedi
Browse files

floss: Update socket topshim for connection complete

Add a converter for ConnectionComplete in socket profile and make a few
other housekeeping changes.

Bug: 233123287
Tag: #floss
Test: ./build.py --target test
Change-Id: Icdd26add53038499c598bdf95602f3a717e1593b
parent f5eb27f2
Loading
Loading
Loading
Loading
+9 −9
Original line number Diff line number Diff line
@@ -25,15 +25,15 @@ bt_facade_helpers = { path = "../facade/helpers" }
bluetooth_rs = { path = "../stack" }
topshim_macros = { path = "macros" }

cxx = "*"
lazy_static = "*"
log = "*"
proc-macro2 = "*"
num-derive = "*"
num-traits = "*"
tokio = { version = "*", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] }
tokio-stream = "*"
bitflags ="*"
cxx = "1.0"
lazy_static = "1.4"
log = "0.4"
num-derive = "0.3"
num-traits = "0.2"
proc-macro2 = "1.0"
tokio = { version = "1", features = ['bytes', 'fs', 'io-util', 'libc', 'macros', 'memchr', 'mio', 'net', 'num_cpus', 'rt', 'rt-multi-thread', 'sync', 'time', 'tokio-macros'] }
tokio-stream = "0.1"
bitflags ="1.2"

[build-dependencies]
bindgen = "0.59"
+7 −1
Original line number Diff line number Diff line
@@ -175,7 +175,7 @@ impl From<u32> for BtDiscoveryState {
    }
}

#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[derive(Clone, Copy, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtStatus {
    Success = 0,
@@ -227,6 +227,12 @@ impl From<bindings::bt_status_t> for BtStatus {
    }
}

impl Into<u32> for BtStatus {
    fn into(self) -> u32 {
        self.to_u32().unwrap_or_default()
    }
}

impl From<bindings::bt_bdname_t> for String {
    fn from(item: bindings::bt_bdname_t) -> Self {
        ascii_to_string(&item.name, item.name.len())
+126 −6
Original line number Diff line number Diff line
use num_traits::cast::{FromPrimitive, ToPrimitive};
use std::convert::{TryFrom, TryInto};
use std::ffi::CString;
use std::fs::File;
use std::os::unix::io::FromRawFd;

use crate::bindings::root as bindings;
use crate::btif::{
    BluetoothInterface, BtStatus, FfiAddress, RawAddress, SupportedProfiles, Uuid, Uuid128Bit,
};
use crate::{cast_to_ffi_address, ccall};

use num_traits::cast::{FromPrimitive, ToPrimitive};
use std::ffi::CString;
use std::fs::File;
use std::os::unix::io::FromRawFd;

#[derive(Clone, Debug, FromPrimitive, ToPrimitive)]
#[repr(u32)]
/// Socket interface type.
@@ -34,6 +35,83 @@ impl From<SocketType> for bindings::btsock_type_t {
    }
}

/// Socket flag: No flags (used for insecure connections).
pub const SOCK_FLAG_NONE: i32 = 0;
/// Socket flag: connection must be encrypted.
pub const SOCK_FLAG_ENCRYPT: i32 = 1 << 0;
/// Socket flag: require authentication.
pub const SOCK_FLAG_AUTH: i32 = 1 << 1;
/// Socket flag: don't generate SDP entry for listening socket.
pub const SOCK_FLAG_NO_SDP: i32 = 1 << 2;
/// Socket flag: require authentication with MITM protection.
pub const SOCK_FLAG_AUTH_MITM: i32 = 1 << 3;
/// Socket flag: require a minimum of 16 digits for sec mode 2 connections.
pub const SOCK_FLAG_AUTH_16_DIGIT: i32 = 1 << 4;
/// Socket flag: LE connection oriented channel.
pub const SOCK_FLAG_LE_COC: i32 = 1 << 5;

/// Combination of SOCK_FLAG_ENCRYPT and SOCK_FLAG_AUTH.
pub const SOCK_META_FLAG_SECURE: i32 = SOCK_FLAG_ENCRYPT | SOCK_FLAG_AUTH;

/// Struct showing a completed socket event. This is the first data that should
/// arrive on a connecting socket once it is connected.
pub struct ConnectionComplete {
    pub size: u16,
    pub addr: RawAddress,
    pub channel: i32,
    pub status: i32,
    pub max_tx_packet_size: u16,
    pub max_rx_packet_size: u16,
}

/// Size of connect complete data. The data read from libbluetooth is packed but
/// the Rust struct is not, so depend on this value for validation.
pub const CONNECT_COMPLETE_SIZE: usize = 20;

// Convert from raw bytes to struct.
impl TryFrom<&[u8]> for ConnectionComplete {
    type Error = String;

    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
        if bytes.len() != CONNECT_COMPLETE_SIZE {
            return Err(format!("Wrong number of bytes for Connection Complete: {}", bytes.len()));
        }

        // The ConnectComplete event is constructed within libbluetooth and uses
        // the native endianness of the machine when writing to the socket. When
        // parsing, make sure to use native endianness here.
        let (size_bytes, rest) = bytes.split_at(std::mem::size_of::<u16>());
        if u16::from_ne_bytes(size_bytes.clone().try_into().unwrap())
            != (CONNECT_COMPLETE_SIZE as u16)
        {
            return Err(format!("Wrong size in Connection Complete: {:?}", size_bytes));
        }

        // We know from previous size checks that all these splits will work.
        let (addr_bytes, rest) = rest.split_at(std::mem::size_of::<RawAddress>());
        let (channel_bytes, rest) = rest.split_at(std::mem::size_of::<i32>());
        let (status_bytes, rest) = rest.split_at(std::mem::size_of::<i32>());
        let (max_tx_packet_size_bytes, rest) = rest.split_at(std::mem::size_of::<u16>());
        let (max_rx_packet_size_bytes, _unused) = rest.split_at(std::mem::size_of::<u16>());

        let addr = match RawAddress::from_bytes(addr_bytes) {
            Some(v) => v,
            None => {
                return Err("Invalid address in Connection Complete".into());
            }
        };

        Ok(ConnectionComplete {
            size: CONNECT_COMPLETE_SIZE.try_into().unwrap_or_default(),
            addr,
            channel: i32::from_ne_bytes(channel_bytes.try_into().unwrap()),
            status: i32::from_ne_bytes(status_bytes.try_into().unwrap()),
            max_tx_packet_size: u16::from_ne_bytes(max_tx_packet_size_bytes.try_into().unwrap()),
            max_rx_packet_size: u16::from_ne_bytes(max_rx_packet_size_bytes.try_into().unwrap()),
        })
    }
}

/// Represents the standard BT SOCKET interface.
///
/// For parameter documentation, see the type |sock_connect_signal_t|.
@@ -54,7 +132,7 @@ pub struct BtSocket {

pub type FdError = &'static str;

fn try_from_fd(fd: i32) -> Result<File, FdError> {
pub fn try_from_fd(fd: i32) -> Result<File, FdError> {
    if fd >= 0 {
        Ok(unsafe { File::from_raw_fd(fd) })
    } else {
@@ -148,3 +226,45 @@ impl BtSocket {
        ccall!(self, request_max_tx_data_length, ffi_addr);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_conncomplete_parsing() {
        // Actual slice size doesn't match
        let small_input = [0u8; 18];
        let large_input = [0u8; 21];

        assert_eq!(false, ConnectionComplete::try_from(&small_input[0..]).is_ok());
        assert_eq!(false, ConnectionComplete::try_from(&large_input[0..]).is_ok());

        // Size param in slice doesn't match.
        let mut size_no_match = vec![0x0u8, 0x13u8];
        size_no_match.extend([0u8; 18]);

        assert_eq!(false, ConnectionComplete::try_from(size_no_match.as_slice()).is_ok());

        // Valid input with various values.
        let raw_addr = RawAddress { val: [0x1, 0x2, 0x3, 0x4, 0x5, 0x6] };
        let mut valid: Vec<u8> = vec![];
        valid.extend(u16::to_ne_bytes(20));
        valid.extend(raw_addr.to_byte_arr());
        valid.extend(i32::to_ne_bytes(1));
        valid.extend(i32::to_ne_bytes(5));
        valid.extend(u16::to_ne_bytes(16));
        valid.extend(u16::to_ne_bytes(17));

        let result = ConnectionComplete::try_from(valid.as_slice());
        assert_eq!(true, result.is_ok());

        if let Ok(cc) = result {
            assert_eq!(cc.size, 20u16);
            assert_eq!(cc.channel, 1);
            assert_eq!(cc.status, 5);
            assert_eq!(cc.max_tx_packet_size, 16u16);
            assert_eq!(cc.max_rx_packet_size, 17u16);
        }
    }
}