1 // Copyright 2024 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 17 #include <lib/fit/function.h> 18 19 #include <optional> 20 #include <unordered_map> 21 22 #include "pw_bluetooth_sapphire/internal/host/l2cap/dynamic_channel_registry.h" 23 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h" 24 #include "pw_bluetooth_sapphire/internal/host/l2cap/low_energy_command_handler.h" 25 #include "pw_bluetooth_sapphire/internal/host/l2cap/signaling_channel.h" 26 #include "pw_bluetooth_sapphire/internal/host/l2cap/types.h" 27 28 namespace bt::l2cap::internal { 29 30 // Implements factories for LE dynamic channels and dispatches incoming 31 // signaling channel requests to the corresponding channels by local ID. 32 class LeDynamicChannelRegistry final : public DynamicChannelRegistry { 33 public: 34 LeDynamicChannelRegistry(SignalingChannelInterface* sig, 35 DynamicChannelCallback close_cb, 36 ServiceRequestCallback service_request_cb, 37 bool random_channel_ids); 38 ~LeDynamicChannelRegistry() override = default; 39 40 private: 41 // DynamicChannelRegistry override 42 DynamicChannelPtr MakeOutbound(Psm psm, 43 ChannelId local_cid, 44 ChannelParameters params) override; 45 DynamicChannelPtr MakeInbound(Psm psm, 46 ChannelId local_cid, 47 ChannelId remote_cid, 48 ChannelParameters params) override; 49 50 // Incoming command handlers 51 void OnRxLeCreditBasedConnectionRequest( 52 uint16_t psm, 53 uint16_t remote_cid, 54 uint16_t maximum_transmission_unit, 55 uint16_t maximum_payload_size, 56 uint16_t initial_credits, 57 LowEnergyCommandHandler::LeCreditBasedConnectionResponder* responder); 58 59 SignalingChannelInterface* const sig_; 60 }; 61 62 struct LeChannelConfig { 63 // Maximum length of an SDU that can be received. 64 uint16_t mtu = 0; 65 // Maximum length of a PDU payload that can be received. 66 uint16_t mps = 0; 67 // Initial credits, this is only set at channel creation time. 68 uint16_t initial_credits = 0; 69 }; 70 71 // Creates, configures, and tears down dynamic channels using the LE 72 // signaling channel. The lifetime of this object matches that of the channel 73 // itself: created in order to start an outbound channel or in response to an 74 // inbound channel request, then destroyed immediately after the channel is 75 // closed. This is intended to be created and owned by 76 // LeDynamicChannelRegistry. 77 class LeDynamicChannel final : public DynamicChannel { 78 public: 79 static std::unique_ptr<LeDynamicChannel> MakeOutbound( 80 DynamicChannelRegistry* registry, 81 SignalingChannelInterface* signaling_channel, 82 Psm psm, 83 ChannelId local_cid, 84 ChannelParameters params); 85 86 static std::unique_ptr<LeDynamicChannel> MakeInbound( 87 DynamicChannelRegistry* registry, 88 SignalingChannelInterface* signaling_channel, 89 Psm psm, 90 ChannelId local_cid, 91 ChannelId remote_cid, 92 ChannelParameters params); 93 94 // DynamicChannel overrides 95 ~LeDynamicChannel() override = default; 96 97 void Open(fit::closure open_cb) override; 98 void Disconnect(DisconnectDoneCallback done_cb) override; 99 bool IsConnected() const override; 100 bool IsOpen() const override; 101 102 // Must be called for inbound channels after `MakeInbound` to complete opening 103 // the channel. 104 void CompleteInboundConnection( 105 LeChannelConfig remote_config, 106 LowEnergyCommandHandler::LeCreditBasedConnectionResponder* responder); 107 108 // Must not be called until channel is open. 109 ChannelInfo info() const override; 110 local_config()111 const LeChannelConfig& local_config() const { return local_config_; } 112 113 /// The setup state of an LE dynamic channel is much simpler than a BR/EDR 114 /// channel, namely it does not have a configuration state machine. Instead, 115 /// it is considered configured as soon as the 116 /// L2CAP_(LE_)_CREDIT_BASED_CONNECTION_RSP is sent. 117 struct State { 118 // L2CAP_LE_CREDIT_BASED_CONNECTION_REQ or L2CAP_CREDIT_BASED_CONNECTION_REQ 119 // transmitted in either direction. 120 bool exchanged_connection_request = false; 121 // L2CAP_LE_CREDIT_BASED_CONNECTION_RSP or L2CAP_CREDIT_BASED_CONNECTION_RSP 122 // transmitted in opposite direction of REQ. 123 bool exchanged_connection_response = false; 124 // L2CAP_DISCONNECTION_REQ transmitted in either direction. 125 bool exchanged_disconnect_request = false; 126 127 // Produce a string representation of `State`. 128 std::string ToString() const; 129 }; 130 131 private: 132 LeDynamicChannel(DynamicChannelRegistry* registry, 133 SignalingChannelInterface* signaling_channel, 134 Psm psm, 135 ChannelId local_cid, 136 ChannelId remote_cid, 137 ChannelParameters params, 138 bool is_outbound); 139 140 void TriggerOpenCallback(); 141 void OnRxLeCreditConnRsp( 142 const LowEnergyCommandHandler::LeCreditBasedConnectionResponse& rsp); 143 144 SignalingChannelInterface* const signaling_channel_; 145 CreditBasedFlowControlMode const flow_control_mode_; 146 147 State state_; 148 LeChannelConfig local_config_; 149 std::optional<LeChannelConfig> remote_config_; 150 fit::closure open_result_cb_; 151 bool is_outbound_; 152 WeakSelf<LeDynamicChannel> weak_self_; // Keep last. 153 }; 154 155 } // namespace bt::l2cap::internal 156