xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/hci/bredr_connection.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_bluetooth_sapphire/internal/host/hci/bredr_connection.h"
16 
17 #include "pw_bluetooth_sapphire/internal/host/transport/transport.h"
18 
19 namespace bt::hci {
20 
BrEdrConnection(hci_spec::ConnectionHandle handle,const DeviceAddress & local_address,const DeviceAddress & peer_address,pw::bluetooth::emboss::ConnectionRole role,const Transport::WeakPtr & hci)21 BrEdrConnection::BrEdrConnection(hci_spec::ConnectionHandle handle,
22                                  const DeviceAddress& local_address,
23                                  const DeviceAddress& peer_address,
24                                  pw::bluetooth::emboss::ConnectionRole role,
25                                  const Transport::WeakPtr& hci)
26     : AclConnection(handle, local_address, peer_address, role, hci),
27       WeakSelf(this) {
28   PW_CHECK(local_address.type() == DeviceAddress::Type::kBREDR);
29   PW_CHECK(peer_address.type() == DeviceAddress::Type::kBREDR);
30   PW_CHECK(hci.is_alive());
31   PW_CHECK(hci->acl_data_channel());
32 }
33 
StartEncryption()34 bool BrEdrConnection::StartEncryption() {
35   if (state() != Connection::State::kConnected) {
36     bt_log(DEBUG, "hci", "connection closed; cannot start encryption");
37     return false;
38   }
39 
40   PW_CHECK(ltk().has_value() == ltk_type_.has_value());
41   if (!ltk().has_value()) {
42     bt_log(
43         DEBUG,
44         "hci",
45         "connection link key type has not been set; not starting encryption");
46     return false;
47   }
48 
49   auto cmd = CommandPacket::New<
50       pw::bluetooth::emboss::SetConnectionEncryptionCommandWriter>(
51       hci_spec::kSetConnectionEncryption);
52   auto params = cmd.view_t();
53   params.connection_handle().Write(handle());
54   params.encryption_enable().Write(
55       pw::bluetooth::emboss::GenericEnableParam::ENABLE);
56 
57   auto self = GetWeakPtr();
58   auto event_cb = [self, handle = handle()](auto, const EventPacket& event) {
59     if (!self.is_alive()) {
60       return;
61     }
62 
63     Result<> result = event.ToResult();
64     if (bt_is_error(result,
65                     ERROR,
66                     "hci-bredr",
67                     "could not set encryption on link %#.04x",
68                     handle)) {
69       if (self->encryption_change_callback()) {
70         self->encryption_change_callback()(result.take_error());
71       }
72       return;
73     }
74     bt_log(DEBUG, "hci-bredr", "requested encryption start on %#.04x", handle);
75   };
76 
77   if (!hci().is_alive()) {
78     return false;
79   }
80   return hci()->command_channel()->SendCommand(
81       std::move(cmd), std::move(event_cb), hci_spec::kCommandStatusEventCode);
82 }
83 
HandleEncryptionStatus(Result<bool> result,bool key_refreshed)84 void BrEdrConnection::HandleEncryptionStatus(Result<bool> result,
85                                              bool key_refreshed) {
86   bool enabled = result.is_ok() && result.value() && !key_refreshed;
87   if (enabled) {
88     ValidateEncryptionKeySize([self = GetWeakPtr()](Result<> key_valid_status) {
89       if (self.is_alive()) {
90         self->HandleEncryptionStatusValidated(
91             key_valid_status.is_ok() ? Result<bool>(fit::ok(true))
92                                      : key_valid_status.take_error());
93       }
94     });
95     return;
96   }
97   HandleEncryptionStatusValidated(result);
98 }
99 
HandleEncryptionStatusValidated(Result<bool> result)100 void BrEdrConnection::HandleEncryptionStatusValidated(Result<bool> result) {
101   // Core Spec Vol 3, Part C, 5.2.2.1.1 and 5.2.2.2.1 mention disconnecting the
102   // link after pairing failures (supported by TS GAP/SEC/SEM/BV-10-C), but do
103   // not specify actions to take after encryption failures. We'll choose to
104   // disconnect ACL links after encryption failure.
105   if (result.is_error()) {
106     Disconnect(pw::bluetooth::emboss::StatusCode::AUTHENTICATION_FAILURE);
107   }
108 
109   if (!encryption_change_callback()) {
110     bt_log(DEBUG,
111            "hci",
112            "%#.4x: no encryption status callback assigned",
113            handle());
114     return;
115   }
116   encryption_change_callback()(result);
117 }
118 
ValidateEncryptionKeySize(hci::ResultFunction<> key_size_validity_cb)119 void BrEdrConnection::ValidateEncryptionKeySize(
120     hci::ResultFunction<> key_size_validity_cb) {
121   PW_CHECK(state() == Connection::State::kConnected);
122 
123   auto cmd = CommandPacket::New<
124       pw::bluetooth::emboss::ReadEncryptionKeySizeCommandWriter>(
125       hci_spec::kReadEncryptionKeySize);
126   cmd.view_t().connection_handle().Write(handle());
127 
128   auto event_cb = [self = GetWeakPtr(),
129                    valid_cb = std::move(key_size_validity_cb)](
130                       auto, const EventPacket& event) {
131     if (!self.is_alive()) {
132       return;
133     }
134 
135     Result<> result = event.ToResult();
136     if (!bt_is_error(result,
137                      ERROR,
138                      "hci",
139                      "Could not read ACL encryption key size on %#.4x",
140                      self->handle())) {
141       const auto return_params =
142           event.view<pw::bluetooth::emboss::
143                          ReadEncryptionKeySizeCommandCompleteEventView>();
144       uint8_t key_size = return_params.key_size().Read();
145       bt_log(TRACE,
146              "hci",
147              "%#.4x: encryption key size %hhu",
148              self->handle(),
149              key_size);
150 
151       if (key_size < hci_spec::kMinEncryptionKeySize) {
152         bt_log(WARN,
153                "hci",
154                "%#.4x: encryption key size %hhu insufficient",
155                self->handle(),
156                key_size);
157         result = ToResult(HostError::kInsufficientSecurity);
158       }
159     }
160     valid_cb(result);
161   };
162   hci()->command_channel()->SendCommand(std::move(cmd), std::move(event_cb));
163 }
164 
165 }  // namespace bt::hci
166