• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::cell::{Cell, RefCell};
2 use std::collections::VecDeque;
3 use std::convert::{TryFrom, TryInto};
4 use std::future::Future;
5 use std::pin::Pin;
6 use std::rc::{Rc, Weak};
7 use std::task::{Context, Poll};
8 
9 use thiserror::Error;
10 
11 use crate::ffi::LinkManagerOps;
12 use crate::future::noop_waker;
13 use crate::packets::{hci, lmp};
14 use crate::procedure;
15 
16 use hci::Packet as _;
17 use lmp::Packet as _;
18 
19 /// Number of hci command packets used
20 /// in Command Complete and Command Status
21 #[allow(non_upper_case_globals)]
22 pub const num_hci_command_packets: u8 = 1;
23 
24 struct Link {
25     peer: Cell<hci::Address>,
26     // Only store one HCI packet as our Num_HCI_Command_Packets
27     // is always 1
28     hci: Cell<Option<hci::CommandPacket>>,
29     lmp: RefCell<VecDeque<lmp::PacketPacket>>,
30 }
31 
32 impl Default for Link {
default() -> Self33     fn default() -> Self {
34         Link {
35             peer: Cell::new(hci::EMPTY_ADDRESS),
36             hci: Default::default(),
37             lmp: Default::default(),
38         }
39     }
40 }
41 
42 impl Link {
ingest_lmp(&self, packet: lmp::PacketPacket)43     fn ingest_lmp(&self, packet: lmp::PacketPacket) {
44         self.lmp.borrow_mut().push_back(packet);
45     }
46 
ingest_hci(&self, command: hci::CommandPacket)47     fn ingest_hci(&self, command: hci::CommandPacket) {
48         assert!(self.hci.replace(Some(command)).is_none(), "HCI flow control violation");
49     }
50 
poll_hci_command<C: TryFrom<hci::CommandPacket>>(&self) -> Poll<C>51     fn poll_hci_command<C: TryFrom<hci::CommandPacket>>(&self) -> Poll<C> {
52         let command = self.hci.take();
53 
54         if let Some(command) = command.clone().and_then(|c| c.try_into().ok()) {
55             Poll::Ready(command)
56         } else {
57             self.hci.set(command);
58             Poll::Pending
59         }
60     }
61 
poll_lmp_packet<P: TryFrom<lmp::PacketPacket>>(&self) -> Poll<P>62     fn poll_lmp_packet<P: TryFrom<lmp::PacketPacket>>(&self) -> Poll<P> {
63         let mut queue = self.lmp.borrow_mut();
64         let packet = queue.front().and_then(|packet| packet.clone().try_into().ok());
65 
66         if let Some(packet) = packet {
67             queue.pop_front();
68             Poll::Ready(packet)
69         } else {
70             Poll::Pending
71         }
72     }
73 
reset(&self)74     fn reset(&self) {
75         self.peer.set(hci::EMPTY_ADDRESS);
76         self.hci.set(None);
77         self.lmp.borrow_mut().clear();
78     }
79 }
80 
81 #[derive(Error, Debug)]
82 pub enum LinkManagerError {
83     #[error("Unknown peer")]
84     UnknownPeer,
85     #[error("Unhandled HCI packet")]
86     UnhandledHciPacket,
87     #[error("Maximum number of links reached")]
88     MaxNumberOfLink,
89 }
90 
91 /// Max number of Bluetooth Peers
92 pub const MAX_PEER_NUMBER: usize = 7;
93 
94 pub struct LinkManager {
95     ops: LinkManagerOps,
96     links: [Link; MAX_PEER_NUMBER],
97     procedures: RefCell<[Option<Pin<Box<dyn Future<Output = ()>>>>; MAX_PEER_NUMBER]>,
98 }
99 
100 impl LinkManager {
new(ops: LinkManagerOps) -> Self101     pub fn new(ops: LinkManagerOps) -> Self {
102         Self { ops, links: Default::default(), procedures: Default::default() }
103     }
104 
get_link(&self, peer: hci::Address) -> Option<&Link>105     fn get_link(&self, peer: hci::Address) -> Option<&Link> {
106         self.links.iter().find(|link| link.peer.get() == peer)
107     }
108 
ingest_lmp( &self, from: hci::Address, packet: lmp::PacketPacket, ) -> Result<(), LinkManagerError>109     pub fn ingest_lmp(
110         &self,
111         from: hci::Address,
112         packet: lmp::PacketPacket,
113     ) -> Result<(), LinkManagerError> {
114         if let Some(link) = self.get_link(from) {
115             link.ingest_lmp(packet);
116         };
117         Ok(())
118     }
119 
ingest_hci(&self, command: hci::CommandPacket) -> Result<(), LinkManagerError>120     pub fn ingest_hci(&self, command: hci::CommandPacket) -> Result<(), LinkManagerError> {
121         // Try to find the peer address from the command arguments
122         let peer = hci::command_connection_handle(&command)
123             .map(|handle| self.ops.get_address(handle))
124             .or_else(|| hci::command_remote_device_address(&command));
125 
126         if let Some(peer) = peer {
127             if let Some(link) = self.get_link(peer) {
128                 link.ingest_hci(command);
129             };
130             Ok(())
131         } else {
132             Err(LinkManagerError::UnhandledHciPacket)
133         }
134     }
135 
add_link(self: &Rc<Self>, peer: hci::Address) -> Result<(), LinkManagerError>136     pub fn add_link(self: &Rc<Self>, peer: hci::Address) -> Result<(), LinkManagerError> {
137         let index = self.links.iter().position(|link| link.peer.get().is_empty());
138 
139         if let Some(index) = index {
140             self.links[index].peer.set(peer);
141             let context = LinkContext { index: index as u8, manager: Rc::downgrade(self) };
142             self.procedures.borrow_mut()[index] = Some(Box::pin(procedure::run(context)));
143             Ok(())
144         } else {
145             Err(LinkManagerError::UnhandledHciPacket)
146         }
147     }
148 
remove_link(&self, peer: hci::Address) -> Result<(), LinkManagerError>149     pub fn remove_link(&self, peer: hci::Address) -> Result<(), LinkManagerError> {
150         let index = self.links.iter().position(|link| link.peer.get() == peer);
151 
152         if let Some(index) = index {
153             self.links[index].reset();
154             self.procedures.borrow_mut()[index] = None;
155             Ok(())
156         } else {
157             Err(LinkManagerError::UnknownPeer)
158         }
159     }
160 
tick(&self)161     pub fn tick(&self) {
162         let waker = noop_waker();
163 
164         for procedures in self.procedures.borrow_mut().iter_mut().filter_map(Option::as_mut) {
165             let _ = procedures.as_mut().poll(&mut Context::from_waker(&waker));
166         }
167     }
168 
link(&self, idx: u8) -> &Link169     fn link(&self, idx: u8) -> &Link {
170         &self.links[idx as usize]
171     }
172 }
173 
174 struct LinkContext {
175     index: u8,
176     manager: Weak<LinkManager>,
177 }
178 
179 impl procedure::Context for LinkContext {
poll_hci_command<C: TryFrom<hci::CommandPacket>>(&self) -> Poll<C>180     fn poll_hci_command<C: TryFrom<hci::CommandPacket>>(&self) -> Poll<C> {
181         if let Some(manager) = self.manager.upgrade() {
182             manager.link(self.index).poll_hci_command()
183         } else {
184             Poll::Pending
185         }
186     }
187 
poll_lmp_packet<P: TryFrom<lmp::PacketPacket>>(&self) -> Poll<P>188     fn poll_lmp_packet<P: TryFrom<lmp::PacketPacket>>(&self) -> Poll<P> {
189         if let Some(manager) = self.manager.upgrade() {
190             manager.link(self.index).poll_lmp_packet()
191         } else {
192             Poll::Pending
193         }
194     }
195 
send_hci_event<E: Into<hci::EventPacket>>(&self, event: E)196     fn send_hci_event<E: Into<hci::EventPacket>>(&self, event: E) {
197         if let Some(manager) = self.manager.upgrade() {
198             manager.ops.send_hci_event(&event.into().to_vec())
199         }
200     }
201 
send_lmp_packet<P: Into<lmp::PacketPacket>>(&self, packet: P)202     fn send_lmp_packet<P: Into<lmp::PacketPacket>>(&self, packet: P) {
203         if let Some(manager) = self.manager.upgrade() {
204             manager.ops.send_lmp_packet(self.peer_address(), &packet.into().to_vec())
205         }
206     }
207 
peer_address(&self) -> hci::Address208     fn peer_address(&self) -> hci::Address {
209         if let Some(manager) = self.manager.upgrade() {
210             manager.link(self.index).peer.get()
211         } else {
212             hci::EMPTY_ADDRESS
213         }
214     }
215 
peer_handle(&self) -> u16216     fn peer_handle(&self) -> u16 {
217         if let Some(manager) = self.manager.upgrade() {
218             manager.ops.get_handle(self.peer_address())
219         } else {
220             0
221         }
222     }
223 
extended_features(&self, features_page: u8) -> u64224     fn extended_features(&self, features_page: u8) -> u64 {
225         if let Some(manager) = self.manager.upgrade() {
226             manager.ops.extended_features(features_page)
227         } else {
228             0
229         }
230     }
231 }
232