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.3.4
16 
17 use crate::lmp::procedure::Context;
18 use crate::packets::lmp;
19 
initiate(ctx: &impl Context, features_page: u8) -> u6420 pub async fn initiate(ctx: &impl Context, features_page: u8) -> u64 {
21     ctx.send_lmp_packet(
22         lmp::FeaturesReqExtBuilder {
23             transaction_id: 0,
24             features_page,
25             max_supported_page: 1,
26             extended_features: ctx.extended_features(features_page).to_le_bytes(),
27         }
28         .build(),
29     );
30 
31     u64::from_le_bytes(
32         *ctx.receive_lmp_packet::<lmp::FeaturesResExt>().await.get_extended_features(),
33     )
34 }
35 
respond(ctx: &impl Context)36 pub async fn respond(ctx: &impl Context) {
37     let req = ctx.receive_lmp_packet::<lmp::FeaturesReqExt>().await;
38     let features_page = req.get_features_page();
39 
40     ctx.send_lmp_packet(
41         lmp::FeaturesResExtBuilder {
42             transaction_id: 0,
43             features_page,
44             max_supported_page: 1,
45             extended_features: ctx.extended_features(features_page).to_le_bytes(),
46         }
47         .build(),
48     );
49 }
50 
supported_on_both_page(ctx: &impl Context, page_number: u8, feature_mask: u64) -> bool51 async fn supported_on_both_page(ctx: &impl Context, page_number: u8, feature_mask: u64) -> bool {
52     let local_supported = ctx.extended_features(page_number) & feature_mask != 0;
53     // Lazy peer features
54     let peer_supported = async move {
55         let page = if let Some(page) = ctx.peer_extended_features(page_number) {
56             page
57         } else {
58             crate::lmp::procedure::features::initiate(ctx, page_number).await
59         };
60         page & feature_mask != 0
61     };
62     local_supported && peer_supported.await
63 }
64 
supported_on_both_page1( ctx: &impl Context, feature: crate::packets::hci::LMPFeaturesPage1Bits, ) -> bool65 pub async fn supported_on_both_page1(
66     ctx: &impl Context,
67     feature: crate::packets::hci::LMPFeaturesPage1Bits,
68 ) -> bool {
69     supported_on_both_page(ctx, 1, feature.into()).await
70 }
71 
supported_on_both_page2( ctx: &impl Context, feature: crate::packets::hci::LMPFeaturesPage2Bits, ) -> bool72 pub async fn supported_on_both_page2(
73     ctx: &impl Context,
74     feature: crate::packets::hci::LMPFeaturesPage2Bits,
75 ) -> bool {
76     supported_on_both_page(ctx, 2, feature.into()).await
77 }
78