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