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_string/to_string.h> 18 19 #include <chrono> 20 #include <optional> 21 #include <variant> 22 23 #include "pw_bluetooth_sapphire/internal/host/common/macros.h" 24 #include "pw_bluetooth_sapphire/internal/host/common/weak_self.h" 25 #include "pw_bluetooth_sapphire/internal/host/hci-spec/le_connection_parameters.h" 26 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h" 27 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h" 28 #include "pw_bluetooth_sapphire/internal/host/sm/error.h" 29 #include "pw_bluetooth_sapphire/internal/host/sm/types.h" 30 31 namespace bt::l2cap { 32 33 class Channel; 34 // Callback invoked when a channel has been created or when an error occurs 35 // during channel creation (in which case the channel will be nullptr). 36 using ChannelCallback = fit::function<void(WeakSelf<Channel>::WeakPtr)>; 37 38 // Callback invoked when a logical link should be closed due to an error. 39 using LinkErrorCallback = fit::closure; 40 41 // Callback called to notify LE preferred connection parameters during the "LE 42 // Connection Parameter Update" procedure. 43 using LEConnectionParameterUpdateCallback = 44 fit::function<void(const hci_spec::LEPreferredConnectionParameters&)>; 45 46 // Callback called when response received to LE signaling channel Connection 47 // Parameters Update Request. |accepted| indicates whether the parameters were 48 // accepted by the peer. 49 using ConnectionParameterUpdateRequestCallback = 50 fit::function<void(bool accepted)>; 51 52 // Callback used to deliver LE fixed channels that are created when a LE link is 53 // registered with L2CAP. 54 using LEFixedChannelsCallback = fit::function<void( 55 WeakSelf<Channel>::WeakPtr att, WeakSelf<Channel>::WeakPtr smp)>; 56 57 // Callback used to request a security upgrade for an active logical link. 58 // Invokes its |callback| argument with the result of the operation. 59 using SecurityUpgradeCallback = 60 fit::function<void(hci_spec::ConnectionHandle ll_handle, 61 sm::SecurityLevel level, 62 sm::ResultFunction<> callback)>; 63 64 // A variant that can hold any channel mode. While the 65 // `CreditBasedFlowControlMode` codes do not intersect with the 66 // `RetransmissionAndFlowControlMode` retransmission and flow control codes, 67 // that is not a property that is guaranteed to hold for all future versions, 68 // and the request-based codes would not be valid in a configuration packet, 69 // unlike the "classic" modes. This type allows us to treat them as separate 70 // namespaces and access each through the variant. Note: Equality comparison 71 // with enum values for either enum are supported. 72 using AnyChannelMode = 73 std::variant<RetransmissionAndFlowControlMode, CreditBasedFlowControlMode>; 74 75 bool operator==(const AnyChannelMode& any, 76 RetransmissionAndFlowControlMode mode); 77 bool operator==(RetransmissionAndFlowControlMode mode, 78 const AnyChannelMode& any); 79 bool operator==(const AnyChannelMode& any, CreditBasedFlowControlMode mode); 80 bool operator==(CreditBasedFlowControlMode mode, const AnyChannelMode& any); 81 bool operator!=(const AnyChannelMode& any, 82 RetransmissionAndFlowControlMode mode); 83 bool operator!=(RetransmissionAndFlowControlMode mode, 84 const AnyChannelMode& any); 85 bool operator!=(const AnyChannelMode& any, CreditBasedFlowControlMode mode); 86 bool operator!=(CreditBasedFlowControlMode mode, const AnyChannelMode& any); 87 std::string AnyChannelModeToString(const AnyChannelMode& mode); 88 pw::StatusWithSize AnyChannelModeToPwString(const AnyChannelMode& mode, 89 pw::span<char> span); 90 91 // Channel configuration parameters specified by higher layers. 92 struct ChannelParameters { 93 std::optional<AnyChannelMode> mode; 94 // MTU 95 std::optional<uint16_t> max_rx_sdu_size; 96 97 std::optional<pw::chrono::SystemClock::duration> flush_timeout; 98 99 bool operator==(const ChannelParameters& rhs) const { 100 return mode == rhs.mode && max_rx_sdu_size == rhs.max_rx_sdu_size && 101 flush_timeout == rhs.flush_timeout; 102 } 103 ToStringChannelParameters104 std::string ToString() const { 105 auto mode_string = mode.has_value() ? AnyChannelModeToString(*mode) 106 : std::string("nullopt"); 107 auto sdu_string = 108 max_rx_sdu_size.has_value() 109 ? bt_lib_cpp_string::StringPrintf("%hu", *max_rx_sdu_size) 110 : std::string("nullopt"); 111 auto flush_timeout_string = 112 flush_timeout 113 ? bt_lib_cpp_string::StringPrintf( 114 "%lldms", 115 std::chrono::duration_cast<std::chrono::milliseconds>( 116 *flush_timeout) 117 .count()) 118 : std::string("nullopt"); 119 return bt_lib_cpp_string::StringPrintf( 120 "ChannelParameters{mode: %s, max_rx_sdu_size: %s, flush_timeout: %s}", 121 mode_string.c_str(), 122 sdu_string.c_str(), 123 flush_timeout_string.c_str()); 124 } 125 }; 126 127 // Convenience struct for passsing around information about an opened channel. 128 // For example, this is useful when describing the L2CAP channel underlying a 129 // zx::socket. 130 struct ChannelInfo { 131 ChannelInfo() = default; 132 133 static ChannelInfo MakeBasicMode( 134 uint16_t max_rx_sdu_size, 135 uint16_t max_tx_sdu_size, 136 std::optional<Psm> psm = std::nullopt, 137 std::optional<pw::chrono::SystemClock::duration> flush_timeout = 138 std::nullopt) { 139 return ChannelInfo(RetransmissionAndFlowControlMode::kBasic, 140 max_rx_sdu_size, 141 max_tx_sdu_size, 142 0, 143 0, 144 0, 145 psm, 146 flush_timeout); 147 } 148 149 static ChannelInfo MakeEnhancedRetransmissionMode( 150 uint16_t max_rx_sdu_size, 151 uint16_t max_tx_sdu_size, 152 uint8_t n_frames_in_tx_window, 153 uint8_t max_transmissions, 154 uint16_t max_tx_pdu_payload_size, 155 std::optional<Psm> psm = std::nullopt, 156 std::optional<pw::chrono::SystemClock::duration> flush_timeout = 157 std::nullopt) { 158 return ChannelInfo( 159 RetransmissionAndFlowControlMode::kEnhancedRetransmission, 160 max_rx_sdu_size, 161 max_tx_sdu_size, 162 n_frames_in_tx_window, 163 max_transmissions, 164 max_tx_pdu_payload_size, 165 psm, 166 flush_timeout); 167 } 168 169 static ChannelInfo MakeCreditBasedFlowControlMode( 170 CreditBasedFlowControlMode mode_in, 171 uint16_t max_rx_sdu_size, 172 uint16_t max_tx_sdu_size, 173 uint16_t max_tx_pdu_payload_size, 174 uint16_t remote_initial_credits, 175 std::optional<Psm> psm = std::nullopt) { 176 return ChannelInfo(mode_in, 177 max_rx_sdu_size, 178 max_tx_sdu_size, 179 /*n_frames_in_tx_window*/ 0, 180 /*max_transmissions*/ 0, 181 max_tx_pdu_payload_size, 182 psm, 183 std::nullopt, 184 remote_initial_credits); 185 } 186 187 ChannelInfo(AnyChannelMode mode_in, 188 uint16_t max_rx_sdu_size_in, 189 uint16_t max_tx_sdu_size_in, 190 uint8_t n_frames_in_tx_window_in, 191 uint8_t max_transmissions_in, 192 uint16_t max_tx_pdu_payload_size_in, 193 std::optional<Psm> psm_in = std::nullopt, 194 std::optional<pw::chrono::SystemClock::duration> 195 flush_timeout_in = std::nullopt, 196 std::optional<uint16_t> remote_initial_credits_in = std::nullopt) modeChannelInfo197 : mode(mode_in), 198 max_rx_sdu_size(max_rx_sdu_size_in), 199 max_tx_sdu_size(max_tx_sdu_size_in), 200 n_frames_in_tx_window(n_frames_in_tx_window_in), 201 max_transmissions(max_transmissions_in), 202 max_tx_pdu_payload_size(max_tx_pdu_payload_size_in), 203 psm(psm_in), 204 flush_timeout(flush_timeout_in), 205 remote_initial_credits(remote_initial_credits_in) {} 206 207 AnyChannelMode mode; 208 uint16_t max_rx_sdu_size; 209 uint16_t max_tx_sdu_size; 210 211 // For Enhanced Retransmission Mode only. See Core Spec v5.0 Vol 3, Part A, 212 // Sec 5.4 for details on each field. Values are not meaningful if mode = 213 // RetransmissionAndFlowControlMode::kBasic. 214 uint8_t n_frames_in_tx_window; 215 uint8_t max_transmissions; 216 uint16_t max_tx_pdu_payload_size; 217 218 // PSM of the service the channel is used for. 219 std::optional<Psm> psm; 220 221 // If present, the channel's packets will be marked as flushable. The value 222 // will be used to configure the link's automatic flush timeout. 223 std::optional<pw::chrono::SystemClock::duration> flush_timeout; 224 225 // Only present for credit-based flow-control channels. 226 std::optional<uint16_t> remote_initial_credits; 227 }; 228 229 // Data stored for services registered by higher layers. 230 template <typename ChannelCallbackT> 231 struct ServiceInfo { ServiceInfoServiceInfo232 ServiceInfo(ChannelParameters params, ChannelCallbackT cb) 233 : channel_params(params), channel_cb(std::move(cb)) {} 234 ServiceInfo(ServiceInfo&&) = default; 235 ServiceInfo& operator=(ServiceInfo&&) = default; 236 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ServiceInfo); 237 238 // Preferred channel configuration parameters for new channels for this 239 // service. 240 ChannelParameters channel_params; 241 242 // Callback for forwarding new channels to locally-hosted service. 243 ChannelCallbackT channel_cb; 244 }; 245 246 } // namespace bt::l2cap 247 248 namespace pw { 249 // AnyChannelMode supports pw::ToString. 250 template <> 251 StatusWithSize ToString(const bt::l2cap::AnyChannelMode& mode, 252 span<char> buffer); 253 } // namespace pw 254