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 #pragma once 16 #include <lib/fit/function.h> 17 #include <pw_async/dispatcher.h> 18 19 #include <map> 20 #include <memory> 21 #include <unordered_map> 22 23 #include "pw_bluetooth_sapphire/internal/host/att/att.h" 24 #include "pw_bluetooth_sapphire/internal/host/att/error.h" 25 #include "pw_bluetooth_sapphire/internal/host/att/packet.h" 26 #include "pw_bluetooth_sapphire/internal/host/common/assert.h" 27 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h" 28 #include "pw_bluetooth_sapphire/internal/host/common/macros.h" 29 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h" 30 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel.h" 31 #include "pw_bluetooth_sapphire/internal/host/l2cap/scoped_channel.h" 32 33 namespace bt::att { 34 35 // Implements an ATT data bearer with the following features: 36 // 37 // * This can be used over either a LE-U or an ACL-U logical link. No 38 // assumptions are made on the logical transport of the underlying L2CAP 39 // channel. 40 // * Can simultaneously operate in both server and client roles of the 41 // protocol. 42 // 43 // Deleting a Bearer closes the underlying channel. Unlike ShutDown(), this 44 // does NOT notify any callbacks to prevent them from running in destructors. 45 // 46 // THREAD-SAFETY: 47 // 48 // This class is intended to be created, accessed, and destroyed on the same 49 // thread. All callbacks will be invoked on a Bearer's creation thread. 50 class Bearer final { 51 public: 52 // Creates a new ATT Bearer. Returns nullptr if |chan| cannot be activated. 53 // This can happen if the link is closed. 54 static std::unique_ptr<Bearer> Create(l2cap::Channel::WeakPtr chan, 55 pw::async::Dispatcher& dispatcher); 56 57 ~Bearer(); 58 59 // Returns true if the underlying channel is open. is_open()60 bool is_open() const { return static_cast<bool>(chan_); } 61 62 // The bi-directional (client + server) MTU currently in use. The default 63 // value is kLEMinMTU. 64 // 65 // NOTE: This is allowed to be initialized to something smaller than kLEMinMTU 66 // for unit tests. mtu()67 uint16_t mtu() const { return mtu_; } set_mtu(uint16_t value)68 void set_mtu(uint16_t value) { 69 bt_log(DEBUG, "att", "bearer: new MTU %u", value); 70 mtu_ = value; 71 } 72 73 // The preferred MTU. This is initially assigned based on the MTU of the 74 // underlying L2CAP channel and will be used in future MTU Exchange 75 // procedures. preferred_mtu()76 uint16_t preferred_mtu() const { return preferred_mtu_; } set_preferred_mtu(uint16_t value)77 void set_preferred_mtu(uint16_t value) { 78 PW_DCHECK(value >= kLEMinMTU); 79 preferred_mtu_ = value; 80 } 81 82 // Returns the correct minimum ATT_MTU based on the underlying link type. min_mtu()83 uint16_t min_mtu() const { return min_mtu_; } 84 85 // Returns the current link security properties. security()86 sm::SecurityProperties security() const { 87 return chan_ ? chan_->security() : sm::SecurityProperties(); 88 } 89 90 // Sets a callback to be invoked invoked when the underlying channel has 91 // closed. |callback| should disconnect the underlying logical link. set_closed_callback(fit::closure callback)92 void set_closed_callback(fit::closure callback) { 93 closed_cb_ = std::move(callback); 94 } 95 96 // Closes the channel. This should be called when a protocol transaction 97 // warrants the link to be disconnected. Notifies any callback set via 98 // |set_closed_callback()| and notifies the error callback of all pending HCI 99 // transactions. 100 // 101 // Does nothing if the channel is not open. 102 // 103 // NOTE: Bearer internally shuts down the link on request timeouts and 104 // sequential protocol violations. 105 void ShutDown(); 106 107 // Initiates an asynchronous transaction and invokes |callback| on this 108 // Bearer's creation thread when the transaction completes. |pdu| must 109 // correspond to a request or indication. 110 // 111 // TransactionCallback is used to report the end of a request or indication 112 // transaction. |packet| will contain a matching response or confirmation PDU 113 // depending on the transaction in question. 114 // 115 // If the transaction ends with an error or cannot complete (e.g. due to a 116 // timeout), |error_callback| will be called instead of |callback| if 117 // provided. 118 // 119 // Returns false if |pdu| is empty, exceeds the current MTU, or does not 120 // correspond to a request or indication. 121 using TransactionResult = fit::result<std::pair<Error, Handle>, PacketReader>; 122 using TransactionCallback = fit::callback<void(TransactionResult)>; 123 void StartTransaction(ByteBufferPtr pdu, TransactionCallback callback); 124 125 // Sends |pdu| without initiating a transaction. Used for command and 126 // notification PDUs which do not have flow control. 127 // 128 // Returns false if the packet is malformed or does not correspond to a 129 // command or notification. 130 [[nodiscard]] bool SendWithoutResponse(ByteBufferPtr pdu); 131 132 // A Handler is a function that gets invoked when the Bearer receives a PDU 133 // that is not tied to a locally initiated transaction (see 134 // StartTransaction()). 135 // 136 // * |tid| will be set to kInvalidTransactionId for command and notification 137 // PDUs. These do not require a response and are not part of a 138 // transaction. 139 // 140 // * A valid |tid| will be provided for request and indication PDUs. These 141 // require a response which can be sent by calling Reply(). 142 using TransactionId = size_t; 143 static constexpr TransactionId kInvalidTransactionId = 0u; 144 using Handler = 145 fit::function<void(TransactionId tid, const PacketReader& packet)>; 146 147 // Handler: called when |pdu| does not need flow control. This will be 148 // called for commands and notifications. 149 using HandlerId = size_t; 150 static constexpr HandlerId kInvalidHandlerId = 0u; 151 HandlerId RegisterHandler(OpCode opcode, Handler handler); 152 153 // Unregisters a handler. |id| cannot be zero. 154 void UnregisterHandler(HandlerId id); 155 156 // Ends a currently pending transaction with the given response or 157 // confirmation |pdu|. Returns false if |pdu| is malformed or if |id| and 158 // |pdu| do not match a pending transaction. 159 bool Reply(TransactionId tid, ByteBufferPtr pdu); 160 161 // Ends a request transaction with an error response. 162 bool ReplyWithError(TransactionId id, Handle handle, ErrorCode error_code); 163 164 using WeakPtr = WeakSelf<Bearer>::WeakPtr; GetWeakPtr()165 WeakPtr GetWeakPtr() { return weak_self_.GetWeakPtr(); } 166 167 private: 168 explicit Bearer(l2cap::Channel::WeakPtr chan, 169 pw::async::Dispatcher& dispatcher); 170 171 // Returns false if activation fails. This is called by the factory method. 172 bool Activate(); 173 174 // Represents a locally initiated pending request or indication transaction. 175 struct PendingTransaction { 176 PendingTransaction(OpCode opcode_in, 177 TransactionCallback callback_in, 178 ByteBufferPtr pdu_in); 179 180 // Required fields 181 OpCode opcode; 182 TransactionCallback callback; 183 184 // Holds the pdu while the transaction is in the send queue. 185 ByteBufferPtr pdu; 186 187 // Contains the most recently requested security upgrade level under which 188 // this transaction has been retried following an ATT security error. The 189 // states look like the following: 190 // 191 // - sm::SecurityLevel::kNoSecurity: The transaction has not been retried. 192 // - sm::SecurityLevel::kEncrypted: The request has been queued following 193 // a security upgrate to level "Encrypted". 194 // - sm::SecurityLevel::kAuthenticated: The request has been queued 195 // following a security upgrate to level "Authenticated". 196 // 197 // and so on. 198 sm::SecurityLevel security_retry_level; 199 }; 200 using PendingTransactionPtr = std::unique_ptr<PendingTransaction>; 201 202 // Represents a remote initiated pending request or indication transaction. 203 struct PendingRemoteTransaction { 204 PendingRemoteTransaction(TransactionId id_in, OpCode opcode_in); 205 PendingRemoteTransaction() = default; 206 207 TransactionId id; 208 OpCode opcode; 209 }; 210 211 // Used the represent the state of active ATT protocol request and indication 212 // transactions. 213 class TransactionQueue { 214 public: TransactionQueue(pw::async::Dispatcher & dispatcher)215 TransactionQueue(pw::async::Dispatcher& dispatcher) 216 : timeout_task_(dispatcher) {} 217 ~TransactionQueue() = default; 218 219 TransactionQueue(TransactionQueue&& other); 220 221 // Returns the transaction that has been sent to the peer and is currently 222 // pending completion. current()223 inline PendingTransaction* current() const { return current_.get(); } 224 225 // Clears the currently pending transaction data and cancels its transaction 226 // timeout task. Returns ownership of any pending transaction to the caller. 227 PendingTransactionPtr ClearCurrent(); 228 229 // Tries to initiate the next transaction. Sends the PDU over |chan| if 230 // successful. 231 void TrySendNext(const l2cap::Channel::WeakPtr& chan, 232 pw::async::TaskFunction timeout_cb, 233 pw::chrono::SystemClock::duration timeout); 234 235 // Adds |next| to the transaction queue. 236 void Enqueue(PendingTransactionPtr transaction); 237 238 // Resets the contents of this queue to their default state. 239 void Reset(); 240 241 // Invokes the error callbacks of all transactions with |status|. 242 void InvokeErrorAll(Error error); 243 244 private: 245 std::queue<std::unique_ptr<PendingTransaction>> queue_; 246 std::unique_ptr<PendingTransaction> current_; 247 SmartTask timeout_task_; 248 }; 249 250 bool SendInternal(ByteBufferPtr pdu, TransactionCallback callback); 251 252 // Shuts down the link. 253 void ShutDownInternal(bool due_to_timeout); 254 255 // Returns false if |packet| is malformed. 256 bool IsPacketValid(const ByteBuffer& packet); 257 258 // Tries to initiate the next transaction from the given |queue|. 259 void TryStartNextTransaction(TransactionQueue* tq); 260 261 // Sends out an immediate error response. 262 void SendErrorResponse(OpCode request_opcode, 263 Handle attribute_handle, 264 ErrorCode error_code); 265 266 // Called when the peer sends us a response or confirmation PDU. 267 void HandleEndTransaction(TransactionQueue* tq, const PacketReader& packet); 268 269 // Returns the next handler ID and increments the counter. 270 HandlerId NextHandlerId(); 271 272 // Returns the next remote-initiated transaction ID. 273 TransactionId NextRemoteTransactionId(); 274 275 using RemoteTransaction = std::optional<PendingRemoteTransaction>; 276 277 // Called when the peer initiates a request or indication transaction. 278 void HandleBeginTransaction(RemoteTransaction* currently_pending, 279 const PacketReader& packet); 280 281 // Returns any pending peer-initiated transaction that matches |id|. Returns 282 // nullptr otherwise. 283 RemoteTransaction* FindRemoteTransaction(TransactionId id); 284 285 // Called when the peer sends us a PDU that has no flow control (i.e. command 286 // or notification). Routes the packet to the corresponding handler. Drops the 287 // packet if no handler exists. 288 void HandlePDUWithoutResponse(const PacketReader& packet); 289 290 // l2cap::Channel callbacks: 291 void OnChannelClosed(); 292 void OnRxBFrame(ByteBufferPtr sdu); 293 294 pw::async::Dispatcher& dispatcher_; 295 296 l2cap::ScopedChannel chan_; 297 uint16_t mtu_; 298 uint16_t preferred_mtu_; 299 uint16_t min_mtu_; 300 301 // Set to true on the first call to ShutDownInternal. 302 bool shut_down_ = false; 303 304 // Channel closed callback assigned to us via set_closed_callback(). 305 fit::closure closed_cb_; 306 307 // The state of outgoing ATT requests and indications 308 TransactionQueue request_queue_; 309 TransactionQueue indication_queue_; 310 311 // The transaction identifier that will be assigned to the next 312 // remote-initiated request or indication transaction. 313 TransactionId next_remote_transaction_id_; 314 315 // The next available remote-initiated PDU handler id. 316 HandlerId next_handler_id_; 317 318 // Data about currently registered handlers. 319 std::unordered_map<HandlerId, OpCode> handler_id_map_; 320 std::unordered_map<OpCode, Handler> handlers_; 321 322 // Remote-initiated transactions in progress. 323 RemoteTransaction remote_request_; 324 RemoteTransaction remote_indication_; 325 326 WeakSelf<Bearer> weak_self_; 327 328 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Bearer); 329 }; 330 331 } // namespace bt::att 332