• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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