use std::collections::hash_map::Entry;
use std::collections::{HashMap, VecDeque};
use std::fmt::Debug;
use std::mem;
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use structbuf::{Pack, Packer, StructBuf};
use tracing::debug;
pub use handle::*;
pub(crate) use {chan::*, consts::*};
use crate::hci::ACL_HDR;
use crate::{att, hci, host, smp, SyncMutex};
mod chan;
mod consts;
mod handle;
mod rx;
mod tx;
#[allow(clippy::assertions_on_constants)]
const _: () = assert!(usize::BITS > u16::BITS, "usize too small");
#[derive(Clone, Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error(transparent)]
Hci(#[from] hci::Error),
#[error("invalid {0:?}")]
InvalidConn(hci::ConnHandle),
#[error("channel is closed ({0})")]
ChanClosed(LeCid),
#[error("channel is broken ({0})")]
ChanBroken(LeCid),
}
impl From<host::Error> for Error {
#[inline]
fn from(e: host::Error) -> Self {
Self::Hci(e.into())
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub struct ChanManager {
ctl: hci::EventStream,
conns: HashMap<LeU, Conn>,
rm: ResManager,
}
impl ChanManager {
pub async fn new(host: &hci::Host) -> Result<Self> {
Ok(Self {
ctl: host.events(),
conns: HashMap::new(),
rm: ResManager::new(host).await?,
})
}
pub async fn recv(&mut self) -> Result<LeU> {
loop {
tokio::select! {
evt = self.ctl.next() => {
if let Some(link) = self.handle_event(&evt?) {
return Ok(link);
}
}
_ = self.rm.rx.recv() => {} }
}
}
pub fn att_chan(&mut self, link: LeU) -> Option<att::Bearer> {
(self.conns.get_mut(&link)).and_then(|cn| cn.att_opt.take().map(att::Bearer::new))
}
pub fn smp_chan(&mut self, link: LeU) -> Option<smp::Peripheral> {
(self.conns.get_mut(&link).and_then(|cn| cn.smp_opt.take())).map(smp::Peripheral::new)
}
fn handle_event(&mut self, evt: &hci::Event) -> Option<LeU> {
use hci::EventCode::*;
match evt.code() {
LeConnectionComplete | LeEnhancedConnectionComplete => {
return self.handle_connect(&evt.get());
}
DisconnectionComplete => {
self.handle_disconnect(evt.get());
}
NumberOfCompletedPackets => {
self.rm.tx.handle_num_completed(&evt.get());
}
_ => {}
}
None
}
#[allow(dead_code)] fn handle_signal(&mut self, cid: LeCid) {
if cid.chan != Cid::SIG {
return;
}
let _ = self;
debug!("Signal on {cid}");
}
fn handle_connect(&mut self, evt: &hci::LeConnectionComplete) -> Option<LeU> {
if !evt.status.is_ok() {
return None;
}
let link = LeU::new(evt.handle);
let cn = self.ctl.conn(evt.handle).expect("invalid {link}");
let sig = BasicChan::new(link.chan(Cid::SIG), &cn, &self.rm.tx, 23);
let att = BasicChan::new(link.chan(Cid::ATT), &cn, &self.rm.tx, 23);
let sm = BasicChan::new(link.chan(Cid::SMP), &cn, &self.rm.tx, 65);
self.rm.tx.register_link(LeU::new(evt.handle));
self.rm.rx.register_chan(&att.raw);
self.rm.rx.register_chan(&sig.raw);
self.rm.rx.register_chan(&sm.raw);
let cn = Conn {
sig,
att: Arc::clone(&att.raw),
att_opt: Some(att),
smp: Arc::clone(&sm.raw),
smp_opt: Some(sm),
};
assert!(self.conns.insert(link, cn).is_none());
Some(link)
}
fn handle_disconnect(&mut self, evt: hci::DisconnectionComplete) {
if !evt.status.is_ok() {
return;
}
let Some(mut cn) = self.conns.remove(&LeU::new(evt.handle)) else { return };
self.rm.rx.remove_chan(cn.sig.raw.cid);
self.rm.rx.remove_chan(cn.att.cid);
self.rm.rx.remove_chan(cn.smp.cid);
self.rm.tx.handle_disconnect(evt);
cn.set_closed();
}
}
#[derive(Debug)]
struct ResManager {
rx: rx::State,
tx: Arc<tx::State>,
}
impl ResManager {
async fn new(host: &hci::Host) -> Result<Self> {
let mut cbuf = host.le_read_buffer_size().await?;
let acl_num_pkts = if cbuf.acl_data_len == 0 || cbuf.acl_num_pkts == 0 {
let shared = host.read_buffer_size().await?; cbuf.acl_data_len = shared.acl_data_len;
shared.acl_num_pkts
} else {
u16::from(cbuf.acl_num_pkts)
};
debug!("Controller buffers: {:?}", cbuf);
let hbuf = hci::BufferSize {
acl_data_len: cbuf.acl_data_len,
acl_num_pkts: 1,
};
host.host_buffer_size(hbuf).await?;
Ok(Self {
rx: rx::State::new(host.transport(), hbuf.acl_data_len),
tx: tx::State::new(host.transport(), acl_num_pkts, cbuf.acl_data_len),
})
}
}
#[derive(Debug)]
struct Conn {
sig: BasicChan,
att: Arc<RawChan>,
att_opt: Option<BasicChan>,
smp: Arc<RawChan>,
smp_opt: Option<BasicChan>,
}
impl Conn {
fn set_closed(&mut self) {
self.sig.raw.set_closed();
self.att.set_closed();
self.smp.set_closed();
}
}
#[derive(Debug)]
#[must_use]
pub(crate) struct Payload {
f: Frame,
i: usize,
}
impl Payload {
#[inline]
fn new(f: Frame, i: usize) -> Self {
debug_assert!(f.as_ref().len() >= i);
Self { f, i }
}
}
impl AsRef<[u8]> for Payload {
#[inline]
fn as_ref(&self) -> &[u8] {
unsafe { self.f.as_ref().get_unchecked(self.i..) }
}
}
impl Pack for Payload {
#[inline]
fn append(&mut self) -> Packer {
self.f.append()
}
#[inline]
fn at(&mut self, i: usize) -> Packer {
self.f.at(self.i + i)
}
}
#[derive(Debug)]
#[must_use]
enum Frame {
Transfer(AclTransfer),
Buf(StructBuf),
}
impl Frame {
#[inline]
fn complete(xfer: AclTransfer) -> Self {
debug_assert!(ACL_HDR + L2CAP_HDR <= xfer.as_ref().len());
Self::Transfer(xfer)
}
#[inline]
fn first(xfer: &AclTransfer, frame_len: usize) -> StructBuf {
let frag = xfer.as_ref();
debug_assert!(ACL_HDR + L2CAP_HDR <= frag.len() && frag.len() < ACL_HDR + frame_len);
let mut buf = StructBuf::with_capacity(frame_len);
buf.put_at(0, unsafe { frag.get_unchecked(ACL_HDR..) });
buf
}
#[inline]
fn take_xfer(&mut self) -> Option<AclTransfer> {
if matches!(*self, Self::Buf(_)) {
return None;
}
match mem::take(self) {
Self::Transfer(xfer) => Some(xfer),
Self::Buf(_) => unreachable!(),
}
}
}
impl Default for Frame {
#[inline]
fn default() -> Self {
Self::Buf(StructBuf::default())
}
}
impl AsRef<[u8]> for Frame {
#[inline]
fn as_ref(&self) -> &[u8] {
match *self {
Self::Transfer(ref xfer) => unsafe { xfer.as_ref().get_unchecked(ACL_HDR..) },
Self::Buf(ref buf) => buf.as_ref(),
}
}
}
impl Pack for Frame {
#[inline]
fn append(&mut self) -> Packer {
match *self {
Self::Transfer(ref mut xfer) => xfer.append(),
Self::Buf(ref mut buf) => buf.append(),
}
}
#[inline]
fn at(&mut self, i: usize) -> Packer {
match *self {
Self::Transfer(ref mut xfer) => xfer.at(ACL_HDR + i),
Self::Buf(ref mut buf) => buf.at(i),
}
}
}
#[derive(Debug)]
struct Alloc {
transport: Arc<dyn host::Transport>,
free: SyncMutex<Vec<Box<dyn host::Transfer>>>,
acl_data_len: u16,
dir: host::Direction,
}
impl Alloc {
#[inline]
#[must_use]
fn new(
transport: Arc<dyn host::Transport>,
dir: host::Direction,
acl_data_len: u16,
) -> Arc<Self> {
assert!(acl_data_len >= hci::ACL_LE_MIN_DATA_LEN);
Arc::new(Self {
transport,
free: SyncMutex::new(Vec::with_capacity(8)), acl_data_len,
dir,
})
}
#[must_use]
fn xfer(self: &Arc<Self>) -> AclTransfer {
let xfer = self.free.lock().pop().map_or_else(
|| self.transport.acl(self.dir, self.acl_data_len),
|mut xfer| {
xfer.reset();
xfer
},
);
AclTransfer::new(xfer, Arc::clone(self))
}
fn frame(self: &Arc<Self>, max_frame_len: usize) -> Frame {
if max_frame_len <= self.acl_data_len as usize {
#[allow(clippy::cast_possible_truncation)]
let mut xfer = self.transport.acl(self.dir, max_frame_len as u16);
xfer.at(ACL_HDR + L2CAP_HDR).put([]);
Frame::Transfer(AclTransfer::new(xfer, Arc::clone(self)))
} else {
let mut buf = StructBuf::new(max_frame_len);
buf.at(L2CAP_HDR).put([]);
Frame::Buf(buf)
}
}
}
#[derive(Debug)]
struct AclTransfer(ManuallyDrop<(Box<dyn host::Transfer>, Arc<Alloc>)>);
impl AclTransfer {
#[inline]
fn new(xfer: Box<dyn host::Transfer>, alloc: Arc<Alloc>) -> Self {
Self(ManuallyDrop::new((xfer, alloc)))
}
#[inline]
fn dir(&self) -> host::Direction {
self.0 .1.dir
}
#[inline]
async fn submit(self) -> host::Result<Self> {
let (xfer, alloc) = unsafe { ManuallyDrop::take(&mut ManuallyDrop::new(self).0) };
Ok(Self::new(xfer.submit()?.await?, alloc))
}
}
impl Drop for AclTransfer {
fn drop(&mut self) {
let (mut xfer, alloc) = unsafe { ManuallyDrop::take(&mut self.0) };
if xfer.at(ACL_HDR).remaining() != alloc.acl_data_len as usize {
return; }
let mut free = alloc.free.lock();
if free.len() < free.capacity() {
free.push(xfer);
}
}
}
impl Deref for AclTransfer {
type Target = dyn host::Transfer;
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.0 .0.as_ref()
}
}
impl DerefMut for AclTransfer {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
self.0 .0.as_mut()
}
}