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

Commit 4e049bf8 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "system/rust/gatt: Switch to the default PDL rust generator" into main am: fa9654de

parents 471f621e fa9654de
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -36,8 +36,10 @@ rust_defaults {
        "libbitflags",
        "libbt_common",
        "libbt_shim",
        "libbytes",
        "libcxx",
        "liblog_rust",
        "libpdl_runtime",
        "libscopeguard",
    ],
    whole_static_libs: [
@@ -193,7 +195,7 @@ gensrcs {

genrule {
    name: "bluetooth_core_rust_packets",
    defaults: ["pdl_rust_noalloc_generator_defaults"],
    defaults: ["pdl_rust_generator_defaults"],
    srcs: ["src/packets.pdl"],
    out: ["_packets.rs"],
}
+3 −2
Original line number Diff line number Diff line
@@ -31,13 +31,14 @@ android_logger = "*"
jni = "*"
paste = "*"
async-trait = "*"
pdl-runtime = "0.3.0"
pdl-runtime = "0.3.1"
tokio-test = "0.4.2"
tokio = { version = "1.23.0", features = ["macros"] }
scopeguard = "1.1.0"
bytes = "1.5.0"

[build-dependencies]
pdl-compiler = "0.3.0"
pdl-compiler = "0.3.1"

[lib]
crate-type = ["rlib"]
+1 −3
Original line number Diff line number Diff line
@@ -2,7 +2,6 @@
//!
//! Run `cargo install --path .` in `external/rust/crates/pdl-compiler` to ensure `pdlc`
//! is in your path.
use pdl_compiler;
use std::{env, fs::File, io::Write, path::Path};

fn main() {
@@ -13,9 +12,8 @@ fn main() {
    let mut sources = pdl_compiler::ast::SourceDatabase::new();
    let file = pdl_compiler::parser::parse_file(&mut sources, "src/packets.pdl")
        .expect("failed to parse input pdl file");
    let schema = pdl_compiler::backends::intermediate::generate(&file).unwrap();

    let generated = pdl_compiler::backends::rust_no_allocation::generate(&file, &schema).unwrap();
    let generated = pdl_compiler::backends::rust::generate(&sources, &file, &[]);
    dest_file.write_all(generated.as_bytes()).unwrap();

    println!("cargo:rerun-if-changed=build.rs");
+30 −47
Original line number Diff line number Diff line
//! A UUID (See Core Spec 5.3 Vol 1E 2.9.1. Basic Types)

use crate::packets::{
    ParseError, Uuid128Builder, Uuid128View, Uuid16Builder, Uuid16View, UuidBuilder, UuidView,
};
use crate::packets::att;

/// A UUID (See Core Spec 5.3 Vol 1E 2.9.1. Basic Types)
///
@@ -33,83 +31,74 @@ impl Uuid {
    }
}

impl TryFrom<UuidView<'_>> for Uuid {
    type Error = ParseError;
impl TryFrom<att::Uuid> for Uuid {
    type Error = att::Uuid;

    fn try_from(value: UuidView<'_>) -> Result<Self, ParseError> {
        let bytes = value.get_data_iter().collect::<Vec<_>>();
    fn try_from(value: att::Uuid) -> Result<Self, att::Uuid> {
        let bytes = value.data.as_slice();
        Ok(match bytes.len() {
            2 => Self::new(u16::from_le_bytes([bytes[0], bytes[1]]) as u32),
            4 => Self::new(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]])),
            // TODO(aryarahul) - should we handle >16 byte Uuids and drop extra bytes?
            _ => Self::new_from_le_bytes(
                bytes.try_into().map_err(|_| ParseError::OutOfBoundsAccess)?,
            ),
            _ => Self::new_from_le_bytes(bytes.try_into().map_err(|_| value)?),
        })
    }
}

impl From<Uuid16View<'_>> for Uuid {
    fn from(uuid: Uuid16View) -> Self {
        Self::new(uuid.get_data() as u32)
impl From<att::Uuid16> for Uuid {
    fn from(uuid: att::Uuid16) -> Self {
        Self::new(uuid.data as u32)
    }
}

impl From<Uuid128View<'_>> for Uuid {
    fn from(uuid: Uuid128View) -> Self {
        Self::new_from_le_bytes(
            uuid.get_data_iter()
                .collect::<Vec<_>>()
                .try_into()
                .expect("Uuid128View MUST have exactly 16 bytes"),
        )
impl From<att::Uuid128> for Uuid {
    fn from(uuid: att::Uuid128) -> Self {
        Self::new_from_le_bytes(uuid.data)
    }
}

impl From<Uuid> for UuidBuilder {
impl From<Uuid> for att::Uuid {
    fn from(value: Uuid) -> Self {
        // TODO(aryarahul): compress to UUID-16 if possible
        UuidBuilder { data: value.le_bytes().into_iter().collect() }
        att::Uuid { data: value.le_bytes().to_vec() }
    }
}

impl TryFrom<Uuid> for Uuid16Builder {
impl TryFrom<Uuid> for att::Uuid16 {
    type Error = Uuid;

    fn try_from(value: Uuid) -> Result<Self, Self::Error> {
        let backing = u128::from_be_bytes(value.0);
        if backing & ((1u128 << 96) - 1) == BASE_UUID {
            if let Ok(data) = u16::try_from(backing >> 96) {
                return Ok(Uuid16Builder { data });
                return Ok(att::Uuid16 { data });
            }
        }
        Err(value)
    }
}

impl From<Uuid> for Uuid128Builder {
impl From<Uuid> for att::Uuid128 {
    fn from(value: Uuid) -> Self {
        Uuid128Builder { data: value.le_bytes().to_vec().into() }
        att::Uuid128 { data: value.le_bytes() }
    }
}

#[cfg(test)]
mod test {
    use crate::utils::packet::build_view_or_crash;

    use super::*;

    #[test]
    fn test_uuid16_builder_successful() {
        let uuid = Uuid::new(0x0102);
        let builder: Uuid16Builder = uuid.try_into().unwrap();
        let builder: att::Uuid16 = uuid.try_into().unwrap();
        assert_eq!(builder.data, 0x0102);
    }

    #[test]
    fn test_uuid16_builder_fail_nonzero_trailing_bytes() {
        let uuid = Uuid::new(0x01020304);
        let res: Result<Uuid16Builder, _> = uuid.try_into();
        let res: Result<att::Uuid16, _> = uuid.try_into();
        assert!(res.is_err());
    }

@@ -118,14 +107,14 @@ mod test {
        let mut uuid = Uuid::new(0x0102);
        uuid.0[0] = 1;

        let res: Result<Uuid16Builder, _> = uuid.try_into();
        let res: Result<att::Uuid16, _> = uuid.try_into();
        assert!(res.is_err());
    }

    #[test]
    fn test_uuid128_builder() {
        let uuid = Uuid::new(0x01020304);
        let builder: Uuid128Builder = uuid.into();
        let builder: att::Uuid128 = uuid.into();
        assert_eq!(builder.data[..12], BASE_UUID.to_le_bytes()[..12]);
        assert_eq!(builder.data[12..], [4, 3, 2, 1]);
    }
@@ -133,7 +122,7 @@ mod test {
    #[test]
    fn test_uuid_builder() {
        let uuid = Uuid::new(0x01020304);
        let builder: UuidBuilder = uuid.into();
        let builder: att::Uuid = uuid.into();
        assert_eq!(builder.data[..12], BASE_UUID.to_le_bytes()[..12]);
        assert_eq!(builder.data[12..], [4, 3, 2, 1]);
    }
@@ -141,7 +130,7 @@ mod test {
    #[test]
    fn test_uuid_from_16_fixed_view() {
        let expected = Uuid::new(0x0102);
        let actual: Uuid = build_view_or_crash(Uuid16Builder { data: 0x0102 }).view().into();
        let actual: Uuid = att::Uuid16 { data: 0x0102 }.try_into().unwrap();
        assert_eq!(expected, actual);
    }

@@ -149,25 +138,21 @@ mod test {
    fn test_uuid_from_128_fixed_view() {
        let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
        let expected = Uuid::new_from_le_bytes(data);
        let actual: Uuid = build_view_or_crash(Uuid128Builder { data: data.into() }).view().into();
        let actual: Uuid = att::Uuid128 { data }.try_into().unwrap();
        assert_eq!(expected, actual);
    }

    #[test]
    fn test_uuid_from_16_view() {
        let expected = Uuid::new(0x0102);
        let actual: Uuid =
            build_view_or_crash(UuidBuilder { data: [2, 1].into() }).view().try_into().unwrap();
        let actual: Uuid = att::Uuid { data: vec![2, 1] }.try_into().unwrap();
        assert_eq!(expected, actual);
    }

    #[test]
    fn test_uuid_from_32_view() {
        let expected = Uuid::new(0x01020304);
        let actual: Uuid = build_view_or_crash(UuidBuilder { data: [4, 3, 2, 1].into() })
            .view()
            .try_into()
            .unwrap();
        let actual: Uuid = att::Uuid { data: vec![4, 3, 2, 1] }.try_into().unwrap();
        assert_eq!(expected, actual);
    }

@@ -175,16 +160,14 @@ mod test {
    fn test_uuid_from_128_view() {
        let data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
        let expected = Uuid::new_from_le_bytes(data);
        let actual: Uuid =
            build_view_or_crash(UuidBuilder { data: data.into() }).view().try_into().unwrap();
        let actual: Uuid = att::Uuid { data: data.into() }.try_into().unwrap();
        assert_eq!(expected, actual);
    }

    #[test]
    fn test_uuid_from_invalid_view() {
        let packet =
            build_view_or_crash(UuidBuilder { data: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1].into() });
        let res = Uuid::try_from(packet.view());
        let packet = att::Uuid { data: vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1] };
        let res = Uuid::try_from(packet);
        assert!(res.is_err());
    }
}
+23 −36
Original line number Diff line number Diff line
//! This module handles "arbitration" of ATT packets, to determine whether they
//! should be handled by the primary stack or by the Rust stack

use pdl_runtime::Packet;
use std::sync::{Arc, Mutex};

use log::{error, trace, warn};
use std::sync::RwLock;

use crate::{
    do_in_rust_thread,
    packets::{AttOpcode, OwnedAttView, OwnedPacket},
};
use crate::{do_in_rust_thread, packets::att};

use super::{
    ffi::{InterceptAction, StoreCallbacksFromRust},
@@ -62,19 +60,19 @@ pub fn has_arbiter() -> bool {
fn try_parse_att_server_packet(
    isolation_manager: &IsolationManager,
    tcb_idx: TransportIndex,
    packet: Box<[u8]>,
) -> Option<OwnedAttView> {
    packet: &[u8],
) -> Option<att::Att> {
    isolation_manager.get_server_id(tcb_idx)?;

    let att = OwnedAttView::try_parse(packet).ok()?;
    let att = att::Att::decode_full(packet).ok()?;

    if att.view().get_opcode() == AttOpcode::EXCHANGE_MTU_REQUEST {
    if att.opcode == att::AttOpcode::ExchangeMtuRequest {
        // special case: this server opcode is handled by legacy stack, and we snoop
        // on its handling, since the MTU is shared between the client + server
        return None;
    }

    match classify_opcode(att.view().get_opcode()) {
    match classify_opcode(att.opcode) {
        OperationType::Command | OperationType::Request | OperationType::Confirmation => Some(att),
        _ => None,
    }
@@ -123,13 +121,13 @@ fn intercept_packet(tcb_idx: u8, packet: Vec<u8>) -> InterceptAction {
    }

    let tcb_idx = TransportIndex(tcb_idx);
    if let Some(att) = with_arbiter(|arbiter| {
        try_parse_att_server_packet(arbiter, tcb_idx, packet.into_boxed_slice())
    }) {
    if let Some(att) =
        with_arbiter(|arbiter| try_parse_att_server_packet(arbiter, tcb_idx, &packet))
    {
        do_in_rust_thread(move |modules| {
            trace!("pushing packet to GATT");
            if let Some(bearer) = modules.gatt_module.get_bearer(tcb_idx) {
                bearer.handle_packet(att.view())
                bearer.handle_packet(att)
            } else {
                error!("Bearer for {tcb_idx:?} not found");
            }
@@ -160,10 +158,7 @@ mod test {

    use crate::{
        gatt::ids::{AttHandle, ServerId},
        packets::{
            AttBuilder, AttExchangeMtuRequestBuilder, AttOpcode, AttReadRequestBuilder,
            Serializable,
        },
        packets::att,
    };

    const TCB_IDX: TransportIndex = TransportIndex(1);
@@ -183,15 +178,12 @@ mod test {
    #[test]
    fn test_packet_capture_when_isolated() {
        let isolation_manager = create_manager_with_isolated_connection(TCB_IDX, SERVER_ID);
        let packet = AttBuilder {
            opcode: AttOpcode::READ_REQUEST,
            _child_: AttReadRequestBuilder { attribute_handle: AttHandle(1).into() }.into(),
        };
        let packet = att::AttReadRequest { attribute_handle: AttHandle(1).into() };

        let out = try_parse_att_server_packet(
            &isolation_manager,
            TCB_IDX,
            packet.to_vec().unwrap().into(),
            &packet.encode_to_vec().unwrap(),
        );

        assert!(out.is_some());
@@ -200,15 +192,16 @@ mod test {
    #[test]
    fn test_packet_bypass_when_isolated() {
        let isolation_manager = create_manager_with_isolated_connection(TCB_IDX, SERVER_ID);
        let packet = AttBuilder {
            opcode: AttOpcode::ERROR_RESPONSE,
            _child_: AttReadRequestBuilder { attribute_handle: AttHandle(1).into() }.into(),
        let packet = att::AttErrorResponse {
            opcode_in_error: att::AttOpcode::ReadResponse,
            handle_in_error: AttHandle(1).into(),
            error_code: att::AttErrorCode::InvalidHandle,
        };

        let out = try_parse_att_server_packet(
            &isolation_manager,
            TCB_IDX,
            packet.to_vec().unwrap().into(),
            &packet.encode_to_vec().unwrap(),
        );

        assert!(out.is_none());
@@ -217,15 +210,12 @@ mod test {
    #[test]
    fn test_mtu_bypass() {
        let isolation_manager = create_manager_with_isolated_connection(TCB_IDX, SERVER_ID);
        let packet = AttBuilder {
            opcode: AttOpcode::EXCHANGE_MTU_REQUEST,
            _child_: AttExchangeMtuRequestBuilder { mtu: 64 }.into(),
        };
        let packet = att::AttExchangeMtuRequest { mtu: 64 };

        let out = try_parse_att_server_packet(
            &isolation_manager,
            TCB_IDX,
            packet.to_vec().unwrap().into(),
            &packet.encode_to_vec().unwrap(),
        );

        assert!(out.is_none());
@@ -234,15 +224,12 @@ mod test {
    #[test]
    fn test_packet_bypass_when_not_isolated() {
        let isolation_manager = IsolationManager::new();
        let packet = AttBuilder {
            opcode: AttOpcode::READ_REQUEST,
            _child_: AttReadRequestBuilder { attribute_handle: AttHandle(1).into() }.into(),
        };
        let packet = att::AttReadRequest { attribute_handle: AttHandle(1).into() };

        let out = try_parse_att_server_packet(
            &isolation_manager,
            TCB_IDX,
            packet.to_vec().unwrap().into(),
            &packet.encode_to_vec().unwrap(),
        );

        assert!(out.is_none());
Loading