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 #include "pw_bluetooth_sapphire/internal/host/l2cap/bredr_signaling_channel.h"
16
17 #include <pw_assert/check.h>
18 #include <pw_bytes/endian.h>
19
20 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
21
22 namespace bt::l2cap::internal {
23
BrEdrSignalingChannel(Channel::WeakPtr chan,pw::bluetooth::emboss::ConnectionRole role,pw::async::Dispatcher & dispatcher)24 BrEdrSignalingChannel::BrEdrSignalingChannel(
25 Channel::WeakPtr chan,
26 pw::bluetooth::emboss::ConnectionRole role,
27 pw::async::Dispatcher& dispatcher)
28 : SignalingChannel(std::move(chan), role, dispatcher) {
29 set_mtu(kDefaultMTU);
30
31 // Add default handler for incoming Echo Request commands.
32 ServeRequest(kEchoRequest,
33 [](const ByteBuffer& req_payload, Responder* responder) {
34 responder->Send(req_payload);
35 });
36 }
37
TestLink(const ByteBuffer & data,DataCallback callback)38 bool BrEdrSignalingChannel::TestLink(const ByteBuffer& data,
39 DataCallback callback) {
40 return SendRequest(
41 kEchoRequest,
42 data,
43 [cb = std::move(callback)](Status status, const ByteBuffer& rsp_payload) {
44 if (status == Status::kSuccess) {
45 cb(rsp_payload);
46 } else {
47 cb(BufferView());
48 }
49 return ResponseHandlerAction::kCompleteOutboundTransaction;
50 });
51 }
52
DecodeRxUnit(ByteBufferPtr sdu,const SignalingPacketHandler & cb)53 void BrEdrSignalingChannel::DecodeRxUnit(ByteBufferPtr sdu,
54 const SignalingPacketHandler& cb) {
55 // "Multiple commands may be sent in a single C-frame over Fixed Channel CID
56 // 0x0001 (ACL-U) (v5.0, Vol 3, Part A, Section 4)"
57 PW_DCHECK(sdu);
58 if (sdu->size() < sizeof(CommandHeader)) {
59 bt_log(DEBUG, "l2cap-bredr", "sig: dropped malformed ACL signaling packet");
60 return;
61 }
62
63 size_t sdu_offset = 0;
64 while (sdu_offset + sizeof(CommandHeader) <= sdu->size()) {
65 const auto header_data = sdu->view(sdu_offset, sizeof(CommandHeader));
66 SignalingPacket packet(&header_data);
67
68 uint16_t expected_payload_length = pw::bytes::ConvertOrderFrom(
69 cpp20::endian::little, packet.header().length);
70 size_t remaining_sdu_length =
71 sdu->size() - sdu_offset - sizeof(CommandHeader);
72 if (remaining_sdu_length < expected_payload_length) {
73 bt_log(DEBUG,
74 "l2cap-bredr",
75 "sig: expected more bytes (%zu < %u); drop",
76 remaining_sdu_length,
77 expected_payload_length);
78 SendCommandReject(
79 packet.header().id, RejectReason::kNotUnderstood, BufferView());
80 return;
81 }
82
83 const auto packet_data =
84 sdu->view(sdu_offset, sizeof(CommandHeader) + expected_payload_length);
85 cb(SignalingPacket(&packet_data, expected_payload_length));
86
87 sdu_offset += packet_data.size();
88 }
89
90 if (sdu_offset != sdu->size()) {
91 bt_log(DEBUG,
92 "l2cap-bredr",
93 "sig: incomplete packet header "
94 "(expected: %zu, left: %zu)",
95 sizeof(CommandHeader),
96 sdu->size() - sdu_offset);
97 }
98 }
99
IsSupportedResponse(CommandCode code) const100 bool BrEdrSignalingChannel::IsSupportedResponse(CommandCode code) const {
101 switch (code) {
102 case kCommandRejectCode:
103 case kConnectionResponse:
104 case kConfigurationResponse:
105 case kDisconnectionResponse:
106 case kEchoResponse:
107 case kInformationResponse:
108 return true;
109 }
110
111 // Other response-type commands are for AMP/LE and are not supported.
112 return false;
113 }
114
115 } // namespace bt::l2cap::internal
116