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