ots_core/
l2cap.rs

1use core::mem::{size_of, MaybeUninit};
2use std::{
3    io::{Error, Result},
4    os::fd::{AsRawFd, RawFd},
5};
6
7pub use macaddr::MacAddr6 as MacAddress;
8pub use socket2::Type as SocketType;
9
10/// Address type
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[repr(u8)]
13pub enum AddressType {
14    Public = 1,
15    Random = 2,
16}
17
18/// L2CAP socket address
19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct L2capSockAddr {
21    /// MAC address
22    pub addr: MacAddress,
23    /// Address type
24    pub type_: AddressType,
25    /// PSM
26    pub psm: u16,
27    /// CID
28    pub cid: u16,
29}
30
31#[derive(Clone, Copy)]
32#[repr(i32)]
33#[non_exhaustive]
34enum BtProto {
35    L2Cap = 0,
36}
37
38#[derive(Clone, Copy)]
39#[repr(u16)]
40#[non_exhaustive]
41pub enum Psm {
42    L2CapLeCidOts = 0x25,
43    L2CapLeDynStart = 0x80,
44}
45
46impl From<Psm> for u16 {
47    fn from(psm: Psm) -> u16 {
48        psm as _
49    }
50}
51
52#[derive(Clone, Copy)]
53#[repr(i32)]
54#[non_exhaustive]
55enum SockOpt {
56    BtSndMtu = 12,
57    BtRcvMtu = 13,
58}
59
60impl L2capSockAddr {
61    /// Create L2CAP socket address
62    pub fn new(addr: MacAddress, type_: AddressType, psm: impl Into<u16>) -> Self {
63        Self {
64            addr,
65            type_,
66            psm: psm.into(),
67            cid: 0,
68        }
69    }
70}
71
72#[derive(Clone, Copy)]
73#[allow(non_camel_case_types)]
74#[repr(C)]
75struct sockaddr_l2 {
76    pub l2_family: libc::sa_family_t,
77    pub l2_psm: libc::c_ushort,
78    pub l2_bdaddr: bdaddr_t,
79    pub l2_cid: libc::c_ushort,
80    pub l2_bdaddr_type: u8,
81}
82
83impl From<&L2capSockAddr> for socket2::SockAddr {
84    fn from(sockaddr: &L2capSockAddr) -> Self {
85        let mut addr_storage: libc::sockaddr_storage = unsafe { core::mem::zeroed() };
86        let sockaddr_ref = unsafe { &mut *(&mut addr_storage as *mut _ as *mut sockaddr_l2) };
87
88        sockaddr_ref.l2_family = libc::AF_BLUETOOTH as _;
89        sockaddr_ref.l2_psm = sockaddr.psm.to_le();
90        sockaddr_ref.l2_bdaddr = bdaddr_t::from(&sockaddr.addr);
91        sockaddr_ref.l2_cid = sockaddr.cid;
92        sockaddr_ref.l2_bdaddr_type = sockaddr.type_ as _;
93
94        unsafe { socket2::SockAddr::new(addr_storage, size_of::<sockaddr_l2>() as _) }
95    }
96}
97
98impl TryFrom<socket2::SockAddr> for L2capSockAddr {
99    type Error = Error;
100    fn try_from(sockaddr: socket2::SockAddr) -> Result<Self> {
101        let addr_storage = sockaddr.as_storage();
102        let sockaddr_ref = unsafe { &*(&addr_storage as *const _ as *const sockaddr_l2) };
103
104        if sockaddr_ref.l2_family != libc::AF_BLUETOOTH as _ {
105            return Err(Error::new(
106                std::io::ErrorKind::InvalidInput,
107                "Bluetooth address family expected",
108            ));
109        }
110
111        Ok(Self {
112            addr: sockaddr_ref.l2_bdaddr.into(),
113            type_: match sockaddr_ref.l2_bdaddr_type {
114                1 => AddressType::Public,
115                2 => AddressType::Random,
116                _ => {
117                    return Err(Error::new(
118                        std::io::ErrorKind::InvalidInput,
119                        "Unknown L2CAP address type",
120                    ))
121                }
122            },
123            psm: sockaddr_ref.l2_psm,
124            cid: sockaddr_ref.l2_cid,
125        })
126    }
127}
128
129#[derive(Clone, Copy)]
130#[allow(non_camel_case_types)]
131#[repr(C, packed)]
132struct bdaddr_t {
133    pub b: [u8; 6],
134}
135
136impl From<&MacAddress> for bdaddr_t {
137    fn from(macaddr: &MacAddress) -> Self {
138        let addr = macaddr.into_array();
139
140        #[cfg(target_endian = "little")]
141        let addr = {
142            let mut addr = addr;
143            addr.reverse();
144            addr
145        };
146
147        Self { b: addr }
148    }
149}
150
151impl From<&bdaddr_t> for MacAddress {
152    fn from(bdaddr: &bdaddr_t) -> Self {
153        let addr = bdaddr.b;
154
155        #[cfg(target_endian = "little")]
156        let addr = {
157            let mut addr = addr;
158            addr.reverse();
159            addr
160        };
161
162        Self::from(addr)
163    }
164}
165
166impl From<bdaddr_t> for MacAddress {
167    fn from(bdaddr: bdaddr_t) -> Self {
168        Self::from(&bdaddr)
169    }
170}
171
172/// Bluetooth security
173#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
174#[repr(C)]
175pub struct Security {
176    /// Level.
177    pub level: SecurityLevel,
178    /// Key size
179    pub key_size: u8,
180}
181
182pub const BT_SECURITY: i32 = 4;
183
184/// Bluetooth security level
185#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
186#[repr(u8)]
187pub enum SecurityLevel {
188    /// SPD
189    Sdp = 0,
190    /// Low (default)
191    #[default]
192    Low = 1,
193    /// Medium
194    Medium = 2,
195    /// High
196    High = 3,
197    /// FIPS
198    Fips = 4,
199}
200
201pub struct L2capSocket {
202    inner: socket2::Socket,
203}
204
205impl core::ops::Deref for L2capSocket {
206    type Target = socket2::Socket;
207
208    fn deref(&self) -> &Self::Target {
209        &self.inner
210    }
211}
212
213impl core::ops::DerefMut for L2capSocket {
214    fn deref_mut(&mut self) -> &mut Self::Target {
215        &mut self.inner
216    }
217}
218
219impl L2capSocket {
220    pub fn new(type_: SocketType) -> Result<Self> {
221        let inner = socket2::Socket::new(
222            libc::AF_BLUETOOTH.into(),
223            type_,
224            Some((BtProto::L2Cap as i32).into()),
225        )?;
226        Ok(Self { inner })
227    }
228
229    pub fn bind(&self, sockaddr: &L2capSockAddr) -> Result<()> {
230        self.inner.bind(&sockaddr.into())
231    }
232
233    pub fn connect(&self, sockaddr: &L2capSockAddr) -> Result<()> {
234        self.inner.connect(&sockaddr.into())
235    }
236
237    pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> {
238        self.inner.set_nonblocking(nonblocking)
239    }
240
241    /// Get the local address of this socket.
242    pub fn local_addr(&self) -> Result<L2capSockAddr> {
243        self.inner.local_addr().and_then(TryFrom::try_from)
244    }
245
246    /// Get the peer address of this socket.
247    pub fn peer_addr(&self) -> Result<L2capSockAddr> {
248        self.inner.peer_addr().and_then(TryFrom::try_from)
249    }
250
251    pub fn security(&self) -> Result<Security> {
252        getsockopt(&self.inner, libc::SOL_BLUETOOTH, BT_SECURITY)
253    }
254
255    pub fn set_security(&self, security: &Security) -> Result<()> {
256        setsockopt(&self.inner, libc::SOL_BLUETOOTH, BT_SECURITY, security)
257    }
258
259    pub fn recv_mtu(&self) -> Result<usize> {
260        Ok(getsockopt::<u16>(&self.inner, libc::SOL_BLUETOOTH, SockOpt::BtRcvMtu as _)? as _)
261    }
262
263    pub fn set_recv_mtu(&self, mtu: usize) -> Result<()> {
264        let mtu = mtu as u16;
265        setsockopt(
266            &self.inner,
267            libc::SOL_BLUETOOTH,
268            SockOpt::BtRcvMtu as _,
269            &mtu,
270        )
271    }
272
273    pub fn send_mtu(&self) -> Result<usize> {
274        Ok(getsockopt::<u16>(&self.inner, libc::SOL_BLUETOOTH, SockOpt::BtSndMtu as _)? as _)
275    }
276
277    pub fn set_send_mtu(&self, mtu: usize) -> Result<()> {
278        let mtu = mtu as u16;
279        setsockopt(
280            &self.inner,
281            libc::SOL_BLUETOOTH,
282            SockOpt::BtSndMtu as _,
283            &mtu,
284        )
285    }
286}
287
288impl AsRawFd for L2capSocket {
289    fn as_raw_fd(&self) -> RawFd {
290        self.inner.as_raw_fd()
291    }
292}
293
294fn getsockopt<T>(socket: &impl AsRawFd, level: libc::c_int, optname: libc::c_int) -> Result<T> {
295    let mut optval: MaybeUninit<T> = MaybeUninit::uninit();
296    let mut optlen: libc::socklen_t = size_of::<T>() as _;
297    if unsafe {
298        libc::getsockopt(
299            socket.as_raw_fd(),
300            level,
301            optname,
302            optval.as_mut_ptr() as *mut _,
303            &mut optlen,
304        )
305    } == -1
306    {
307        return Err(Error::last_os_error());
308    }
309    if optlen != size_of::<T>() as _ {
310        return Err(Error::new(std::io::ErrorKind::InvalidInput, "invalid size"));
311    }
312    let optval = unsafe { optval.assume_init() };
313    Ok(optval)
314}
315
316fn setsockopt<T>(
317    socket: &impl AsRawFd,
318    level: libc::c_int,
319    optname: libc::c_int,
320    optval: &T,
321) -> Result<()> {
322    let optlen: libc::socklen_t = size_of::<T>() as _;
323    if unsafe {
324        libc::setsockopt(
325            socket.as_raw_fd(),
326            level,
327            optname,
328            optval as *const _ as *const _,
329            optlen,
330        )
331    } == -1
332    {
333        return Err(Error::last_os_error());
334    }
335    Ok(())
336}