1 // Bluetooth Core, Vol 2, Part C, 4.2.5
2
3 use super::features;
4 use crate::num_hci_command_packets;
5 use crate::packets::{hci, lmp};
6 use crate::procedure::Context;
7
8 use hci::LMPFeaturesPage1Bits::SecureConnectionsHostSupport;
9 use hci::LMPFeaturesPage2Bits::SecureConnectionsControllerSupport;
10
initiate(ctx: &impl Context)11 pub async fn initiate(ctx: &impl Context) {
12 // TODO: handle turn off
13 let _ = ctx.receive_hci_command::<hci::SetConnectionEncryptionPacket>().await;
14 ctx.send_hci_event(
15 hci::SetConnectionEncryptionStatusBuilder {
16 num_hci_command_packets,
17 status: hci::ErrorCode::Success,
18 }
19 .build(),
20 );
21
22 // TODO: handle failure
23 let _ = ctx
24 .send_accepted_lmp_packet(
25 lmp::EncryptionModeReqBuilder { transaction_id: 0, encryption_mode: 0x1 }.build(),
26 )
27 .await;
28
29 // TODO: handle failure
30 let _ = ctx
31 .send_accepted_lmp_packet(
32 lmp::EncryptionKeySizeReqBuilder { transaction_id: 0, key_size: 16 }.build(),
33 )
34 .await;
35
36 // TODO: handle failure
37 let _ = ctx
38 .send_accepted_lmp_packet(
39 lmp::StartEncryptionReqBuilder { transaction_id: 0, random_number: [0; 16] }.build(),
40 )
41 .await;
42
43 let aes_ccm = features::supported_on_both_page1(ctx, SecureConnectionsHostSupport).await
44 && features::supported_on_both_page2(ctx, SecureConnectionsControllerSupport).await;
45
46 ctx.send_hci_event(
47 hci::EncryptionChangeBuilder {
48 status: hci::ErrorCode::Success,
49 connection_handle: ctx.peer_handle(),
50 encryption_enabled: if aes_ccm {
51 hci::EncryptionEnabled::BrEdrAesCcm
52 } else {
53 hci::EncryptionEnabled::On
54 },
55 }
56 .build(),
57 );
58 }
59
respond(ctx: &impl Context)60 pub async fn respond(ctx: &impl Context) {
61 // TODO: handle
62 let _ = ctx.receive_lmp_packet::<lmp::EncryptionModeReqPacket>().await;
63 ctx.send_lmp_packet(
64 lmp::AcceptedBuilder { transaction_id: 0, accepted_opcode: lmp::Opcode::EncryptionModeReq }
65 .build(),
66 );
67
68 let _ = ctx.receive_lmp_packet::<lmp::EncryptionKeySizeReqPacket>().await;
69 ctx.send_lmp_packet(
70 lmp::AcceptedBuilder {
71 transaction_id: 0,
72 accepted_opcode: lmp::Opcode::EncryptionKeySizeReq,
73 }
74 .build(),
75 );
76
77 let _ = ctx.receive_lmp_packet::<lmp::StartEncryptionReqPacket>().await;
78 ctx.send_lmp_packet(
79 lmp::AcceptedBuilder {
80 transaction_id: 0,
81 accepted_opcode: lmp::Opcode::StartEncryptionReq,
82 }
83 .build(),
84 );
85
86 let aes_ccm = features::supported_on_both_page1(ctx, SecureConnectionsHostSupport).await
87 && features::supported_on_both_page2(ctx, SecureConnectionsControllerSupport).await;
88
89 ctx.send_hci_event(
90 hci::EncryptionChangeBuilder {
91 status: hci::ErrorCode::Success,
92 connection_handle: ctx.peer_handle(),
93 encryption_enabled: if aes_ccm {
94 hci::EncryptionEnabled::BrEdrAesCcm
95 } else {
96 hci::EncryptionEnabled::On
97 },
98 }
99 .build(),
100 );
101 }
102
103 #[cfg(test)]
104 mod tests {
105 use super::initiate;
106 use super::respond;
107 use crate::procedure::Context;
108 use crate::test::{sequence, TestContext};
109
110 use crate::packets::hci::LMPFeaturesPage1Bits::SecureConnectionsHostSupport;
111 use crate::packets::hci::LMPFeaturesPage2Bits::SecureConnectionsControllerSupport;
112
113 #[test]
accept_encryption()114 fn accept_encryption() {
115 let context = TestContext::new();
116 let procedure = respond;
117
118 include!("../../test/ENC/BV-01-C.in");
119 }
120
121 #[test]
initiate_encryption()122 fn initiate_encryption() {
123 let context = TestContext::new();
124 let procedure = initiate;
125
126 include!("../../test/ENC/BV-05-C.in");
127 }
128
129 #[test]
accept_aes_ccm_encryption_request()130 fn accept_aes_ccm_encryption_request() {
131 let context = TestContext::new()
132 .with_page_1_feature(SecureConnectionsHostSupport)
133 .with_page_2_feature(SecureConnectionsControllerSupport)
134 .with_peer_page_1_feature(SecureConnectionsHostSupport)
135 .with_peer_page_2_feature(SecureConnectionsControllerSupport);
136 let procedure = respond;
137
138 include!("../../test/ENC/BV-26-C.in");
139 }
140
141 #[test]
initiate_aes_ccm_encryption()142 fn initiate_aes_ccm_encryption() {
143 let context = TestContext::new()
144 .with_page_1_feature(SecureConnectionsHostSupport)
145 .with_page_2_feature(SecureConnectionsControllerSupport)
146 .with_peer_page_1_feature(SecureConnectionsHostSupport)
147 .with_peer_page_2_feature(SecureConnectionsControllerSupport);
148 let procedure = initiate;
149
150 include!("../../test/ENC/BV-34-C.in");
151 }
152 }
153