Skip to main content

btle/hci/
mod.rs

1//! HCI Layer (where most the magic happens). Implements a Bluetooth Adapter for any controller
2//! supporting HCI streams.
3//! (HCI Layer is Little Endian).
4pub mod adapter;
5pub mod adapters;
6pub mod baseband;
7#[cfg(all(unix, feature = "bluez_socket"))]
8pub mod bluez_socket;
9pub mod command;
10pub mod event;
11pub mod le;
12pub mod link_control;
13pub mod packet;
14#[cfg(feature = "remote")]
15pub mod remote;
16pub mod stream;
17#[cfg(feature = "hci_usb")]
18pub mod usb;
19
20#[derive(Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Hash, Debug)]
21pub enum StreamError {
22    EventError(PackError),
23    CommandError(PackError),
24    UnsupportedPacketType(u8),
25    BadOpcode,
26    BadEventCode,
27    BadPacketCode,
28    StreamClosed,
29    StreamFailed,
30}
31use crate::bytes::ToFromBytesEndian;
32use crate::ConversionError;
33use crate::PackError;
34use core::convert::{TryFrom, TryInto};
35use core::fmt::Formatter;
36
37pub const MAX_ACL_SIZE: usize = 1492 + 4;
38pub const MAX_SCO_SIZE: usize = 255;
39pub const MAX_EVENT_SIZE: usize = 260;
40pub const MAX_FRAME_SIZE: usize = MAX_ACL_SIZE + 4;
41
42pub enum DeviceEvent {
43    Reg = 1,
44    Unreg = 2,
45    Up = 3,
46    Down = 4,
47    Suspend = 5,
48    Resume = 6,
49}
50pub enum BusType {
51    Virtual = 0,
52    USB = 1,
53    PCCard = 2,
54    UART = 3,
55    RS232 = 4,
56    PCI = 5,
57    SDIO = 6,
58}
59pub enum ControllerType {
60    BREDR = 0x00,
61    AMP = 0x01,
62}
63/// Bluetooth Version reported by HCI Controller according to HCISpec. More versions may be added in
64/// the future once they are released.
65#[derive(Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Debug, Hash)]
66#[repr(u8)]
67#[non_exhaustive]
68pub enum Version {
69    Bluetooth1v0b = 0,
70    Bluetooth1v1 = 1,
71    Bluetooth1v2 = 2,
72    Bluetooth2v0 = 3,
73    Bluetooth2v1 = 4,
74    Bluetooth3v0 = 5,
75    Bluetooth4v0 = 6,
76    Bluetooth4v1 = 7,
77    Bluetooth4v2 = 8,
78    Bluetooth5v0 = 9,
79    Bluetooth5v1 = 10,
80    Bluetooth5v2 = 11,
81}
82impl From<Version> for u8 {
83    fn from(v: Version) -> Self {
84        v as u8
85    }
86}
87impl TryFrom<u8> for Version {
88    type Error = ConversionError;
89
90    fn try_from(value: u8) -> Result<Self, Self::Error> {
91        match value {
92            0 => Ok(Version::Bluetooth1v0b),
93            1 => Ok(Version::Bluetooth1v1),
94            2 => Ok(Version::Bluetooth1v2),
95            3 => Ok(Version::Bluetooth2v0),
96            4 => Ok(Version::Bluetooth2v1),
97            5 => Ok(Version::Bluetooth3v0),
98            6 => Ok(Version::Bluetooth4v0),
99            7 => Ok(Version::Bluetooth4v1),
100            8 => Ok(Version::Bluetooth4v2),
101            9 => Ok(Version::Bluetooth5v0),
102            10 => Ok(Version::Bluetooth5v1),
103            11 => Ok(Version::Bluetooth5v2),
104            _ => Err(ConversionError(())),
105        }
106    }
107}
108/// HCI Error Code. Usually returned from an HCI Controller after each sent command.
109#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
110#[repr(u8)]
111pub enum ErrorCode {
112    Ok = 0x00,
113    UnknownHCICommand = 0x01,
114    NoConnection = 0x02,
115    HardwareFailure = 0x03,
116    PageTimeout = 0x04,
117    AuthenticationFailure = 0x05,
118    KeyMissing = 0x06,
119    MemoryFull = 0x07,
120    ConnectionTimeout = 0x08,
121    MaxNumberOfConnections = 0x09,
122    MaxNumberOfSCOConnectionsToADevice = 0x0A,
123    ACLConnectionAlreadyExists = 0x0B,
124    CommandDisallowed = 0x0C,
125    HostRejectedDueToLimitedResources = 0x0D,
126    HostRejectedDueToSecurityReasons = 0x0E,
127    HostRejectedDueToARemoteDeviceOnlyAPersonalDevice = 0x0F,
128    HostTimeout = 0x10,
129    UnsupportedFeatureOrParameterValue = 0x11,
130    InvalidHCICommandParameters = 0x12,
131    OtherEndTerminatedConnectionUserEndedConnection = 0x13,
132    OtherEndTerminatedConnectionLowResources = 0x14,
133    OtherEndTerminatedConnectionAboutToPowerOff = 0x15,
134    ConnectionTerminatedByLocalHost = 0x16,
135    RepeatedAttempts = 0x17,
136    PairingNotAllowed = 0x18,
137    UnknownLMPPDU = 0x19,
138    UnsupportedRemoteFeature = 0x1A,
139    SCOOffsetRejected = 0x1B,
140    SCOIntervalRejected = 0x1C,
141    SCOAirModeRejected = 0x1D,
142    InvalidLMPParameters = 0x1E,
143    UnspecifiedError = 0x1F,
144    UnsupportedLMPParameter = 0x20,
145    RoleChangeNotAllowed = 0x21,
146    LMPResponseTimeout = 0x22,
147    LMPErrorTransactionCollision = 0x23,
148    LMPPDUNotAllowed = 0x24,
149    EncryptionModeNotAcceptable = 0x25,
150    UnitKeyUsed = 0x26,
151    QoSNotSupported = 0x27,
152    InstantPassed = 0x28,
153    PairingWithUnitKeyNotSupported = 0x29,
154    TransactionCollision = 0x2A,
155    QOSUnacceptableParameter = 0x2C,
156    QOSRejected = 0x2D,
157    ClassificationNotSupported = 0x2E,
158    InsufficientSecurity = 0x2F,
159    ParameterOutOfRange = 0x30,
160    RoleSwitchPending = 0x32,
161    SlotViolation = 0x34,
162    RoleSwitchFailed = 0x35,
163    EIRTooLarge = 0x36,
164    SimplePairingNotSupported = 0x37,
165    HostBusyPairing = 0x38,
166}
167impl ErrorCode {
168    pub const BYTE_LEN: usize = 1;
169    pub fn is_ok(self) -> bool {
170        match self {
171            ErrorCode::Ok => true,
172            _ => false,
173        }
174    }
175    pub fn error(self) -> Result<(), ErrorCode> {
176        match self {
177            ErrorCode::Ok => Ok(()),
178            e => Err(e),
179        }
180    }
181    pub fn as_str(self) -> &'static str {
182        match self {
183            ErrorCode::Ok => "Ok",
184            ErrorCode::UnknownHCICommand => "UnknownHCICommand",
185            ErrorCode::NoConnection => "NoConnection",
186            ErrorCode::HardwareFailure => "HardwareFailure",
187            ErrorCode::PageTimeout => "PageTimeout",
188            ErrorCode::AuthenticationFailure => "AuthenticationFailure",
189            ErrorCode::KeyMissing => "KeyMissing",
190            ErrorCode::MemoryFull => "MemoryFull",
191            ErrorCode::ConnectionTimeout => "ConnectionTimeout",
192            ErrorCode::MaxNumberOfConnections => "MaxNumberOfConnections",
193            ErrorCode::MaxNumberOfSCOConnectionsToADevice => "MaxNumberOfSCOConnectionsToADevice",
194            ErrorCode::ACLConnectionAlreadyExists => "ACLConnectionAlreadyExists",
195            ErrorCode::CommandDisallowed => "CommandDisallowed",
196            ErrorCode::HostRejectedDueToLimitedResources => "HostRejectedDueToLimitedResources",
197            ErrorCode::HostRejectedDueToSecurityReasons => "HostRejectedDueToSecurityReasons",
198            ErrorCode::HostRejectedDueToARemoteDeviceOnlyAPersonalDevice => {
199                "HostRejectedDueToARemoteDeviceOnlyAPersonalDevice"
200            }
201            ErrorCode::HostTimeout => "HostTimeout",
202            ErrorCode::UnsupportedFeatureOrParameterValue => "UnsupportedFeatureOrParameterValue",
203            ErrorCode::InvalidHCICommandParameters => "InvalidHCICommandParameters",
204            ErrorCode::OtherEndTerminatedConnectionUserEndedConnection => {
205                "OtherEndTerminatedConnectionUserEndedConnection"
206            }
207            ErrorCode::OtherEndTerminatedConnectionLowResources => {
208                "OtherEndTerminatedConnectionLowResources"
209            }
210            ErrorCode::OtherEndTerminatedConnectionAboutToPowerOff => {
211                "OtherEndTerminatedConnectionAboutToPowerOff"
212            }
213            ErrorCode::ConnectionTerminatedByLocalHost => "ConnectionTerminatedByLocalHost",
214            ErrorCode::RepeatedAttempts => "RepeatedAttempts",
215            ErrorCode::PairingNotAllowed => "PairingNotAllowed",
216            ErrorCode::UnknownLMPPDU => "UnknownLMPPDU",
217            ErrorCode::UnsupportedRemoteFeature => "UnsupportedRemoteFeature",
218            ErrorCode::SCOOffsetRejected => "SCOOffsetRejected",
219            ErrorCode::SCOIntervalRejected => "SCOIntervalRejected",
220            ErrorCode::SCOAirModeRejected => "SCOAirModeRejected",
221            ErrorCode::InvalidLMPParameters => "InvalidLMPParameters",
222            ErrorCode::UnspecifiedError => "UnspecifiedError",
223            ErrorCode::UnsupportedLMPParameter => "UnsupportedLMPParameter",
224            ErrorCode::RoleChangeNotAllowed => "RoleChangeNotAllowed",
225            ErrorCode::LMPResponseTimeout => "LMPResponseTimeout",
226            ErrorCode::LMPErrorTransactionCollision => "LMPErrorTransactionCollision",
227            ErrorCode::LMPPDUNotAllowed => "LMPPDUNotAllowed",
228            ErrorCode::EncryptionModeNotAcceptable => "EncryptionModeNotAcceptable",
229            ErrorCode::UnitKeyUsed => "UnitKeyUsed",
230            ErrorCode::QoSNotSupported => "QoSNotSupported",
231            ErrorCode::InstantPassed => "InstantPassed",
232            ErrorCode::PairingWithUnitKeyNotSupported => "PairingWithUnitKeyNotSupported",
233            ErrorCode::TransactionCollision => "TransactionCollision",
234            ErrorCode::QOSUnacceptableParameter => "QOSUnacceptableParameter",
235            ErrorCode::QOSRejected => "QOSRejected",
236            ErrorCode::ClassificationNotSupported => "ClassificationNotSupported",
237            ErrorCode::InsufficientSecurity => "InsufficientSecurity",
238            ErrorCode::ParameterOutOfRange => "ParameterOutOfRange",
239            ErrorCode::RoleSwitchPending => "RoleSwitchPending",
240            ErrorCode::SlotViolation => "SlotViolation",
241            ErrorCode::RoleSwitchFailed => "RoleSwitchFailed",
242            ErrorCode::EIRTooLarge => "EIRTooLarge",
243            ErrorCode::SimplePairingNotSupported => "SimplePairingNotSupported",
244            ErrorCode::HostBusyPairing => "HostBusyPairing",
245        }
246    }
247}
248impl core::fmt::Display for ErrorCode {
249    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
250        write!(f, "{}", self.as_str())
251    }
252}
253impl From<ErrorCode> for u8 {
254    fn from(code: ErrorCode) -> Self {
255        code as u8
256    }
257}
258impl TryFrom<u8> for ErrorCode {
259    type Error = ConversionError;
260
261    fn try_from(value: u8) -> Result<Self, Self::Error> {
262        match value {
263            0x00 => Ok(ErrorCode::Ok),
264            0x01 => Ok(ErrorCode::UnknownHCICommand),
265            0x02 => Ok(ErrorCode::NoConnection),
266            0x03 => Ok(ErrorCode::HardwareFailure),
267            0x04 => Ok(ErrorCode::PageTimeout),
268            0x05 => Ok(ErrorCode::AuthenticationFailure),
269            0x06 => Ok(ErrorCode::KeyMissing),
270            0x07 => Ok(ErrorCode::MemoryFull),
271            0x08 => Ok(ErrorCode::ConnectionTimeout),
272            0x09 => Ok(ErrorCode::MaxNumberOfConnections),
273            0x0A => Ok(ErrorCode::MaxNumberOfSCOConnectionsToADevice),
274            0x0B => Ok(ErrorCode::ACLConnectionAlreadyExists),
275            0x0C => Ok(ErrorCode::CommandDisallowed),
276            0x0D => Ok(ErrorCode::HostRejectedDueToLimitedResources),
277            0x0E => Ok(ErrorCode::HostRejectedDueToSecurityReasons),
278            0x0F => Ok(ErrorCode::HostRejectedDueToARemoteDeviceOnlyAPersonalDevice),
279            0x10 => Ok(ErrorCode::HostTimeout),
280            0x11 => Ok(ErrorCode::UnsupportedFeatureOrParameterValue),
281            0x12 => Ok(ErrorCode::InvalidHCICommandParameters),
282            0x13 => Ok(ErrorCode::OtherEndTerminatedConnectionUserEndedConnection),
283            0x14 => Ok(ErrorCode::OtherEndTerminatedConnectionLowResources),
284            0x15 => Ok(ErrorCode::OtherEndTerminatedConnectionAboutToPowerOff),
285            0x16 => Ok(ErrorCode::ConnectionTerminatedByLocalHost),
286            0x17 => Ok(ErrorCode::RepeatedAttempts),
287            0x18 => Ok(ErrorCode::PairingNotAllowed),
288            0x19 => Ok(ErrorCode::UnknownLMPPDU),
289            0x1A => Ok(ErrorCode::UnsupportedRemoteFeature),
290            0x1B => Ok(ErrorCode::SCOOffsetRejected),
291            0x1C => Ok(ErrorCode::SCOIntervalRejected),
292            0x1D => Ok(ErrorCode::SCOAirModeRejected),
293            0x1E => Ok(ErrorCode::InvalidLMPParameters),
294            0x1F => Ok(ErrorCode::UnspecifiedError),
295            0x20 => Ok(ErrorCode::UnsupportedLMPParameter),
296            0x21 => Ok(ErrorCode::RoleChangeNotAllowed),
297            0x22 => Ok(ErrorCode::LMPResponseTimeout),
298            0x23 => Ok(ErrorCode::LMPErrorTransactionCollision),
299            0x24 => Ok(ErrorCode::LMPPDUNotAllowed),
300            0x25 => Ok(ErrorCode::EncryptionModeNotAcceptable),
301            0x26 => Ok(ErrorCode::UnitKeyUsed),
302            0x27 => Ok(ErrorCode::QoSNotSupported),
303            0x28 => Ok(ErrorCode::InstantPassed),
304            0x29 => Ok(ErrorCode::PairingWithUnitKeyNotSupported),
305            _ => Err(ConversionError(())),
306        }
307    }
308}
309pub const EVENT_MAX_LEN: usize = 255;
310pub const COMMAND_MAX_LEN: usize = 255;
311pub const FULL_COMMAND_MAX_LEN: usize = COMMAND_MAX_LEN + OPCODE_LEN + 1;
312pub const EVENT_CODE_LEN: usize = 1;
313/// 6 bit OGF. (OpCode Ground Field)
314#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug, Hash)]
315#[repr(u8)]
316pub enum OGF {
317    NOP = 0x00,
318    LinkControl = 0x01,
319    LinkPolicy = 0x02,
320    HCIControlBaseband = 0x03,
321    InformationalParameters = 0x04,
322    StatusParameters = 0x05,
323    Testing = 0x06,
324    LEController = 0x08,
325    VendorSpecific = 0x3F,
326}
327impl Default for OGF {
328    fn default() -> Self {
329        OGF::NOP
330    }
331}
332impl From<OGF> for u8 {
333    fn from(ogf: OGF) -> Self {
334        ogf as u8
335    }
336}
337impl TryFrom<u8> for OGF {
338    type Error = ConversionError;
339
340    fn try_from(value: u8) -> Result<Self, Self::Error> {
341        match value {
342            0x00 => Ok(OGF::NOP),
343            0x01 => Ok(OGF::LinkControl),
344            0x02 => Ok(OGF::LinkPolicy),
345            0x03 => Ok(OGF::HCIControlBaseband),
346            0x04 => Ok(OGF::InformationalParameters),
347            0x05 => Ok(OGF::StatusParameters),
348            0x06 => Ok(OGF::Testing),
349            0x08 => Ok(OGF::LEController),
350            0x3F => Ok(OGF::VendorSpecific),
351            _ => Err(ConversionError(())),
352        }
353    }
354}
355pub const OCF_MAX: u16 = (1 << 10) - 1;
356/// 10 bit OCF (`Opcode` Command Field)
357#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug, Hash, Default)]
358pub struct OCF(u16);
359impl OCF {
360    /// Creates a new 10-bit OCF
361    /// # Panics
362    /// Panics if `ocf > OCF_MAX` (if `ocf` isn't 10-bit)
363    pub fn new(ocf: u16) -> Self {
364        assert!(ocf <= OCF_MAX, "ocf bigger than 10 bits");
365        Self(ocf)
366    }
367    /// Creates a new 10-bit OCF by masking a u16
368    pub fn new_masked(ocf: u16) -> Self {
369        Self(ocf & OCF_MAX)
370    }
371}
372impl From<OCF> for u16 {
373    fn from(ocf: OCF) -> Self {
374        ocf.0
375    }
376}
377pub const OPCODE_LEN: usize = 2;
378/// 16-bit HCI Opcode. Contains a OGF (OpCode Ground Field) and OCF (OpCode Command Field).
379#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug, Hash, Default)]
380pub struct Opcode(pub OGF, pub OCF);
381impl Opcode {
382    pub const fn byte_len() -> usize {
383        OPCODE_LEN
384    }
385    /// # Errors
386    /// returns `HCIPackError::BadLength` if `buf.len() != OPCODE_LEN`.
387    pub fn pack(self, buf: &mut [u8]) -> Result<(), PackError> {
388        PackError::expect_length(OPCODE_LEN, buf)?;
389        buf[..2].copy_from_slice(&u16::from(self).to_bytes_le());
390        Ok(())
391    }
392    /// # Errors
393    /// returns `HCIPackError::BadLength` if `buf.len() != OPCODE_LEN`.
394    /// returns `HCIPackError::BadBytes` if `buf` doesn't contain a value opcode.
395    pub fn unpack(buf: &[u8]) -> Result<Opcode, PackError> {
396        PackError::expect_length(OPCODE_LEN, buf)?;
397        Ok(u16::from_bytes_le(&buf)
398            .expect("length checked above")
399            .try_into()
400            .ok()
401            .ok_or(PackError::BadBytes { index: Some(0) })?)
402    }
403    pub const fn nop() -> Opcode {
404        Opcode(OGF::NOP, OCF(0))
405    }
406    pub fn is_nop(self) -> bool {
407        self.0 == OGF::NOP
408    }
409}
410impl From<Opcode> for u16 {
411    fn from(opcode: Opcode) -> Self {
412        (opcode.1).0 | (u16::from(u8::from(opcode.0)) << 10)
413    }
414}
415impl TryFrom<u16> for Opcode {
416    type Error = ConversionError;
417
418    fn try_from(value: u16) -> Result<Self, Self::Error> {
419        let ogf = OGF::try_from(u8::try_from(value >> 10).expect("OGF is 6-bits"))?;
420        let ocf = OCF::new_masked(value);
421        Ok(Opcode(ogf, ocf))
422    }
423}