• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "pw_bluetooth/l2cap_frames.emb.h"
18 #include "pw_bluetooth_proxy/basic_l2cap_channel.h"
19 #include "pw_bluetooth_proxy/l2cap_status_delegate.h"
20 #include "pw_containers/vector.h"
21 #include "pw_multibuf/allocator.h"
22 #include "pw_sync/lock_annotations.h"
23 #include "pw_sync/mutex.h"
24 
25 namespace pw::bluetooth::proxy {
26 
27 // Interface for L2CAP signaling channels, which can be either ACL-U signaling
28 // channels or LE-U signaling channels.
29 //
30 // Write and Read payloads are L2CAP signal commands.
31 class L2capSignalingChannel : public BasicL2capChannel {
32  public:
33   explicit L2capSignalingChannel(L2capChannelManager& l2cap_channel_manager,
34                                  uint16_t connection_handle,
35                                  AclTransportType transport,
36                                  uint16_t fixed_cid);
37 
38   L2capSignalingChannel& operator=(L2capSignalingChannel&& other);
39 
40   // Process the payload of a CFrame. Implementations should return true if the
41   // CFrame was consumed by the channel. Otherwise, return false and the PDU
42   // containing this CFrame will be forwarded on by the ProxyHost.
43   virtual bool OnCFramePayload(Direction direction,
44                                pw::span<const uint8_t> cframe_payload) = 0;
45 
46   // Process an individual signaling command.
47   //
48   // Returns false if the command is not processed, either because it is not
49   // directed to a channel managed by `L2capChannelManager` or because we do
50   // not listen for that type of command.
51   bool HandleL2capSignalingCommand(Direction direction,
52                                    emboss::L2capSignalingCommandView cmd);
53 
54   // Handle L2CAP_CONNECTION_REQ.
55   void HandleConnectionReq(Direction direction,
56                            emboss::L2capConnectionReqView cmd);
57 
58   // Handle L2CAP_CONNECTION_RSP.
59   void HandleConnectionRsp(Direction direction,
60                            emboss::L2capConnectionRspView cmd);
61 
62   // Handle L2CAP_DISCONNECTION_REQ.
63   void HandleDisconnectionReq(Direction direction,
64                               emboss::L2capDisconnectionReqView cmd);
65 
66   // Handle L2CAP_DISCONNECTION_RSP.
67   void HandleDisconnectionRsp(Direction direction,
68                               emboss::L2capDisconnectionRspView cmd);
69 
70   // Handle L2CAP_FLOW_CONTROL_CREDIT_IND.
71   //
72   // Returns false if the packet is invalid or not directed to a channel managed
73   // by `L2capChannelManager`.
74   bool HandleFlowControlCreditInd(emboss::L2capFlowControlCreditIndView cmd);
75 
76   // Send L2CAP_FLOW_CONTROL_CREDIT_IND to indicate local endpoint `cid` is
77   // capable of receiving a number of additional K-frames (`credits`).
78   //
79   // @returns @rst
80   //
81   // .. pw-status-codes::
82   // UNAVAILABLE:   Send could not be queued due to lack of memory in the
83   // client-provided rx_multibuf_allocator (transient error).
84   //  FAILED_PRECONDITION: If channel is not `State::kRunning`.
85   // @endrst
86   Status SendFlowControlCreditInd(
87       uint16_t cid,
88       uint16_t credits,
89       multibuf::MultiBufAllocator& multibuf_allocator);
90 
91  protected:
92   // Process a C-frame.
93   //
94   // Returns false if the C-frame is to be forwarded on to the Bluetooth host,
95   // either because the command is not directed towards a channel managed by
96   // `L2capChannelManager` or because the C-frame is invalid and should be
97   // handled by the Bluetooth host.
98   bool DoHandlePduFromController(pw::span<uint8_t> cframe) override;
99 
100   bool HandlePduFromHost(pw::span<uint8_t> cframe) override;
101 
102   // Get the next Identifier value that should be written to a signaling
103   // command and increment the Identifier.
104   uint8_t GetNextIdentifierAndIncrement();
105 
106   L2capChannelManager& l2cap_channel_manager_;
107 
108  private:
109   struct PendingConnection {
110     Direction direction;
111     uint16_t source_cid;
112     uint16_t psm;
113   };
114 
115   // Number of partially open l2cap connections the signaling channel can track.
116   // These are kept open till the connection response comes through providing
117   // the destination_cid to complete the connection info.
118   static constexpr size_t kMaxPendingConnections = 10;
119 
120   Vector<PendingConnection, kMaxPendingConnections> pending_connections_
PW_GUARDED_BY(mutex_)121       PW_GUARDED_BY(mutex_){};
122 
123   sync::Mutex mutex_;
124 
125   // Core Spec v6.0 Vol 3, Part A, Section 4: "The Identifier field is one octet
126   // long and matches responses with requests. The requesting device sets this
127   // field and the responding device uses the same value in its response. Within
128   // each signaling channel a different Identifier shall be used for each
129   // successive command. Following the original transmission of an Identifier in
130   // a command, the Identifier may be recycled if all other Identifiers have
131   // subsequently been used."
132   // TODO: https://pwbug.dev/382553099 - Synchronize this value with AP host.
133   uint8_t next_identifier_ = 1;
134 };
135 
136 }  // namespace pw::bluetooth::proxy
137