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