• 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::lmp::procedure;
14 use crate::num_hci_command_packets;
15 use crate::packets::{hci, lmp};
16 
17 use hci::Packet as _;
18 use lmp::Packet as _;
19 
20 struct Link {
21     peer: Cell<hci::Address>,
22     // Only store one HCI packet as our Num_HCI_Command_Packets
23     // is always 1
24     hci: Cell<Option<hci::CommandPacket>>,
25     lmp: RefCell<VecDeque<lmp::LmpPacket>>,
26 }
27 
28 impl Default for Link {
default() -> Self29     fn default() -> Self {
30         Link {
31             peer: Cell::new(hci::EMPTY_ADDRESS),
32             hci: Default::default(),
33             lmp: Default::default(),
34         }
35     }
36 }
37 
38 impl Link {
ingest_lmp(&self, packet: lmp::LmpPacket)39     fn ingest_lmp(&self, packet: lmp::LmpPacket) {
40         self.lmp.borrow_mut().push_back(packet);
41     }
42 
ingest_hci(&self, command: hci::CommandPacket)43     fn ingest_hci(&self, command: hci::CommandPacket) {
44         assert!(self.hci.replace(Some(command)).is_none(), "HCI flow control violation");
45     }
46 
poll_hci_command<C: TryFrom<hci::CommandPacket>>(&self) -> Poll<C>47     fn poll_hci_command<C: TryFrom<hci::CommandPacket>>(&self) -> Poll<C> {
48         let command = self.hci.take();
49 
50         if let Some(command) = command.clone().and_then(|c| c.try_into().ok()) {
51             Poll::Ready(command)
52         } else {
53             self.hci.set(command);
54             Poll::Pending
55         }
56     }
57 
poll_lmp_packet<P: TryFrom<lmp::LmpPacket>>(&self) -> Poll<P>58     fn poll_lmp_packet<P: TryFrom<lmp::LmpPacket>>(&self) -> Poll<P> {
59         let mut queue = self.lmp.borrow_mut();
60         let packet = queue.front().and_then(|packet| packet.clone().try_into().ok());
61 
62         if let Some(packet) = packet {
63             queue.pop_front();
64             Poll::Ready(packet)
65         } else {
66             Poll::Pending
67         }
68     }
69 
reset(&self)70     fn reset(&self) {
71         self.peer.set(hci::EMPTY_ADDRESS);
72         self.hci.set(None);
73         self.lmp.borrow_mut().clear();
74     }
75 }
76 
77 #[derive(Error, Debug)]
78 pub enum LinkManagerError {
79     #[error("Unknown peer")]
80     UnknownPeer,
81     #[error("Unhandled HCI packet")]
82     UnhandledHciPacket,
83     #[error("Maximum number of links reached")]
84     MaxNumberOfLink,
85 }
86 
87 /// Max number of Bluetooth Peers
88 pub const MAX_PEER_NUMBER: usize = 7;
89 
90 pub struct LinkManager {
91     ops: LinkManagerOps,
92     links: [Link; MAX_PEER_NUMBER],
93     procedures: RefCell<[Option<Pin<Box<dyn Future<Output = ()>>>>; MAX_PEER_NUMBER]>,
94 }
95 
96 impl LinkManager {
new(ops: LinkManagerOps) -> Self97     pub fn new(ops: LinkManagerOps) -> Self {
98         Self { ops, links: Default::default(), procedures: Default::default() }
99     }
100 
get_link(&self, peer: hci::Address) -> Option<&Link>101     fn get_link(&self, peer: hci::Address) -> Option<&Link> {
102         self.links.iter().find(|link| link.peer.get() == peer)
103     }
104 
ingest_lmp( &self, from: hci::Address, packet: lmp::LmpPacket, ) -> Result<(), LinkManagerError>105     pub fn ingest_lmp(
106         &self,
107         from: hci::Address,
108         packet: lmp::LmpPacket,
109     ) -> Result<(), LinkManagerError> {
110         if let Some(link) = self.get_link(from) {
111             link.ingest_lmp(packet);
112         };
113         Ok(())
114     }
115 
116     /// Send a command complete or command status event
117     /// with the specified error code.
send_command_complete_event( &self, command: &hci::CommandPacket, status: hci::ErrorCode, ) -> Result<(), LinkManagerError>118     fn send_command_complete_event(
119         &self,
120         command: &hci::CommandPacket,
121         status: hci::ErrorCode,
122     ) -> Result<(), LinkManagerError> {
123         use hci::CommandChild::*;
124         #[allow(unused_imports)]
125         use Option::None; // Overwrite `None` variant of `Child` enum
126 
127         let event: hci::EventPacket = match command.specialize() {
128             LinkKeyRequestReply(packet) => hci::LinkKeyRequestReplyCompleteBuilder {
129                 status,
130                 bd_addr: packet.get_bd_addr(),
131                 num_hci_command_packets,
132             }
133             .into(),
134             LinkKeyRequestNegativeReply(packet) => {
135                 hci::LinkKeyRequestNegativeReplyCompleteBuilder {
136                     status,
137                     bd_addr: packet.get_bd_addr(),
138                     num_hci_command_packets,
139                 }
140                 .into()
141             }
142             PinCodeRequestReply(packet) => hci::PinCodeRequestReplyCompleteBuilder {
143                 status,
144                 bd_addr: packet.get_bd_addr(),
145                 num_hci_command_packets,
146             }
147             .into(),
148             PinCodeRequestNegativeReply(packet) => {
149                 hci::PinCodeRequestNegativeReplyCompleteBuilder {
150                     status,
151                     bd_addr: packet.get_bd_addr(),
152                     num_hci_command_packets,
153                 }
154                 .into()
155             }
156             IoCapabilityRequestReply(packet) => hci::IoCapabilityRequestReplyCompleteBuilder {
157                 status,
158                 bd_addr: packet.get_bd_addr(),
159                 num_hci_command_packets,
160             }
161             .into(),
162             IoCapabilityRequestNegativeReply(packet) => {
163                 hci::IoCapabilityRequestNegativeReplyCompleteBuilder {
164                     status,
165                     bd_addr: packet.get_bd_addr(),
166                     num_hci_command_packets,
167                 }
168                 .into()
169             }
170             UserConfirmationRequestReply(packet) => {
171                 hci::UserConfirmationRequestReplyCompleteBuilder {
172                     status,
173                     bd_addr: packet.get_bd_addr(),
174                     num_hci_command_packets,
175                 }
176                 .into()
177             }
178             UserConfirmationRequestNegativeReply(packet) => {
179                 hci::UserConfirmationRequestNegativeReplyCompleteBuilder {
180                     status,
181                     bd_addr: packet.get_bd_addr(),
182                     num_hci_command_packets,
183                 }
184                 .into()
185             }
186             UserPasskeyRequestReply(packet) => hci::UserPasskeyRequestReplyCompleteBuilder {
187                 status,
188                 bd_addr: packet.get_bd_addr(),
189                 num_hci_command_packets,
190             }
191             .into(),
192             UserPasskeyRequestNegativeReply(packet) => {
193                 hci::UserPasskeyRequestNegativeReplyCompleteBuilder {
194                     status,
195                     bd_addr: packet.get_bd_addr(),
196                     num_hci_command_packets,
197                 }
198                 .into()
199             }
200             RemoteOobDataRequestReply(packet) => hci::RemoteOobDataRequestReplyCompleteBuilder {
201                 status,
202                 bd_addr: packet.get_bd_addr(),
203                 num_hci_command_packets,
204             }
205             .into(),
206             RemoteOobDataRequestNegativeReply(packet) => {
207                 hci::RemoteOobDataRequestNegativeReplyCompleteBuilder {
208                     status,
209                     bd_addr: packet.get_bd_addr(),
210                     num_hci_command_packets,
211                 }
212                 .into()
213             }
214             SendKeypressNotification(packet) => hci::SendKeypressNotificationCompleteBuilder {
215                 status,
216                 bd_addr: packet.get_bd_addr(),
217                 num_hci_command_packets,
218             }
219             .into(),
220             AuthenticationRequested(_) => {
221                 hci::AuthenticationRequestedStatusBuilder { status, num_hci_command_packets }.into()
222             }
223             SetConnectionEncryption(_) => {
224                 hci::SetConnectionEncryptionStatusBuilder { status, num_hci_command_packets }.into()
225             }
226             _ => return Err(LinkManagerError::UnhandledHciPacket),
227         };
228         self.ops.send_hci_event(&event.to_vec());
229         Ok(())
230     }
231 
ingest_hci(&self, command: hci::CommandPacket) -> Result<(), LinkManagerError>232     pub fn ingest_hci(&self, command: hci::CommandPacket) -> Result<(), LinkManagerError> {
233         // Try to find the matching link from the command arguments
234         let link = hci::command_connection_handle(&command)
235             .and_then(|handle| self.ops.get_address(handle))
236             .or_else(|| hci::command_remote_device_address(&command))
237             .and_then(|peer| self.get_link(peer));
238 
239         if let Some(link) = link {
240             link.ingest_hci(command);
241             Ok(())
242         } else {
243             self.send_command_complete_event(&command, hci::ErrorCode::InvalidHciCommandParameters)
244         }
245     }
246 
add_link(self: &Rc<Self>, peer: hci::Address) -> Result<(), LinkManagerError>247     pub fn add_link(self: &Rc<Self>, peer: hci::Address) -> Result<(), LinkManagerError> {
248         let index = self.links.iter().position(|link| link.peer.get().is_empty());
249 
250         if let Some(index) = index {
251             self.links[index].peer.set(peer);
252             let context = LinkContext { index: index as u8, manager: Rc::downgrade(self) };
253             self.procedures.borrow_mut()[index] = Some(Box::pin(procedure::run(context)));
254             Ok(())
255         } else {
256             Err(LinkManagerError::UnhandledHciPacket)
257         }
258     }
259 
remove_link(&self, peer: hci::Address) -> Result<(), LinkManagerError>260     pub fn remove_link(&self, peer: hci::Address) -> Result<(), LinkManagerError> {
261         let index = self.links.iter().position(|link| link.peer.get() == peer);
262 
263         if let Some(index) = index {
264             self.links[index].reset();
265             self.procedures.borrow_mut()[index] = None;
266             Ok(())
267         } else {
268             Err(LinkManagerError::UnknownPeer)
269         }
270     }
271 
tick(&self)272     pub fn tick(&self) {
273         let waker = noop_waker();
274 
275         for procedures in self.procedures.borrow_mut().iter_mut().filter_map(Option::as_mut) {
276             let _ = procedures.as_mut().poll(&mut Context::from_waker(&waker));
277         }
278     }
279 
link(&self, idx: u8) -> &Link280     fn link(&self, idx: u8) -> &Link {
281         &self.links[idx as usize]
282     }
283 }
284 
285 struct LinkContext {
286     index: u8,
287     manager: Weak<LinkManager>,
288 }
289 
290 impl procedure::Context for LinkContext {
poll_hci_command<C: TryFrom<hci::CommandPacket>>(&self) -> Poll<C>291     fn poll_hci_command<C: TryFrom<hci::CommandPacket>>(&self) -> Poll<C> {
292         if let Some(manager) = self.manager.upgrade() {
293             manager.link(self.index).poll_hci_command()
294         } else {
295             Poll::Pending
296         }
297     }
298 
poll_lmp_packet<P: TryFrom<lmp::LmpPacket>>(&self) -> Poll<P>299     fn poll_lmp_packet<P: TryFrom<lmp::LmpPacket>>(&self) -> Poll<P> {
300         if let Some(manager) = self.manager.upgrade() {
301             manager.link(self.index).poll_lmp_packet()
302         } else {
303             Poll::Pending
304         }
305     }
306 
send_hci_event<E: Into<hci::EventPacket>>(&self, event: E)307     fn send_hci_event<E: Into<hci::EventPacket>>(&self, event: E) {
308         if let Some(manager) = self.manager.upgrade() {
309             manager.ops.send_hci_event(&event.into().to_vec())
310         }
311     }
312 
send_lmp_packet<P: Into<lmp::LmpPacket>>(&self, packet: P)313     fn send_lmp_packet<P: Into<lmp::LmpPacket>>(&self, packet: P) {
314         if let Some(manager) = self.manager.upgrade() {
315             manager.ops.send_lmp_packet(self.peer_address(), &packet.into().to_vec())
316         }
317     }
318 
peer_address(&self) -> hci::Address319     fn peer_address(&self) -> hci::Address {
320         if let Some(manager) = self.manager.upgrade() {
321             manager.link(self.index).peer.get()
322         } else {
323             hci::EMPTY_ADDRESS
324         }
325     }
326 
peer_handle(&self) -> u16327     fn peer_handle(&self) -> u16 {
328         if let Some(manager) = self.manager.upgrade() {
329             manager.ops.get_handle(self.peer_address())
330         } else {
331             0
332         }
333     }
334 
extended_features(&self, features_page: u8) -> u64335     fn extended_features(&self, features_page: u8) -> u64 {
336         if let Some(manager) = self.manager.upgrade() {
337             manager.ops.extended_features(features_page)
338         } else {
339             0
340         }
341     }
342 }
343