• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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