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 //! Bluetooth Core, Vol 2, Part C, 4.2.1
16 
17 use crate::either::Either;
18 use crate::lmp::procedure::features;
19 use crate::lmp::procedure::legacy_pairing;
20 use crate::lmp::procedure::secure_simple_pairing;
21 use crate::lmp::procedure::Context;
22 use crate::num_hci_command_packets;
23 use crate::packets::{hci, lmp};
24 
send_challenge( ctx: &impl Context, transaction_id: u8, _link_key: [u8; 16], ) -> Result<(), ()>25 pub async fn send_challenge(
26     ctx: &impl Context,
27     transaction_id: u8,
28     _link_key: [u8; 16],
29 ) -> Result<(), ()> {
30     let random_number = [0; 16];
31     ctx.send_lmp_packet(lmp::AuRandBuilder { transaction_id, random_number }.build());
32 
33     match ctx.receive_lmp_packet::<Either<lmp::Sres, lmp::NotAccepted>>().await {
34         Either::Left(_response) => Ok(()),
35         Either::Right(_) => Err(()),
36     }
37 }
38 
receive_challenge(ctx: &impl Context, _link_key: [u8; 16])39 pub async fn receive_challenge(ctx: &impl Context, _link_key: [u8; 16]) {
40     let _random_number = *ctx.receive_lmp_packet::<lmp::AuRand>().await.get_random_number();
41     ctx.send_lmp_packet(lmp::SresBuilder { transaction_id: 0, authentication_rsp: [0; 4] }.build());
42 }
43 
initiate(ctx: &impl Context)44 pub async fn initiate(ctx: &impl Context) {
45     let _ = ctx.receive_hci_command::<hci::AuthenticationRequested>().await;
46     ctx.send_hci_event(
47         hci::AuthenticationRequestedStatusBuilder {
48             num_hci_command_packets,
49             status: hci::ErrorCode::Success,
50         }
51         .build(),
52     );
53 
54     ctx.send_hci_event(hci::LinkKeyRequestBuilder { bd_addr: ctx.peer_address() }.build());
55 
56     let status = match ctx
57         .receive_hci_command::<Either<hci::LinkKeyRequestReply, hci::LinkKeyRequestNegativeReply>>()
58         .await
59     {
60         Either::Left(_reply) => {
61             ctx.send_hci_event(
62                 hci::LinkKeyRequestReplyCompleteBuilder {
63                     num_hci_command_packets,
64                     status: hci::ErrorCode::Success,
65                     bd_addr: ctx.peer_address(),
66                 }
67                 .build(),
68             );
69             hci::ErrorCode::Success
70         }
71         Either::Right(_) => {
72             ctx.send_hci_event(
73                 hci::LinkKeyRequestNegativeReplyCompleteBuilder {
74                     num_hci_command_packets,
75                     status: hci::ErrorCode::Success,
76                     bd_addr: ctx.peer_address(),
77                 }
78                 .build(),
79             );
80 
81             let result = if features::supported_on_both_page1(
82                 ctx,
83                 hci::LMPFeaturesPage1Bits::SecureSimplePairingHostSupport,
84             )
85             .await
86             {
87                 secure_simple_pairing::initiate(ctx).await
88             } else {
89                 legacy_pairing::initiate(ctx).await
90             };
91 
92             match result {
93                 Ok(_) => hci::ErrorCode::Success,
94                 Err(_) => hci::ErrorCode::AuthenticationFailure,
95             }
96         }
97     };
98 
99     ctx.send_hci_event(
100         hci::AuthenticationCompleteBuilder { status, connection_handle: ctx.peer_handle() }.build(),
101     );
102 }
103 
respond(ctx: &impl Context)104 pub async fn respond(ctx: &impl Context) {
105     match ctx
106         .receive_lmp_packet::<Either<lmp::AuRand, Either<lmp::IoCapabilityReq, lmp::InRand>>>()
107         .await
108     {
109         Either::Left(_random_number) => {
110             // TODO: Resolve authentication challenge
111             // TODO: Ask for link key
112             ctx.send_lmp_packet(
113                 lmp::SresBuilder { transaction_id: 0, authentication_rsp: [0; 4] }.build(),
114             );
115         }
116         Either::Right(pairing) => {
117             let _result = match pairing {
118                 Either::Left(io_capability_request) => {
119                     secure_simple_pairing::respond(ctx, io_capability_request).await
120                 }
121                 Either::Right(in_rand) => legacy_pairing::respond(ctx, in_rand).await,
122             };
123         }
124     }
125 }
126