1 // Copyright 2022 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 //! The "Actions" data element and associated types. 16 //! 17 //! This DE is somewhat more complex than other DEs. Whether or not it supports a particular flavor 18 //! depends on the actions set, so it has to be treated as two separate types based on which 19 //! flavor type parameter is used. 20 use crate::legacy::data_elements::{DirectMapPredicate, DirectMapper, LengthMapper}; 21 use crate::{ 22 legacy::{ 23 data_elements::{ 24 de_type::{DeActualLength, DeEncodedLength, DeTypeCode}, 25 DataElementDeserializeError, DataElementSerializationBuffer, DataElementSerializeError, 26 DeserializeDataElement, SerializeDataElement, 27 }, 28 PacketFlavor, PacketFlavorEnum, 29 }, 30 private::Sealed, 31 }; 32 33 #[cfg(feature = "devtools")] 34 use core::ops::Range; 35 use core::{marker, ops}; 36 use nom::{bytes, combinator, error}; 37 use sink::Sink; 38 use strum::IntoEnumIterator as _; 39 40 mod macros; 41 #[cfg(test)] 42 pub(crate) mod tests; 43 44 /// Actions DE. 45 /// Only as many DE payload bytes will be present as needed to represent all set bits that are encoded, 46 /// with a lower bound of 1 byte in the special case of no set action bits, and an upper bound 47 /// of 3 bytes occupied by the DE payload. 48 #[derive(Debug, PartialEq, Eq, Clone)] 49 pub struct ActionsDataElement<F: PacketFlavor> { 50 /// The action bits 51 pub action: ActionBits<F>, 52 } 53 54 /// Max length of an actions DE contents 55 pub(crate) const ACTIONS_MAX_LEN: usize = 3; 56 /// Range of valid actual lengths 57 pub(crate) const ACTIONS_VALID_ACTUAL_LEN: ops::RangeInclusive<usize> = 1..=ACTIONS_MAX_LEN; 58 59 impl<F> ActionsDataElement<F> 60 where 61 F: PacketFlavor, 62 { 63 /// Generic deserialize, not meant to be called directly -- use [DeserializeDataElement] impls instead. 64 #[allow(clippy::assertions_on_constants)] deserialize(de_contents: &[u8]) -> Result<Self, DataElementDeserializeError>65 fn deserialize(de_contents: &[u8]) -> Result<Self, DataElementDeserializeError> { 66 combinator::all_consuming::<&[u8], _, error::Error<&[u8]>, _>(combinator::map( 67 bytes::complete::take_while_m_n(0, ACTIONS_MAX_LEN, |_| true), 68 |bytes: &[u8]| { 69 // pack bits into u32 for convenient access 70 debug_assert!(4 >= ACTIONS_MAX_LEN, "Actions must fit in u32"); 71 let mut action_bytes = [0_u8; 4]; 72 action_bytes[..bytes.len()].copy_from_slice(bytes); 73 u32::from_be_bytes(action_bytes) 74 }, 75 ))(de_contents) 76 .map_err(|_| DataElementDeserializeError::DeserializeError { de_type: Self::DE_TYPE_CODE }) 77 .map(|(_remaining, actions)| actions) 78 .and_then(|action_bits_num| { 79 let action = ActionBits::try_from(action_bits_num).map_err(|e| { 80 DataElementDeserializeError::FlavorNotSupported { 81 de_type: Self::DE_TYPE_CODE, 82 flavor: e.flavor, 83 } 84 })?; 85 Ok(Self { action }) 86 }) 87 } 88 } 89 90 impl<F: PacketFlavor> From<ActionBits<F>> for ActionsDataElement<F> { from(action: ActionBits<F>) -> Self91 fn from(action: ActionBits<F>) -> Self { 92 Self { action } 93 } 94 } 95 96 impl<F: PacketFlavor> Sealed for ActionsDataElement<F> {} 97 98 impl<F: PacketFlavor> SerializeDataElement<F> for ActionsDataElement<F> { de_type_code(&self) -> DeTypeCode99 fn de_type_code(&self) -> DeTypeCode { 100 ActionsDataElement::<F>::DE_TYPE_CODE 101 } 102 map_actual_len_to_encoded_len(&self, actual_len: DeActualLength) -> DeEncodedLength103 fn map_actual_len_to_encoded_len(&self, actual_len: DeActualLength) -> DeEncodedLength { 104 <Self as DeserializeDataElement>::LengthMapper::map_actual_len_to_encoded_len(actual_len) 105 } 106 serialize_contents( &self, sink: &mut DataElementSerializationBuffer, ) -> Result<(), DataElementSerializeError>107 fn serialize_contents( 108 &self, 109 sink: &mut DataElementSerializationBuffer, 110 ) -> Result<(), DataElementSerializeError> { 111 let used = self.action.bytes_used(); 112 sink.try_extend_from_slice(&self.action.bits.to_be_bytes()[..used]) 113 .ok_or(DataElementSerializeError::InsufficientSpace) 114 } 115 } 116 117 impl<E: PacketFlavor> DeserializeDataElement for ActionsDataElement<E> { 118 const DE_TYPE_CODE: DeTypeCode = match DeTypeCode::try_from(0b0110) { 119 Ok(t) => t, 120 Err(_) => unreachable!(), 121 }; 122 123 type LengthMapper = DirectMapper<ActionsLengthPredicate>; 124 deserialize<F: PacketFlavor>( de_contents: &[u8], ) -> Result<Self, DataElementDeserializeError>125 fn deserialize<F: PacketFlavor>( 126 de_contents: &[u8], 127 ) -> Result<Self, DataElementDeserializeError> { 128 if E::ENUM_VARIANT == F::ENUM_VARIANT { 129 ActionsDataElement::deserialize(de_contents) 130 } else { 131 Err(DataElementDeserializeError::FlavorNotSupported { 132 de_type: Self::DE_TYPE_CODE, 133 flavor: F::ENUM_VARIANT, 134 }) 135 } 136 } 137 } 138 139 pub(in crate::legacy) struct ActionsLengthPredicate; 140 141 impl DirectMapPredicate for ActionsLengthPredicate { is_valid(len: usize) -> bool142 fn is_valid(len: usize) -> bool { 143 ACTIONS_VALID_ACTUAL_LEN.contains(&len) 144 } 145 } 146 147 /// Container for the 24 bits defined for "actions" (feature flags and the like). 148 /// This internally stores a u32, but only the 24 highest bits of this 149 /// field will actually ever be populated. 150 #[derive(Debug, PartialEq, Eq, Clone, Copy)] 151 pub struct ActionBits<F: PacketFlavor> { 152 bits: u32, 153 // marker for element type 154 flavor: marker::PhantomData<F>, 155 } 156 157 impl<F: PacketFlavor> ActionBits<F> { 158 /// Returns the actions bits as a u32. The upper limit of an actions field is 3 bytes, 159 /// so the last bytes of this u32 will always be 0 as_u32(self) -> u32160 pub fn as_u32(self) -> u32 { 161 self.bits 162 } 163 164 /// Return whether a boolean action type is set in this data element, or `None` if the given 165 /// action type does not represent a boolean. has_action(&self, action_type: ActionType) -> bool166 pub fn has_action(&self, action_type: ActionType) -> bool { 167 self.bits_for_type(action_type) != 0 168 } 169 } 170 171 impl<F: PacketFlavor> Default for ActionBits<F> { default() -> Self172 fn default() -> Self { 173 ActionBits { 174 bits: 0, // no bits set 175 flavor: marker::PhantomData, 176 } 177 } 178 } 179 180 /// At least one action doesn't support the required flavor 181 #[derive(PartialEq, Eq, Debug)] 182 pub struct FlavorNotSupported { 183 flavor: PacketFlavorEnum, 184 } 185 186 lazy_static::lazy_static! { 187 /// All bits for plaintext action types: 1 where a plaintext action could have a bit, 0 elsewhere. 188 static ref ALL_PLAINTEXT_ELEMENT_BITS: u32 = ActionType::iter() 189 .filter(|t| t.supports_flavor(PacketFlavorEnum::Plaintext)) 190 .map(|t| t.all_bits()) 191 .fold(0_u32, |accum, bits| accum | bits); 192 } 193 194 lazy_static::lazy_static! { 195 /// All bits for ciphertext action types: 1 where a ciphertext action could have a bit, 0 elsewhere. 196 static ref ALL_CIPHERTEXT_ELEMENT_BITS: u32 = ActionType::iter() 197 .filter(|t| t.supports_flavor(PacketFlavorEnum::Ciphertext)) 198 .map(|t| t.all_bits()) 199 .fold(0_u32, |accum, bits| accum | bits); 200 } 201 202 impl<F: PacketFlavor> ActionBits<F> { 203 /// Tries to create ActionBits from a u32, returning error in the event a specific bit is set for 204 /// an unsupported flavor try_from(value: u32) -> Result<Self, FlavorNotSupported>205 pub fn try_from(value: u32) -> Result<Self, FlavorNotSupported> { 206 let ok_bits: u32 = match F::ENUM_VARIANT { 207 PacketFlavorEnum::Plaintext => *ALL_PLAINTEXT_ELEMENT_BITS, 208 PacketFlavorEnum::Ciphertext => *ALL_CIPHERTEXT_ELEMENT_BITS, 209 }; 210 211 // no bits set beyond what's allowed for this flavor 212 if value | ok_bits == ok_bits { 213 Ok(Self { bits: value, flavor: marker::PhantomData }) 214 } else { 215 Err(FlavorNotSupported { flavor: F::ENUM_VARIANT }) 216 } 217 } 218 219 /// Set the bits for the provided element. 220 /// Bits outside the range set by the action will be unaffected. set_action<E: ActionElementFlavor<F>>(&mut self, action_element: E)221 pub fn set_action<E: ActionElementFlavor<F>>(&mut self, action_element: E) { 222 let bits = action_element.bits(); 223 224 // validate that the element is not horribly broken 225 debug_assert!(E::HIGH_BIT_INDEX < 32); 226 // must not have bits set past the low `len` bits 227 debug_assert_eq!(0, bits >> 1); 228 229 // 0-extend to u32 230 let byte_extended = bits as u32; 231 // Shift so that the high bit is at the desired index. 232 // Won't overflow since length > 0. 233 let bits_in_position = byte_extended << (31 - E::HIGH_BIT_INDEX); 234 235 // We want to effectively clear out the bits already in place, so we don't want to just |=. 236 // Instead, we construct a u32 with all 1s above and below the relevant bits and &=, so that 237 // if the new bits are 0, the stored bits will be cleared. 238 239 // avoid overflow when index = 0 -- need zero 1 bits to the left in that case 240 let left_1s = u32::MAX.checked_shl(32 - E::HIGH_BIT_INDEX).unwrap_or(0); 241 // avoid underflow when index + len = 32 -- zero 1 bits to the right 242 let right_1s = u32::MAX.checked_shr(E::HIGH_BIT_INDEX + 1).unwrap_or(0); 243 let mask = left_1s | right_1s; 244 let bits_for_other_actions = self.bits & mask; 245 self.bits = bits_for_other_actions | bits_in_position; 246 } 247 248 /// How many bytes (1-3) are needed to represent the set bits, starting from the most 249 /// significant bit. The lower bound of 1 is because the unique special case of 250 /// an actions field of all zeroes is required by the spec to occupy exactly one byte. bytes_used(&self) -> usize251 fn bytes_used(&self) -> usize { 252 let bits_used = 32 - self.bits.trailing_zeros(); 253 let raw_count = (bits_used as usize + 7) / 8; 254 if raw_count == 0 { 255 1 // Uncommon case - should only be hit for all-zero action bits 256 } else { 257 raw_count 258 } 259 } 260 261 /// Return the bits for a given action type as the low bits in the returned u32. 262 /// 263 /// For example, when extracting the bits `B` from `0bXXXXXXXXXXBBBBBBXXXXXXXXXXXXXXXX`, the 264 /// return value will be `0b00000000000000000000000000BBBBBB`. bits_for_type(&self, action_type: ActionType) -> u32265 pub fn bits_for_type(&self, action_type: ActionType) -> u32 { 266 self.bits << action_type.high_bit_index() >> (31) 267 } 268 } 269 270 /// Core trait for an individual action 271 pub trait ActionElement { 272 /// The assigned offset for this type from the high bit in the eventual bit sequence of all 273 /// actions. 274 /// 275 /// Each implementation must have a non-conflicting index defined by 276 /// [Self::HIGH_BIT_INDEX] 277 const HIGH_BIT_INDEX: u32; 278 279 /// Forces implementations to have a matching enum variant so the enum can be kept up to date. 280 const ACTION_TYPE: ActionType; 281 282 /// Returns whether this action supports the provided `flavor`. 283 /// 284 /// Must match the implementations of [ActionElementFlavor]. supports_flavor(flavor: PacketFlavorEnum) -> bool285 fn supports_flavor(flavor: PacketFlavorEnum) -> bool; 286 287 /// Returns the low bit that should be included in the final bit vector 288 /// starting at [Self::HIGH_BIT_INDEX]. bits(&self) -> u8289 fn bits(&self) -> u8; 290 } 291 292 /// Marker trait indicating support for a particular [PacketFlavor]. 293 pub trait ActionElementFlavor<F: PacketFlavor>: ActionElement {} 294 295 /// Provides a way to iterate over all action types. 296 #[derive(Clone, Copy, strum_macros::EnumIter, PartialEq, Eq, Hash, Debug)] 297 #[allow(missing_docs)] 298 pub enum ActionType { 299 CrossDevSdk, 300 CallTransfer, 301 ActiveUnlock, 302 NearbyShare, 303 InstantTethering, 304 PhoneHub, 305 } 306 307 impl ActionType { 308 /// A u32 with all possible bits for this action type set all_bits(&self) -> u32309 const fn all_bits(&self) -> u32 { 310 (u32::MAX << (31_u32)) >> self.high_bit_index() 311 } 312 313 /// Get the range of the bits occupied used by this bit index. For example, if the action type 314 /// uses the 5th and 6th bits, the returned range will be (5..7). 315 /// (0 is the index of the most significant bit). 316 #[cfg(feature = "devtools")] bits_range_for_devtools(&self) -> Range<u32>317 pub const fn bits_range_for_devtools(&self) -> Range<u32> { 318 let high_bit_index = self.high_bit_index(); 319 high_bit_index..high_bit_index + 1 320 } 321 high_bit_index(&self) -> u32322 const fn high_bit_index(&self) -> u32 { 323 match self { 324 ActionType::CrossDevSdk => CrossDevSdk::HIGH_BIT_INDEX, 325 ActionType::CallTransfer => CallTransfer::HIGH_BIT_INDEX, 326 ActionType::ActiveUnlock => ActiveUnlock::HIGH_BIT_INDEX, 327 ActionType::NearbyShare => NearbyShare::HIGH_BIT_INDEX, 328 ActionType::InstantTethering => InstantTethering::HIGH_BIT_INDEX, 329 ActionType::PhoneHub => PhoneHub::HIGH_BIT_INDEX, 330 } 331 } 332 supports_flavor(&self, flavor: PacketFlavorEnum) -> bool333 pub(crate) fn supports_flavor(&self, flavor: PacketFlavorEnum) -> bool { 334 match self { 335 ActionType::CrossDevSdk => CrossDevSdk::supports_flavor(flavor), 336 ActionType::CallTransfer => CallTransfer::supports_flavor(flavor), 337 ActionType::ActiveUnlock => ActiveUnlock::supports_flavor(flavor), 338 ActionType::NearbyShare => NearbyShare::supports_flavor(flavor), 339 ActionType::InstantTethering => InstantTethering::supports_flavor(flavor), 340 ActionType::PhoneHub => PhoneHub::supports_flavor(flavor), 341 } 342 } 343 } 344 345 // enabling an element for public adv requires privacy approval due to fingerprinting risk 346 macros::boolean_element!(CrossDevSdk, 1, plaintext_and_ciphertext); 347 macros::boolean_element!(CallTransfer, 4, ciphertext_only); 348 macros::boolean_element!(ActiveUnlock, 8, ciphertext_only); 349 macros::boolean_element!(NearbyShare, 9, plaintext_and_ciphertext); 350 macros::boolean_element!(InstantTethering, 10, ciphertext_only); 351 macros::boolean_element!(PhoneHub, 11, ciphertext_only); 352