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