1 // Copyright 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use std::convert::TryFrom;
16 use std::future::Future;
17 use std::pin::Pin;
18 use std::task::{self, Poll};
19 
20 use crate::lmp::ec::PrivateKey;
21 use crate::packets::{hci, lmp};
22 
23 pub trait Context {
poll_hci_command<C: TryFrom<hci::Command>>(&self) -> Poll<C>24     fn poll_hci_command<C: TryFrom<hci::Command>>(&self) -> Poll<C>;
poll_lmp_packet<P: TryFrom<lmp::LmpPacket>>(&self) -> Poll<P>25     fn poll_lmp_packet<P: TryFrom<lmp::LmpPacket>>(&self) -> Poll<P>;
26 
send_hci_event<E: Into<hci::Event>>(&self, event: E)27     fn send_hci_event<E: Into<hci::Event>>(&self, event: E);
send_lmp_packet<P: Into<lmp::LmpPacket>>(&self, packet: P)28     fn send_lmp_packet<P: Into<lmp::LmpPacket>>(&self, packet: P);
29 
peer_address(&self) -> hci::Address30     fn peer_address(&self) -> hci::Address;
peer_handle(&self) -> u1631     fn peer_handle(&self) -> u16;
32 
peer_extended_features(&self, _features_page: u8) -> Option<u64>33     fn peer_extended_features(&self, _features_page: u8) -> Option<u64> {
34         None
35     }
36 
extended_features(&self, features_page: u8) -> u6437     fn extended_features(&self, features_page: u8) -> u64;
38 
receive_hci_command<C: TryFrom<hci::Command>>(&self) -> ReceiveFuture<'_, Self, C>39     fn receive_hci_command<C: TryFrom<hci::Command>>(&self) -> ReceiveFuture<'_, Self, C> {
40         ReceiveFuture(Self::poll_hci_command, self)
41     }
42 
receive_lmp_packet<P: TryFrom<lmp::LmpPacket>>(&self) -> ReceiveFuture<'_, Self, P>43     fn receive_lmp_packet<P: TryFrom<lmp::LmpPacket>>(&self) -> ReceiveFuture<'_, Self, P> {
44         ReceiveFuture(Self::poll_lmp_packet, self)
45     }
46 
send_accepted_lmp_packet<P: Into<lmp::LmpPacket>>( &self, packet: P, ) -> SendAcceptedLmpPacketFuture<'_, Self>47     fn send_accepted_lmp_packet<P: Into<lmp::LmpPacket>>(
48         &self,
49         packet: P,
50     ) -> SendAcceptedLmpPacketFuture<'_, Self> {
51         let packet = packet.into();
52         let opcode = packet.get_opcode();
53         self.send_lmp_packet(packet);
54 
55         SendAcceptedLmpPacketFuture(self, opcode)
56     }
57 
58     #[allow(dead_code)]
get_private_key(&self) -> Option<PrivateKey>59     fn get_private_key(&self) -> Option<PrivateKey> {
60         None
61     }
62 
set_private_key(&self, _key: &PrivateKey)63     fn set_private_key(&self, _key: &PrivateKey) {}
64 }
65 
66 /// Future for Context::receive_hci_command and Context::receive_lmp_packet
67 pub struct ReceiveFuture<'a, C: ?Sized, P>(fn(&'a C) -> Poll<P>, &'a C);
68 
69 impl<'a, C, O> Future for ReceiveFuture<'a, C, O>
70 where
71     C: Context,
72 {
73     type Output = O;
74 
poll(self: Pin<&mut Self>, _cx: &mut task::Context<'_>) -> Poll<Self::Output>75     fn poll(self: Pin<&mut Self>, _cx: &mut task::Context<'_>) -> Poll<Self::Output> {
76         (self.0)(self.1)
77     }
78 }
79 
80 /// Future for Context::receive_hci_command and Context::receive_lmp_packet
81 pub struct SendAcceptedLmpPacketFuture<'a, C: ?Sized>(&'a C, lmp::Opcode);
82 
83 impl<'a, C> Future for SendAcceptedLmpPacketFuture<'a, C>
84 where
85     C: Context,
86 {
87     type Output = Result<(), u8>;
88 
poll(self: Pin<&mut Self>, _cx: &mut task::Context<'_>) -> Poll<Self::Output>89     fn poll(self: Pin<&mut Self>, _cx: &mut task::Context<'_>) -> Poll<Self::Output> {
90         let accepted = self.0.poll_lmp_packet::<lmp::Accepted>();
91         if let Poll::Ready(accepted) = accepted {
92             if accepted.get_accepted_opcode() == self.1 {
93                 return Poll::Ready(Ok(()));
94             }
95         }
96 
97         let not_accepted = self.0.poll_lmp_packet::<lmp::NotAccepted>();
98         if let Poll::Ready(not_accepted) = not_accepted {
99             if not_accepted.get_not_accepted_opcode() == self.1 {
100                 return Poll::Ready(Err(not_accepted.get_error_code()));
101             }
102         }
103 
104         Poll::Pending
105     }
106 }
107 
108 pub mod authentication;
109 mod encryption;
110 pub mod features;
111 pub mod legacy_pairing;
112 pub mod secure_simple_pairing;
113 
114 macro_rules! run_procedures {
115     ($(
116         $idx:tt { $procedure:expr }
117     )+) => {{
118         $(
119             let $idx = async { loop { $procedure.await; } };
120             crate::future::pin!($idx);
121         )+
122 
123         use std::future::Future;
124         use std::pin::Pin;
125         use std::task::{Poll, Context};
126 
127         #[allow(non_camel_case_types)]
128         struct Join<'a, $($idx),+> {
129             $($idx: Pin<&'a mut $idx>),+
130         }
131 
132         #[allow(non_camel_case_types)]
133         impl<'a, $($idx: Future<Output = ()>),+> Future for Join<'a, $($idx),+> {
134             type Output = ();
135 
136             fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
137                 $(assert!(self.$idx.as_mut().poll(cx).is_pending());)+
138                 Poll::Pending
139             }
140         }
141 
142         Join {
143             $($idx),+
144         }.await
145     }}
146 }
147 
run(ctx: impl Context)148 pub async fn run(ctx: impl Context) {
149     run_procedures! {
150         a { authentication::initiate(&ctx) }
151         b { authentication::respond(&ctx) }
152         c { encryption::initiate(&ctx) }
153         d { encryption::respond(&ctx) }
154         e { features::respond(&ctx) }
155     }
156 }
157