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 //! BLE advertisements. 16 17 use crate::wrapper::assigned_numbers::{COMPANY_IDS, SERVICE_IDS}; 18 use crate::wrapper::core::{Uuid128, Uuid16, Uuid32}; 19 use itertools::Itertools; 20 use nom::{combinator, multi, number}; 21 use std::fmt; 22 use strum::IntoEnumIterator; 23 24 /// The numeric code for a common data type. 25 /// 26 /// For known types, see [CommonDataType], or use this type directly for non-assigned codes. 27 #[derive(PartialEq, Eq, Debug, Clone, Copy, Hash)] 28 pub struct CommonDataTypeCode(u8); 29 30 impl From<CommonDataType> for CommonDataTypeCode { from(value: CommonDataType) -> Self31 fn from(value: CommonDataType) -> Self { 32 let byte = match value { 33 CommonDataType::Flags => 0x01, 34 CommonDataType::IncompleteListOf16BitServiceClassUuids => 0x02, 35 CommonDataType::CompleteListOf16BitServiceClassUuids => 0x03, 36 CommonDataType::IncompleteListOf32BitServiceClassUuids => 0x04, 37 CommonDataType::CompleteListOf32BitServiceClassUuids => 0x05, 38 CommonDataType::IncompleteListOf128BitServiceClassUuids => 0x06, 39 CommonDataType::CompleteListOf128BitServiceClassUuids => 0x07, 40 CommonDataType::ShortenedLocalName => 0x08, 41 CommonDataType::CompleteLocalName => 0x09, 42 CommonDataType::TxPowerLevel => 0x0A, 43 CommonDataType::ClassOfDevice => 0x0D, 44 CommonDataType::SimplePairingHashC192 => 0x0E, 45 CommonDataType::SimplePairingRandomizerR192 => 0x0F, 46 // These two both really have type code 0x10! D: 47 CommonDataType::DeviceId => 0x10, 48 CommonDataType::SecurityManagerTkValue => 0x10, 49 CommonDataType::SecurityManagerOutOfBandFlags => 0x11, 50 CommonDataType::PeripheralConnectionIntervalRange => 0x12, 51 CommonDataType::ListOf16BitServiceSolicitationUuids => 0x14, 52 CommonDataType::ListOf128BitServiceSolicitationUuids => 0x15, 53 CommonDataType::ServiceData16BitUuid => 0x16, 54 CommonDataType::PublicTargetAddress => 0x17, 55 CommonDataType::RandomTargetAddress => 0x18, 56 CommonDataType::Appearance => 0x19, 57 CommonDataType::AdvertisingInterval => 0x1A, 58 CommonDataType::LeBluetoothDeviceAddress => 0x1B, 59 CommonDataType::LeRole => 0x1C, 60 CommonDataType::SimplePairingHashC256 => 0x1D, 61 CommonDataType::SimplePairingRandomizerR256 => 0x1E, 62 CommonDataType::ListOf32BitServiceSolicitationUuids => 0x1F, 63 CommonDataType::ServiceData32BitUuid => 0x20, 64 CommonDataType::ServiceData128BitUuid => 0x21, 65 CommonDataType::LeSecureConnectionsConfirmationValue => 0x22, 66 CommonDataType::LeSecureConnectionsRandomValue => 0x23, 67 CommonDataType::Uri => 0x24, 68 CommonDataType::IndoorPositioning => 0x25, 69 CommonDataType::TransportDiscoveryData => 0x26, 70 CommonDataType::LeSupportedFeatures => 0x27, 71 CommonDataType::ChannelMapUpdateIndication => 0x28, 72 CommonDataType::PbAdv => 0x29, 73 CommonDataType::MeshMessage => 0x2A, 74 CommonDataType::MeshBeacon => 0x2B, 75 CommonDataType::BigInfo => 0x2C, 76 CommonDataType::BroadcastCode => 0x2D, 77 CommonDataType::ResolvableSetIdentifier => 0x2E, 78 CommonDataType::AdvertisingIntervalLong => 0x2F, 79 CommonDataType::ThreeDInformationData => 0x3D, 80 CommonDataType::ManufacturerSpecificData => 0xFF, 81 }; 82 83 Self(byte) 84 } 85 } 86 87 impl From<u8> for CommonDataTypeCode { from(value: u8) -> Self88 fn from(value: u8) -> Self { 89 Self(value) 90 } 91 } 92 93 impl From<CommonDataTypeCode> for u8 { from(value: CommonDataTypeCode) -> Self94 fn from(value: CommonDataTypeCode) -> Self { 95 value.0 96 } 97 } 98 99 /// Data types for assigned type codes. 100 /// 101 /// See Bluetooth Assigned Numbers § 2.3 102 #[derive(Debug, Clone, Copy, PartialEq, Eq, strum_macros::EnumIter)] 103 #[allow(missing_docs)] 104 pub enum CommonDataType { 105 Flags, 106 IncompleteListOf16BitServiceClassUuids, 107 CompleteListOf16BitServiceClassUuids, 108 IncompleteListOf32BitServiceClassUuids, 109 CompleteListOf32BitServiceClassUuids, 110 IncompleteListOf128BitServiceClassUuids, 111 CompleteListOf128BitServiceClassUuids, 112 ShortenedLocalName, 113 CompleteLocalName, 114 TxPowerLevel, 115 ClassOfDevice, 116 SimplePairingHashC192, 117 SimplePairingRandomizerR192, 118 DeviceId, 119 SecurityManagerTkValue, 120 SecurityManagerOutOfBandFlags, 121 PeripheralConnectionIntervalRange, 122 ListOf16BitServiceSolicitationUuids, 123 ListOf128BitServiceSolicitationUuids, 124 ServiceData16BitUuid, 125 PublicTargetAddress, 126 RandomTargetAddress, 127 Appearance, 128 AdvertisingInterval, 129 LeBluetoothDeviceAddress, 130 LeRole, 131 SimplePairingHashC256, 132 SimplePairingRandomizerR256, 133 ListOf32BitServiceSolicitationUuids, 134 ServiceData32BitUuid, 135 ServiceData128BitUuid, 136 LeSecureConnectionsConfirmationValue, 137 LeSecureConnectionsRandomValue, 138 Uri, 139 IndoorPositioning, 140 TransportDiscoveryData, 141 LeSupportedFeatures, 142 ChannelMapUpdateIndication, 143 PbAdv, 144 MeshMessage, 145 MeshBeacon, 146 BigInfo, 147 BroadcastCode, 148 ResolvableSetIdentifier, 149 AdvertisingIntervalLong, 150 ThreeDInformationData, 151 ManufacturerSpecificData, 152 } 153 154 impl CommonDataType { 155 /// Iterate over the zero, one, or more matching types for the provided code. 156 /// 157 /// `0x10` maps to both Device Id and Security Manager TK Value, so multiple matching types 158 /// may exist for a single code. for_type_code(code: CommonDataTypeCode) -> impl Iterator<Item = CommonDataType>159 pub fn for_type_code(code: CommonDataTypeCode) -> impl Iterator<Item = CommonDataType> { 160 Self::iter().filter(move |t| CommonDataTypeCode::from(*t) == code) 161 } 162 163 /// Apply type-specific human-oriented formatting to data, if any is applicable format_data(&self, data: &[u8]) -> Option<String>164 pub fn format_data(&self, data: &[u8]) -> Option<String> { 165 match self { 166 Self::Flags => Some(Flags::matching(data).map(|f| format!("{:?}", f)).join(",")), 167 Self::CompleteListOf16BitServiceClassUuids 168 | Self::IncompleteListOf16BitServiceClassUuids 169 | Self::ListOf16BitServiceSolicitationUuids => { 170 combinator::complete(multi::many0(Uuid16::parse_le))(data) 171 .map(|(_res, uuids)| { 172 uuids 173 .into_iter() 174 .map(|uuid| { 175 SERVICE_IDS 176 .get(&uuid) 177 .map(|name| format!("{:?} ({name})", uuid)) 178 .unwrap_or_else(|| format!("{:?}", uuid)) 179 }) 180 .join(", ") 181 }) 182 .ok() 183 } 184 Self::CompleteListOf32BitServiceClassUuids 185 | Self::IncompleteListOf32BitServiceClassUuids 186 | Self::ListOf32BitServiceSolicitationUuids => { 187 combinator::complete(multi::many0(Uuid32::parse))(data) 188 .map(|(_res, uuids)| uuids.into_iter().map(|u| format!("{:?}", u)).join(", ")) 189 .ok() 190 } 191 Self::CompleteListOf128BitServiceClassUuids 192 | Self::IncompleteListOf128BitServiceClassUuids 193 | Self::ListOf128BitServiceSolicitationUuids => { 194 combinator::complete(multi::many0(Uuid128::parse_le))(data) 195 .map(|(_res, uuids)| uuids.into_iter().map(|u| format!("{:?}", u)).join(", ")) 196 .ok() 197 } 198 Self::ServiceData16BitUuid => Uuid16::parse_le(data) 199 .map(|(rem, uuid)| { 200 format!( 201 "service={:?}, data={}", 202 SERVICE_IDS 203 .get(&uuid) 204 .map(|name| format!("{:?} ({name})", uuid)) 205 .unwrap_or_else(|| format!("{:?}", uuid)), 206 hex::encode_upper(rem) 207 ) 208 }) 209 .ok(), 210 Self::ServiceData32BitUuid => Uuid32::parse(data) 211 .map(|(rem, uuid)| format!("service={:?}, data={}", uuid, hex::encode_upper(rem))) 212 .ok(), 213 Self::ServiceData128BitUuid => Uuid128::parse_le(data) 214 .map(|(rem, uuid)| format!("service={:?}, data={}", uuid, hex::encode_upper(rem))) 215 .ok(), 216 Self::ShortenedLocalName | Self::CompleteLocalName => { 217 std::str::from_utf8(data).ok().map(|s| format!("\"{}\"", s)) 218 } 219 Self::TxPowerLevel => { 220 let (_, tx) = 221 combinator::complete(number::complete::i8::<_, nom::error::Error<_>>)(data) 222 .ok()?; 223 224 Some(tx.to_string()) 225 } 226 Self::ManufacturerSpecificData => { 227 let (rem, id) = Uuid16::parse_le(data).ok()?; 228 Some(format!( 229 "company={}, data=0x{}", 230 COMPANY_IDS 231 .get(&id) 232 .map(|s| s.to_string()) 233 .unwrap_or_else(|| format!("{:?}", id)), 234 hex::encode_upper(rem) 235 )) 236 } 237 _ => None, 238 } 239 } 240 } 241 242 impl fmt::Display for CommonDataType { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 244 match self { 245 CommonDataType::Flags => write!(f, "Flags"), 246 CommonDataType::IncompleteListOf16BitServiceClassUuids => { 247 write!(f, "Incomplete List of 16-bit Service Class UUIDs") 248 } 249 CommonDataType::CompleteListOf16BitServiceClassUuids => { 250 write!(f, "Complete List of 16-bit Service Class UUIDs") 251 } 252 CommonDataType::IncompleteListOf32BitServiceClassUuids => { 253 write!(f, "Incomplete List of 32-bit Service Class UUIDs") 254 } 255 CommonDataType::CompleteListOf32BitServiceClassUuids => { 256 write!(f, "Complete List of 32-bit Service Class UUIDs") 257 } 258 CommonDataType::ListOf16BitServiceSolicitationUuids => { 259 write!(f, "List of 16-bit Service Solicitation UUIDs") 260 } 261 CommonDataType::ListOf32BitServiceSolicitationUuids => { 262 write!(f, "List of 32-bit Service Solicitation UUIDs") 263 } 264 CommonDataType::ListOf128BitServiceSolicitationUuids => { 265 write!(f, "List of 128-bit Service Solicitation UUIDs") 266 } 267 CommonDataType::IncompleteListOf128BitServiceClassUuids => { 268 write!(f, "Incomplete List of 128-bit Service Class UUIDs") 269 } 270 CommonDataType::CompleteListOf128BitServiceClassUuids => { 271 write!(f, "Complete List of 128-bit Service Class UUIDs") 272 } 273 CommonDataType::ShortenedLocalName => write!(f, "Shortened Local Name"), 274 CommonDataType::CompleteLocalName => write!(f, "Complete Local Name"), 275 CommonDataType::TxPowerLevel => write!(f, "TX Power Level"), 276 CommonDataType::ClassOfDevice => write!(f, "Class of Device"), 277 CommonDataType::SimplePairingHashC192 => { 278 write!(f, "Simple Pairing Hash C-192") 279 } 280 CommonDataType::SimplePairingHashC256 => { 281 write!(f, "Simple Pairing Hash C 256") 282 } 283 CommonDataType::SimplePairingRandomizerR192 => { 284 write!(f, "Simple Pairing Randomizer R-192") 285 } 286 CommonDataType::SimplePairingRandomizerR256 => { 287 write!(f, "Simple Pairing Randomizer R 256") 288 } 289 CommonDataType::DeviceId => write!(f, "Device Id"), 290 CommonDataType::SecurityManagerTkValue => { 291 write!(f, "Security Manager TK Value") 292 } 293 CommonDataType::SecurityManagerOutOfBandFlags => { 294 write!(f, "Security Manager Out of Band Flags") 295 } 296 CommonDataType::PeripheralConnectionIntervalRange => { 297 write!(f, "Peripheral Connection Interval Range") 298 } 299 CommonDataType::ServiceData16BitUuid => { 300 write!(f, "Service Data 16-bit UUID") 301 } 302 CommonDataType::ServiceData32BitUuid => { 303 write!(f, "Service Data 32-bit UUID") 304 } 305 CommonDataType::ServiceData128BitUuid => { 306 write!(f, "Service Data 128-bit UUID") 307 } 308 CommonDataType::PublicTargetAddress => write!(f, "Public Target Address"), 309 CommonDataType::RandomTargetAddress => write!(f, "Random Target Address"), 310 CommonDataType::Appearance => write!(f, "Appearance"), 311 CommonDataType::AdvertisingInterval => write!(f, "Advertising Interval"), 312 CommonDataType::LeBluetoothDeviceAddress => { 313 write!(f, "LE Bluetooth Device Address") 314 } 315 CommonDataType::LeRole => write!(f, "LE Role"), 316 CommonDataType::LeSecureConnectionsConfirmationValue => { 317 write!(f, "LE Secure Connections Confirmation Value") 318 } 319 CommonDataType::LeSecureConnectionsRandomValue => { 320 write!(f, "LE Secure Connections Random Value") 321 } 322 CommonDataType::LeSupportedFeatures => write!(f, "LE Supported Features"), 323 CommonDataType::Uri => write!(f, "URI"), 324 CommonDataType::IndoorPositioning => write!(f, "Indoor Positioning"), 325 CommonDataType::TransportDiscoveryData => { 326 write!(f, "Transport Discovery Data") 327 } 328 CommonDataType::ChannelMapUpdateIndication => { 329 write!(f, "Channel Map Update Indication") 330 } 331 CommonDataType::PbAdv => write!(f, "PB-ADV"), 332 CommonDataType::MeshMessage => write!(f, "Mesh Message"), 333 CommonDataType::MeshBeacon => write!(f, "Mesh Beacon"), 334 CommonDataType::BigInfo => write!(f, "BIGIInfo"), 335 CommonDataType::BroadcastCode => write!(f, "Broadcast Code"), 336 CommonDataType::ResolvableSetIdentifier => { 337 write!(f, "Resolvable Set Identifier") 338 } 339 CommonDataType::AdvertisingIntervalLong => { 340 write!(f, "Advertising Interval Long") 341 } 342 CommonDataType::ThreeDInformationData => write!(f, "3D Information Data"), 343 CommonDataType::ManufacturerSpecificData => { 344 write!(f, "Manufacturer Specific Data") 345 } 346 } 347 } 348 } 349 350 /// Accumulates advertisement data to broadcast on a [crate::wrapper::device::Device]. 351 #[derive(Debug, Clone, Default)] 352 pub struct AdvertisementDataBuilder { 353 encoded_data: Vec<u8>, 354 } 355 356 impl AdvertisementDataBuilder { 357 /// Returns a new, empty instance. new() -> Self358 pub fn new() -> Self { 359 Self { 360 encoded_data: Vec::new(), 361 } 362 } 363 364 /// Append advertising data to the builder. 365 /// 366 /// Returns an error if the data cannot be appended. append( &mut self, type_code: impl Into<CommonDataTypeCode>, data: &[u8], ) -> Result<(), AdvertisementDataBuilderError>367 pub fn append( 368 &mut self, 369 type_code: impl Into<CommonDataTypeCode>, 370 data: &[u8], 371 ) -> Result<(), AdvertisementDataBuilderError> { 372 self.encoded_data.push( 373 data.len() 374 .try_into() 375 .ok() 376 .and_then(|len: u8| len.checked_add(1)) 377 .ok_or(AdvertisementDataBuilderError::DataTooLong)?, 378 ); 379 self.encoded_data.push(type_code.into().0); 380 self.encoded_data.extend_from_slice(data); 381 382 Ok(()) 383 } 384 into_bytes(self) -> Vec<u8>385 pub(crate) fn into_bytes(self) -> Vec<u8> { 386 self.encoded_data 387 } 388 } 389 390 /// Errors that can occur when building advertisement data with [AdvertisementDataBuilder]. 391 #[derive(Debug, PartialEq, Eq, thiserror::Error)] 392 pub enum AdvertisementDataBuilderError { 393 /// The provided adv data is too long to be encoded 394 #[error("Data too long")] 395 DataTooLong, 396 } 397 398 #[derive(PartialEq, Eq, strum_macros::EnumIter)] 399 #[allow(missing_docs)] 400 /// Features in the Flags AD 401 pub enum Flags { 402 LeLimited, 403 LeDiscoverable, 404 NoBrEdr, 405 BrEdrController, 406 BrEdrHost, 407 } 408 409 impl fmt::Debug for Flags { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result410 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 411 write!(f, "{}", self.short_name()) 412 } 413 } 414 415 impl Flags { 416 /// Iterates over the flags that are present in the provided `flags` bytes. matching(flags: &[u8]) -> impl Iterator<Item = Self> + '_417 pub fn matching(flags: &[u8]) -> impl Iterator<Item = Self> + '_ { 418 // The encoding is not clear from the spec: do we look at the first byte? or the last? 419 // In practice it's only one byte. 420 let first_byte = flags.first().unwrap_or(&0_u8); 421 422 Self::iter().filter(move |f| { 423 let mask = match f { 424 Flags::LeLimited => 0x01_u8, 425 Flags::LeDiscoverable => 0x02, 426 Flags::NoBrEdr => 0x04, 427 Flags::BrEdrController => 0x08, 428 Flags::BrEdrHost => 0x10, 429 }; 430 431 mask & first_byte > 0 432 }) 433 } 434 435 /// An abbreviated form of the flag name. 436 /// 437 /// See [Flags::name] for the full name. short_name(&self) -> &'static str438 pub fn short_name(&self) -> &'static str { 439 match self { 440 Flags::LeLimited => "LE Limited", 441 Flags::LeDiscoverable => "LE General", 442 Flags::NoBrEdr => "No BR/EDR", 443 Flags::BrEdrController => "BR/EDR C", 444 Flags::BrEdrHost => "BR/EDR H", 445 } 446 } 447 448 /// The human-readable name of the flag. 449 /// 450 /// See [Flags::short_name] for a shorter string for use if compactness is important. name(&self) -> &'static str451 pub fn name(&self) -> &'static str { 452 match self { 453 Flags::LeLimited => "LE Limited Discoverable Mode", 454 Flags::LeDiscoverable => "LE General Discoverable Mode", 455 Flags::NoBrEdr => "BR/EDR Not Supported", 456 Flags::BrEdrController => "Simultaneous LE and BR/EDR (Controller)", 457 Flags::BrEdrHost => "Simultaneous LE and BR/EDR (Host)", 458 } 459 } 460 } 461