mod signaling;
use self::signaling::SignalingState;
use crate::att::{self, AttributeProvider, AttributeServer, NoAttributes};
use crate::link::queue::{Consume, Producer};
use crate::link::{data::Llid, MIN_DATA_PAYLOAD_BUF};
use crate::security::{NoSecurity, SecurityLevel, SecurityManager};
use crate::{bytes::*, utils::HexSlice, Error};
use core::fmt;
use core::ops::{Deref, DerefMut};
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
pub struct Channel(u16);
impl Channel {
pub const NULL: Self = Channel(0x0000);
pub const ATT: Self = Channel(0x0004);
pub const LE_SIGNALING: Self = Channel(0x0005);
pub const LE_SECURITY_MANAGER: Self = Channel(0x0006);
pub fn as_raw(&self) -> u16 {
self.0
}
pub fn is_connection_oriented(&self) -> bool {
!self.is_connectionless()
}
pub fn is_connectionless(&self) -> bool {
matches!(self.0, 0x0002 | 0x0001 | 0x0005)
}
}
impl fmt::Debug for Channel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:#06X}", self.0)
}
}
impl FromBytes<'_> for Channel {
fn from_bytes(bytes: &mut ByteReader<'_>) -> Result<Self, Error> {
Ok(Channel(bytes.read_u16_le()?))
}
}
impl ToBytes for Channel {
fn to_bytes(&self, writer: &mut ByteWriter<'_>) -> Result<(), Error> {
writer.write_u16_le(self.0)
}
}
pub trait ChannelMapper {
type AttributeProvider: AttributeProvider;
fn lookup(&mut self, channel: Channel) -> Option<ChannelData<'_, dyn ProtocolObj + '_>>;
fn att(&mut self) -> ChannelData<'_, AttributeServer<Self::AttributeProvider>>;
}
pub struct ChannelData<'a, P: ?Sized> {
response_channel: Channel,
protocol: &'a mut P,
pdu: u8,
}
impl<'a> ChannelData<'a, dyn ProtocolObj + 'a> {
fn new_dyn<T: Protocol + 'a>(response_channel: Channel, protocol: &'a mut T) -> Self {
assert!(
usize::from(T::RSP_PDU_SIZE + Header::SIZE) <= MIN_DATA_PAYLOAD_BUF,
"protocol min PDU is smaller than data channel PDU (L2CAP reassembly NYI)"
);
ChannelData {
response_channel,
pdu: T::RSP_PDU_SIZE,
protocol,
}
}
}
impl<'a, P: Protocol> ChannelData<'a, P> {
fn new(response_channel: Channel, protocol: &'a mut P) -> Self {
assert!(
usize::from(P::RSP_PDU_SIZE + Header::SIZE) <= MIN_DATA_PAYLOAD_BUF,
"protocol min PDU is smaller than data channel PDU (L2CAP reassembly NYI)"
);
ChannelData {
response_channel,
pdu: P::RSP_PDU_SIZE,
protocol,
}
}
}
impl<'a, P: ?Sized> ChannelData<'a, P> {
pub fn response_channel(&self) -> Channel {
self.response_channel
}
pub fn pdu_size(&self) -> u8 {
self.pdu
}
pub fn protocol(&mut self) -> &mut P {
self.protocol
}
pub fn into_protocol(self) -> &'a mut P {
self.protocol
}
}
pub struct BleChannelMap<A: AttributeProvider, S: SecurityLevel> {
att: AttributeServer<A>,
signaling: SignalingState,
sm: SecurityManager<S>,
}
impl BleChannelMap<NoAttributes, NoSecurity> {
pub fn empty() -> Self {
Self {
att: AttributeServer::new(NoAttributes),
signaling: SignalingState::new(),
sm: SecurityManager::no_security(),
}
}
}
impl<A: AttributeProvider> BleChannelMap<A, NoSecurity> {
pub fn with_attributes(att: A) -> Self {
Self {
att: AttributeServer::new(att),
signaling: SignalingState::new(),
sm: SecurityManager::no_security(),
}
}
pub fn attribute_provider(&mut self) -> &mut A {
self.att.provider()
}
}
impl<A: AttributeProvider, S: SecurityLevel> ChannelMapper for BleChannelMap<A, S> {
type AttributeProvider = A;
fn lookup(&mut self, channel: Channel) -> Option<ChannelData<'_, dyn ProtocolObj + '_>> {
match channel {
Channel::ATT => Some(ChannelData::new_dyn(channel, &mut self.att)),
Channel::LE_SIGNALING => Some(ChannelData::new_dyn(channel, &mut self.signaling)),
Channel::LE_SECURITY_MANAGER => Some(ChannelData::new_dyn(channel, &mut self.sm)),
_ => None,
}
}
fn att(&mut self) -> ChannelData<'_, AttributeServer<Self::AttributeProvider>> {
ChannelData::new(Channel::ATT, &mut self.att)
}
}
pub trait ProtocolObj {
fn process_message(&mut self, message: &[u8], responder: Sender<'_>) -> Result<(), Error>;
}
pub trait Protocol: ProtocolObj {
const RSP_PDU_SIZE: u8;
}
#[derive(Debug)]
struct Header {
length: u16,
channel: Channel,
}
impl Header {
const SIZE: u8 = 2 + 2;
}
impl<'a> FromBytes<'a> for Header {
fn from_bytes(bytes: &mut ByteReader<'a>) -> Result<Self, Error> {
let length = bytes.read_u16_le()?;
let channel = Channel::from_bytes(bytes)?;
Ok(Self { length, channel })
}
}
impl ToBytes for Header {
fn to_bytes(&self, writer: &mut ByteWriter<'_>) -> Result<(), Error> {
writer.write_u16_le(self.length)?;
writer.write_u16_le(self.channel.as_raw())?;
Ok(())
}
}
struct Message<P> {
header: Header,
payload: P,
}
impl<'a, P: FromBytes<'a>> FromBytes<'a> for Message<P> {
fn from_bytes(bytes: &mut ByteReader<'a>) -> Result<Self, Error> {
let header = Header::from_bytes(bytes)?;
assert_eq!(
header.length as usize,
bytes.bytes_left(),
"L2CAP reassembly not yet implemented"
);
Ok(Self {
header,
payload: P::from_bytes(bytes)?,
})
}
}
impl<P: ToBytes> ToBytes for Message<P> {
fn to_bytes(&self, writer: &mut ByteWriter<'_>) -> Result<(), Error> {
self.header.to_bytes(writer)?;
self.payload.to_bytes(writer)?;
Ok(())
}
}
#[derive(Debug)]
pub struct L2CAPState<M: ChannelMapper> {
mapper: M,
}
impl<M: ChannelMapper> L2CAPState<M> {
pub fn new(mapper: M) -> Self {
Self { mapper }
}
pub fn tx<'a, P: Producer>(&'a mut self, tx: &'a mut P) -> L2CAPStateTx<'a, M, P> {
L2CAPStateTx { l2cap: self, tx }
}
pub fn channel_mapper(&mut self) -> &mut M {
&mut self.mapper
}
}
pub struct Sender<'a> {
pdu: u8,
tx: &'a mut dyn Producer,
channel: Channel,
}
impl<'a> Sender<'a> {
fn new<T: ?Sized>(chdata: &ChannelData<'_, T>, tx: &'a mut dyn Producer) -> Option<Self> {
let free = tx.free_space();
let needed = chdata.pdu_size() + Header::SIZE;
if free < needed {
debug!("{} free bytes, need {}", free, needed);
return None;
}
let resp_channel = chdata.response_channel();
let pdu = chdata.pdu_size();
Some(Sender {
pdu,
tx,
channel: resp_channel,
})
}
pub fn send<P: ToBytes>(&mut self, payload: P) -> Result<(), Error> {
self.send_with(|writer| payload.to_bytes(writer))
}
pub fn send_with<T, E>(
&mut self,
f: impl FnOnce(&mut ByteWriter<'_>) -> Result<T, E>,
) -> Result<T, E>
where
E: From<Error>,
{
let mut f = Some(f);
let channel = self.channel;
let pdu = self.pdu;
let mut r = None;
let r2 = self.tx.produce_dyn(
pdu + Header::SIZE,
&mut |writer: &mut ByteWriter<'_>| -> Result<_, Error> {
let mut header_writer = writer.split_off(usize::from(Header::SIZE))?;
assert!(writer.space_left() >= pdu.into());
let mut payload_writer = ByteWriter::new(&mut writer.rest()[..pdu.into()]);
let left = payload_writer.space_left();
let result = f.take().unwrap()(&mut payload_writer);
let is_ok = result.is_ok();
r = Some(result);
let used = left - payload_writer.space_left();
writer.skip(used).unwrap();
assert!(used < 0xFFFF);
Header {
length: used as u16,
channel,
}
.to_bytes(&mut header_writer)?;
assert_eq!(header_writer.space_left(), 0);
if is_ok {
Ok(Llid::DataStart)
} else {
Err(Error::InvalidValue)
}
},
);
if let Err(e) = r2 {
if e != Error::InvalidValue {
return Err(e.into());
}
}
r.unwrap()
}
}
pub struct L2CAPStateTx<'a, M: ChannelMapper, P: Producer> {
l2cap: &'a mut L2CAPState<M>,
tx: &'a mut P,
}
impl<'a, M: ChannelMapper, P: Producer> L2CAPStateTx<'a, M, P> {
pub fn process_start(&mut self, message: &[u8]) -> Consume<()> {
let msg = match Message::<&[u8]>::from_bytes(&mut ByteReader::new(message)) {
Ok(msg) => msg,
Err(e) => return Consume::always(Err(e)),
};
if usize::from(msg.header.length) != msg.payload.len() {
unimplemented!("L2CAP reassembly");
}
self.dispatch(msg.header.channel, msg.payload)
}
pub fn process_cont(&mut self, _data: &[u8]) -> Consume<()> {
unimplemented!("reassembly")
}
fn dispatch(&mut self, channel: Channel, payload: &[u8]) -> Consume<()> {
if let Some(mut chdata) = self.l2cap.mapper.lookup(channel) {
let sender = if let Some(sender) = Sender::new(&chdata, self.tx) {
sender
} else {
return Consume::never(Ok(()));
};
Consume::always(chdata.protocol().process_message(payload, sender))
} else {
warn!(
"ignoring message sent to unconnected channel {:?}: {:?}",
channel,
HexSlice(payload)
);
Consume::always(Ok(()))
}
}
pub fn att(&mut self) -> Option<att::AttributeServerTx<'_, M::AttributeProvider>> {
let att = self.l2cap.mapper.att();
Sender::new(&att, self.tx).map(move |sender| att.into_protocol().with_sender(sender))
}
}
impl<'a, M: ChannelMapper, P: Producer> Deref for L2CAPStateTx<'a, M, P> {
type Target = L2CAPState<M>;
fn deref(&self) -> &Self::Target {
&self.l2cap
}
}
impl<'a, M: ChannelMapper, P: Producer> DerefMut for L2CAPStateTx<'a, M, P> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.l2cap
}
}