xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/hci/acl_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/acl_connection.h"
16 
17 #include "pw_bluetooth_sapphire/internal/host/transport/transport.h"
18 
19 namespace bt::hci {
20 
21 namespace {
22 
23 template <CommandChannel::EventCallbackResult (
24     AclConnection::*EventHandlerMethod)(const EventPacket&)>
BindEventHandler(const WeakPtr<AclConnection> & conn)25 CommandChannel::EventCallback BindEventHandler(
26     const WeakPtr<AclConnection>& conn) {
27   return [conn](const EventPacket& event) {
28     if (conn.is_alive()) {
29       return (conn.get().*EventHandlerMethod)(event);
30     }
31     return CommandChannel::EventCallbackResult::kRemove;
32   };
33 }
34 
35 }  // namespace
36 
AclConnection(hci_spec::ConnectionHandle handle,const DeviceAddress & local_address,const DeviceAddress & peer_address,pw::bluetooth::emboss::ConnectionRole role,const Transport::WeakPtr & hci)37 AclConnection::AclConnection(hci_spec::ConnectionHandle handle,
38                              const DeviceAddress& local_address,
39                              const DeviceAddress& peer_address,
40                              pw::bluetooth::emboss::ConnectionRole role,
41                              const Transport::WeakPtr& hci)
42     : Connection(handle,
43                  local_address,
44                  peer_address,
45                  hci,
46                  [handle, hci] {
47                    AclConnection::OnDisconnectionComplete(handle, hci);
48                  }),
49       role_(role),
50       weak_self_(this) {
51   auto self = weak_self_.GetWeakPtr();
52   enc_change_id_ = hci->command_channel()->AddEventHandler(
53       hci_spec::kEncryptionChangeEventCode,
54       BindEventHandler<&AclConnection::OnEncryptionChangeEvent>(self));
55   enc_key_refresh_cmpl_id_ = hci->command_channel()->AddEventHandler(
56       hci_spec::kEncryptionKeyRefreshCompleteEventCode,
57       BindEventHandler<&AclConnection::OnEncryptionKeyRefreshCompleteEvent>(
58           self));
59 }
60 
~AclConnection()61 AclConnection::~AclConnection() {
62   // Unregister HCI event handlers.
63   hci()->command_channel()->RemoveEventHandler(enc_change_id_);
64   hci()->command_channel()->RemoveEventHandler(enc_key_refresh_cmpl_id_);
65 }
66 
OnDisconnectionComplete(hci_spec::ConnectionHandle handle,const Transport::WeakPtr & hci)67 void AclConnection::OnDisconnectionComplete(hci_spec::ConnectionHandle handle,
68                                             const Transport::WeakPtr& hci) {
69   if (!hci.is_alive()) {
70     return;
71   }
72   // Notify ACL data channel that packets have been flushed from controller
73   // buffer.
74   hci->acl_data_channel()->ClearControllerPacketCount(handle);
75 }
76 
OnEncryptionChangeEvent(const EventPacket & event)77 CommandChannel::EventCallbackResult AclConnection::OnEncryptionChangeEvent(
78     const EventPacket& event) {
79   PW_CHECK(event.event_code() == hci_spec::kEncryptionChangeEventCode);
80 
81   auto params =
82       event
83           .unchecked_view<pw::bluetooth::emboss::EncryptionChangeEventV1View>();
84   if (!params.Ok()) {
85     bt_log(WARN, "hci", "malformed encryption change event");
86     return CommandChannel::EventCallbackResult::kContinue;
87   }
88 
89   hci_spec::ConnectionHandle handle = params.connection_handle().Read();
90 
91   // Silently ignore the event as it isn't meant for this connection.
92   if (handle != this->handle()) {
93     return CommandChannel::EventCallbackResult::kContinue;
94   }
95 
96   if (state() != Connection::State::kConnected) {
97     bt_log(DEBUG, "hci", "encryption change ignored for closed connection");
98     return CommandChannel::EventCallbackResult::kContinue;
99   }
100 
101   Result<> result = event.ToResult();
102   encryption_status_ = params.encryption_enabled().Read();
103   bool encryption_enabled =
104       encryption_status_ != pw::bluetooth::emboss::EncryptionStatus::OFF;
105 
106   bt_log(DEBUG,
107          "hci",
108          "encryption change (%s) %s",
109          encryption_enabled ? "enabled" : "disabled",
110          bt_str(result));
111 
112   // If peer and local Secure Connections support are present, the pairing logic
113   // needs to verify that the status received in the Encryption Changed event is
114   // for AES encryption.
115   if (use_secure_connections_ &&
116       encryption_status_ !=
117           pw::bluetooth::emboss::EncryptionStatus::ON_WITH_AES_FOR_BREDR) {
118     bt_log(DEBUG,
119            "hci",
120            "BR/EDR Secure Connection must use AES encryption. Closing "
121            "connection...");
122     HandleEncryptionStatus(fit::error(Error(HostError::kInsufficientSecurity)),
123                            /*key_refreshed=*/false);
124     return CommandChannel::EventCallbackResult::kContinue;
125   }
126 
127   HandleEncryptionStatus(result.is_ok()
128                              ? Result<bool>(fit::ok(encryption_enabled))
129                              : result.take_error(),
130                          /*key_refreshed=*/false);
131   return CommandChannel::EventCallbackResult::kContinue;
132 }
133 
134 CommandChannel::EventCallbackResult
OnEncryptionKeyRefreshCompleteEvent(const EventPacket & event)135 AclConnection::OnEncryptionKeyRefreshCompleteEvent(const EventPacket& event) {
136   const auto params =
137       event
138           .view<pw::bluetooth::emboss::EncryptionKeyRefreshCompleteEventView>();
139   const hci_spec::ConnectionHandle handle = params.connection_handle().Read();
140 
141   // Silently ignore this event as it isn't meant for this connection.
142   if (handle != this->handle()) {
143     return CommandChannel::EventCallbackResult::kContinue;
144   }
145 
146   if (state() != Connection::State::kConnected) {
147     bt_log(
148         DEBUG, "hci", "encryption key refresh ignored for closed connection");
149     return CommandChannel::EventCallbackResult::kContinue;
150   }
151 
152   Result<> status = event.ToResult();
153   bt_log(DEBUG, "hci", "encryption key refresh %s", bt_str(status));
154 
155   // Report that encryption got disabled on failure status. The accuracy of this
156   // isn't that important since the link will be disconnected.
157   HandleEncryptionStatus(status.is_ok()
158                              ? Result<bool>(fit::ok(/*enabled=*/true))
159                              : status.take_error(),
160                          /*key_refreshed=*/true);
161 
162   return CommandChannel::EventCallbackResult::kContinue;
163 }
164 
165 }  // namespace bt::hci
166