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