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