1 // Copyright 2023 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! Types for creating arenas used in deserialization of np_adv. This implementation is purpose-made 16 //! for deserializing in `np_adv` and is not intended for general use as an arena. 17 18 use crate::extended::BLE_5_ADV_SVC_MAX_CONTENT_LEN; 19 20 /// Create a [`DeserializationArena`] suitable for use with deserializing an advertisement. 21 #[macro_export] 22 macro_rules! deserialization_arena { 23 // Trick borrowed from `pin!`: In an argument to a braced constructor, if we take a reference to 24 // a temporary value, that value will be upgraded to live for the scope of the enclosing block, 25 // avoiding another `let` binding for the buffer which is normally required to keep the buffer 26 // on the stack. 27 // Reference: https://doc.rust-lang.org/reference/destructors.html#temporary-lifetime-extension 28 () => { 29 $crate::deserialization_arena::DeserializationArena { 30 buffer: &mut $crate::deserialization_arena::DeserializationArena::new_buffer(), 31 } 32 }; 33 } 34 35 /// A simple allocator that simply keeps splitting the given slice on allocation. Use the 36 /// [`deserialization_arena!`][crate::deserialization_arena!] macro to create an instance. 37 pub(crate) struct DeserializationArenaAllocator<'a> { 38 #[doc(hidden)] 39 slice: &'a mut [u8], 40 } 41 42 impl<'a> DeserializationArenaAllocator<'a> { 43 /// Allocates `len` bytes from the slice given upon construction. In the expected use case, the 44 /// allocated slice should be written to with actual data, overwriting what's contained in 45 /// there. While reading from the allocated slice without first writing to it is safe in the 46 /// Rust memory-safety sense, the returned slice contains "garbage" data from the slice given 47 /// during construction. 48 /// 49 /// Returns an error with [`ArenaOutOfSpace`] if the remaining slice is not long enough to 50 /// allocate `len` bytes. allocate(&mut self, len: u8) -> Result<&'a mut [u8], ArenaOutOfSpace>51 pub fn allocate(&mut self, len: u8) -> Result<&'a mut [u8], ArenaOutOfSpace> { 52 if usize::from(len) > self.slice.len() { 53 return Err(ArenaOutOfSpace); 54 } 55 let (allocated, remaining) = core::mem::take(&mut self.slice).split_at_mut(len.into()); 56 self.slice = remaining; 57 // Note: the returned data is logically garbage. While it's deterministic (not UB), 58 // semantically this should be treated as a write only slice. 59 Ok(allocated) 60 } 61 } 62 63 /// A simple allocator that simply keeps splitting the given slice on allocation. Use the 64 /// [`deserialization_arena!`][crate::deserialization_arena!] macro to create an instance. 65 pub struct DeserializationArena<'a> { 66 #[doc(hidden)] // Exposed for use by `deserialization_arena!` only. 67 pub buffer: &'a mut [u8; BLE_5_ADV_SVC_MAX_CONTENT_LEN], 68 } 69 70 impl<'a> DeserializationArena<'a> { 71 #[doc(hidden)] // Exposed for use by `deserialization_arena!` only. new_buffer() -> [u8; BLE_5_ADV_SVC_MAX_CONTENT_LEN]72 pub fn new_buffer() -> [u8; BLE_5_ADV_SVC_MAX_CONTENT_LEN] { 73 [0; BLE_5_ADV_SVC_MAX_CONTENT_LEN] 74 } 75 76 /// Convert this arena into an allocator that can start allocating. into_allocator(self) -> DeserializationArenaAllocator<'a>77 pub(crate) fn into_allocator(self) -> DeserializationArenaAllocator<'a> { 78 DeserializationArenaAllocator { slice: self.buffer } 79 } 80 } 81 82 /// Error indicating that the arena has ran out of space, and deserialization cannot proceed. This 83 /// should never happen if the arena is created with [`crate::deserialization_arena!`], since the 84 /// total size of decrypted sections should be less than the size of the incoming BLE advertisement. 85 #[derive(Debug, PartialEq, Eq)] 86 pub(crate) struct ArenaOutOfSpace; 87 88 #[cfg(test)] 89 mod test { 90 use crate::{deserialization_arena::ArenaOutOfSpace, extended::BLE_5_ADV_SVC_MAX_CONTENT_LEN}; 91 92 #[test] test_creation()93 fn test_creation() { 94 assert_eq!(BLE_5_ADV_SVC_MAX_CONTENT_LEN, deserialization_arena!().buffer.len()); 95 } 96 97 #[test] test_allocation()98 fn test_allocation() { 99 let arena = deserialization_arena!(); 100 let mut allocator = arena.into_allocator(); 101 assert_eq!(Ok(&mut [0_u8; 100][..]), allocator.allocate(100)); 102 assert_eq!(BLE_5_ADV_SVC_MAX_CONTENT_LEN - 100, allocator.slice.len()); 103 } 104 105 #[test] test_allocation_overflow()106 fn test_allocation_overflow() { 107 let arena = deserialization_arena!(); 108 let mut allocator = arena.into_allocator(); 109 assert_eq!(Err(ArenaOutOfSpace), allocator.allocate(u8::MAX)); 110 } 111 112 #[test] test_allocation_twice_overflow()113 fn test_allocation_twice_overflow() { 114 let arena = deserialization_arena!(); 115 let mut allocator = arena.into_allocator(); 116 assert_eq!(Ok(&mut [0_u8; 128][..]), allocator.allocate(128)); 117 assert_eq!(Err(ArenaOutOfSpace), allocator.allocate(128)); 118 } 119 } 120