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