1 // Bluetooth Core, Vol 2, Part C, 4.2.1
2
3 use crate::either::Either;
4 use crate::num_hci_command_packets;
5 use crate::packets::{hci, lmp};
6 use crate::procedure::features;
7 use crate::procedure::legacy_pairing;
8 use crate::procedure::secure_simple_pairing;
9 use crate::procedure::Context;
10
send_challenge( ctx: &impl Context, transaction_id: u8, _link_key: [u8; 16], ) -> Result<(), ()>11 pub async fn send_challenge(
12 ctx: &impl Context,
13 transaction_id: u8,
14 _link_key: [u8; 16],
15 ) -> Result<(), ()> {
16 let random_number = [0; 16];
17 ctx.send_lmp_packet(lmp::AuRandBuilder { transaction_id, random_number }.build());
18
19 match ctx.receive_lmp_packet::<Either<lmp::SresPacket, lmp::NotAcceptedPacket>>().await {
20 Either::Left(_response) => Ok(()),
21 Either::Right(_) => Err(()),
22 }
23 }
24
receive_challenge(ctx: &impl Context, _link_key: [u8; 16])25 pub async fn receive_challenge(ctx: &impl Context, _link_key: [u8; 16]) {
26 let _random_number = *ctx.receive_lmp_packet::<lmp::AuRandPacket>().await.get_random_number();
27 ctx.send_lmp_packet(lmp::SresBuilder { transaction_id: 0, authentication_rsp: [0; 4] }.build());
28 }
29
initiate(ctx: &impl Context)30 pub async fn initiate(ctx: &impl Context) {
31 let _ = ctx.receive_hci_command::<hci::AuthenticationRequestedPacket>().await;
32 ctx.send_hci_event(
33 hci::AuthenticationRequestedStatusBuilder {
34 num_hci_command_packets,
35 status: hci::ErrorCode::Success,
36 }
37 .build(),
38 );
39
40 ctx.send_hci_event(hci::LinkKeyRequestBuilder { bd_addr: ctx.peer_address() }.build());
41
42 let status = match ctx.receive_hci_command::<Either<
43 hci::LinkKeyRequestReplyPacket,
44 hci::LinkKeyRequestNegativeReplyPacket,
45 >>().await {
46 Either::Left(_reply) => {
47 ctx.send_hci_event(
48 hci::LinkKeyRequestReplyCompleteBuilder {
49 num_hci_command_packets,
50 status: hci::ErrorCode::Success,
51 bd_addr: ctx.peer_address(),
52 }
53 .build(),
54 );
55 hci::ErrorCode::Success
56 },
57 Either::Right(_) => {
58 ctx.send_hci_event(
59 hci::LinkKeyRequestNegativeReplyCompleteBuilder {
60 num_hci_command_packets,
61 status: hci::ErrorCode::Success,
62 bd_addr: ctx.peer_address(),
63 }
64 .build(),
65 );
66
67 let result = if features::supported_on_both_page1(ctx, hci::LMPFeaturesPage1Bits::SecureSimplePairingHostSupport).await {
68 secure_simple_pairing::initiate(ctx).await
69 } else {
70 legacy_pairing::initiate(ctx).await
71 };
72
73 match result {
74 Ok(_) => hci::ErrorCode::Success,
75 Err(_) => hci::ErrorCode::AuthenticationFailure
76 }
77 }
78 };
79
80 ctx.send_hci_event(
81 hci::AuthenticationCompleteBuilder { status, connection_handle: ctx.peer_handle() }.build(),
82 );
83 }
84
respond(ctx: &impl Context)85 pub async fn respond(ctx: &impl Context) {
86 match ctx.receive_lmp_packet::<Either<
87 lmp::AuRandPacket,
88 Either<lmp::IoCapabilityReqPacket, lmp::InRandPacket>
89 >>()
90 .await
91 {
92 Either::Left(_random_number) => {
93 // TODO: Resolve authentication challenge
94 // TODO: Ask for link key
95 ctx.send_lmp_packet(lmp::SresBuilder { transaction_id: 0, authentication_rsp: [0; 4] }.build());
96 },
97 Either::Right(pairing) => {
98 let _result = match pairing {
99 Either::Left(io_capability_request) =>
100 secure_simple_pairing::respond(ctx, io_capability_request).await,
101 Either::Right(in_rand) =>
102 legacy_pairing::respond(ctx, in_rand).await,
103 };
104 }
105 }
106 }
107