1 //! Rootcanal HAL
2 //! This connects to "rootcanal" which provides a simulated
3 //! Bluetooth chip as well as a simulated environment.
4 
5 use crate::internal::{InnerHal, RawHal};
6 use crate::{Result, H4_HEADER_SIZE};
7 use bt_packets::hci::{AclPacket, CommandPacket, EventPacket, IsoPacket, Packet};
8 use bytes::{BufMut, Bytes, BytesMut};
9 use gddi::{module, provides, Stoppable};
10 use num_derive::{FromPrimitive, ToPrimitive};
11 use std::net::{IpAddr, SocketAddr};
12 use std::str::FromStr;
13 use std::sync::Arc;
14 use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader};
15 use tokio::net::TcpStream;
16 use tokio::runtime::Runtime;
17 use tokio::select;
18 use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
19 
20 #[derive(FromPrimitive, ToPrimitive)]
21 enum HciPacketType {
22     Command = 0x01,
23     Acl = 0x02,
24     Sco = 0x03,
25     Event = 0x04,
26     Iso = 0x05,
27 }
28 
29 const SIZE_OF_EVENT_HEADER: usize = 2;
30 const _SIZE_OF_SCO_HEADER: usize = 3;
31 const SIZE_OF_ACL_HEADER: usize = 4;
32 const SIZE_OF_ISO_HEADER: usize = 4;
33 
34 module! {
35     rootcanal_hal_module,
36     providers {
37         RawHal => provide_rootcanal_hal,
38     }
39 }
40 
41 #[provides]
provide_rootcanal_hal(config: RootcanalConfig, rt: Arc<Runtime>) -> RawHal42 async fn provide_rootcanal_hal(config: RootcanalConfig, rt: Arc<Runtime>) -> RawHal {
43     let (raw_hal, inner_hal) = InnerHal::new();
44     let (reader, writer) = TcpStream::connect(&config.to_socket_addr().unwrap())
45         .await
46         .expect("unable to create stream to rootcanal")
47         .into_split();
48 
49     rt.spawn(dispatch_incoming(inner_hal.evt_tx, inner_hal.acl_tx, inner_hal.iso_tx, reader));
50     rt.spawn(dispatch_outgoing(inner_hal.cmd_rx, inner_hal.acl_rx, inner_hal.iso_rx, writer));
51 
52     raw_hal
53 }
54 
55 /// Rootcanal configuration
56 #[derive(Clone, Debug, Default, Stoppable)]
57 pub struct RootcanalConfig {
58     address: String,
59     port: u16,
60 }
61 
62 impl RootcanalConfig {
63     /// Create a rootcanal config
new(address: &str, port: u16) -> Self64     pub fn new(address: &str, port: u16) -> Self {
65         Self { address: String::from(address), port }
66     }
67 
to_socket_addr(&self) -> Result<SocketAddr>68     fn to_socket_addr(&self) -> Result<SocketAddr> {
69         Ok(SocketAddr::new(IpAddr::from_str(&self.address)?, self.port))
70     }
71 }
72 
73 /// Send HCI events received from the HAL to the HCI layer
dispatch_incoming<R>( evt_tx: UnboundedSender<EventPacket>, acl_tx: UnboundedSender<AclPacket>, iso_tx: UnboundedSender<IsoPacket>, reader: R, ) -> Result<()> where R: AsyncReadExt + Unpin,74 async fn dispatch_incoming<R>(
75     evt_tx: UnboundedSender<EventPacket>,
76     acl_tx: UnboundedSender<AclPacket>,
77     iso_tx: UnboundedSender<IsoPacket>,
78     reader: R,
79 ) -> Result<()>
80 where
81     R: AsyncReadExt + Unpin,
82 {
83     let mut reader = BufReader::new(reader);
84     loop {
85         let mut buffer = BytesMut::with_capacity(1024);
86         buffer.resize(H4_HEADER_SIZE, 0);
87         reader.read_exact(&mut buffer).await?;
88         if buffer[0] == HciPacketType::Event as u8 {
89             buffer.resize(SIZE_OF_EVENT_HEADER, 0);
90             reader.read_exact(&mut buffer).await?;
91             let len: usize = buffer[1].into();
92             let mut payload = buffer.split_off(SIZE_OF_EVENT_HEADER);
93             payload.resize(len, 0);
94             reader.read_exact(&mut payload).await?;
95             buffer.unsplit(payload);
96             let frozen = buffer.freeze();
97             match EventPacket::parse(&frozen) {
98                 Ok(p) => evt_tx.send(p).unwrap(),
99                 Err(e) => log::error!("dropping invalid event packet: {}: {:02x}", e, frozen),
100             }
101         } else if buffer[0] == HciPacketType::Acl as u8 {
102             buffer.resize(SIZE_OF_ACL_HEADER, 0);
103             reader.read_exact(&mut buffer).await?;
104             let len: usize = (buffer[2] as u16 + ((buffer[3] as u16) << 8)).into();
105             let mut payload = buffer.split_off(SIZE_OF_ACL_HEADER);
106             payload.resize(len, 0);
107             reader.read_exact(&mut payload).await?;
108             buffer.unsplit(payload);
109             let frozen = buffer.freeze();
110             match AclPacket::parse(&frozen) {
111                 Ok(p) => acl_tx.send(p).unwrap(),
112                 Err(e) => log::error!("dropping invalid ACL packet: {}: {:02x}", e, frozen),
113             }
114         } else if buffer[0] == HciPacketType::Iso as u8 {
115             buffer.resize(SIZE_OF_ISO_HEADER, 0);
116             reader.read_exact(&mut buffer).await?;
117             let len: usize = (buffer[2] as u16 + (((buffer[3] & 0x3f) as u16) << 8)).into();
118             let mut payload = buffer.split_off(SIZE_OF_ISO_HEADER);
119             payload.resize(len, 0);
120             reader.read_exact(&mut payload).await?;
121             buffer.unsplit(payload);
122             let frozen = buffer.freeze();
123             match IsoPacket::parse(&frozen) {
124                 Ok(p) => iso_tx.send(p).unwrap(),
125                 Err(e) => log::error!("dropping invalid ISO packet: {}: {:02x}", e, frozen),
126             }
127         }
128     }
129 }
130 
131 /// Send commands received from the HCI later to rootcanal
dispatch_outgoing<W>( mut cmd_rx: UnboundedReceiver<CommandPacket>, mut acl_rx: UnboundedReceiver<AclPacket>, mut iso_rx: UnboundedReceiver<IsoPacket>, mut writer: W, ) -> Result<()> where W: AsyncWriteExt + Unpin,132 async fn dispatch_outgoing<W>(
133     mut cmd_rx: UnboundedReceiver<CommandPacket>,
134     mut acl_rx: UnboundedReceiver<AclPacket>,
135     mut iso_rx: UnboundedReceiver<IsoPacket>,
136     mut writer: W,
137 ) -> Result<()>
138 where
139     W: AsyncWriteExt + Unpin,
140 {
141     loop {
142         select! {
143             Some(cmd) = cmd_rx.recv() => write_with_type(&mut writer, HciPacketType::Command, cmd.to_bytes()).await?,
144             Some(acl) = acl_rx.recv() => write_with_type(&mut writer, HciPacketType::Acl, acl.to_bytes()).await?,
145             Some(iso) = iso_rx.recv() => write_with_type(&mut writer, HciPacketType::Iso, iso.to_bytes()).await?,
146             else => break,
147         }
148     }
149 
150     Ok(())
151 }
152 
write_with_type<W>(writer: &mut W, t: HciPacketType, b: Bytes) -> Result<()> where W: AsyncWriteExt + Unpin,153 async fn write_with_type<W>(writer: &mut W, t: HciPacketType, b: Bytes) -> Result<()>
154 where
155     W: AsyncWriteExt + Unpin,
156 {
157     let mut data = BytesMut::with_capacity(b.len() + 1);
158     data.put_u8(t as u8);
159     data.extend(b);
160     writer.write_all(&data[..]).await?;
161 
162     Ok(())
163 }
164