• 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/command_handler.h"
16 
17 namespace bt::l2cap::internal {
18 
ParseReject(const ByteBuffer & rej_payload_buf)19 bool CommandHandler::Response::ParseReject(const ByteBuffer& rej_payload_buf) {
20   if (rej_payload_buf.size() < sizeof(CommandRejectPayload)) {
21     bt_log(DEBUG,
22            "l2cap",
23            "cmd: ignoring malformed Command Reject, size %zu (expected >= %zu)",
24            rej_payload_buf.size(),
25            sizeof(CommandRejectPayload));
26     return false;
27   }
28   reject_reason_ = static_cast<RejectReason>(
29       le16toh(rej_payload_buf.ReadMember<&CommandRejectPayload::reason>()));
30 
31   if (reject_reason() == RejectReason::kInvalidCID) {
32     if (rej_payload_buf.size() - sizeof(CommandRejectPayload) <
33         sizeof(InvalidCIDPayload)) {
34       bt_log(DEBUG,
35              "l2cap",
36              "cmd: ignoring malformed Command Reject Invalid Channel ID, size "
37              "%zu (expected %zu)",
38              rej_payload_buf.size(),
39              sizeof(CommandRejectPayload) + sizeof(InvalidCIDPayload));
40       return false;
41     }
42     const auto& invalid_cid_payload =
43         rej_payload_buf.view(sizeof(CommandRejectPayload))
44             .To<InvalidCIDPayload>();
45     remote_cid_ = le16toh(invalid_cid_payload.src_cid);
46     local_cid_ = le16toh(invalid_cid_payload.dst_cid);
47   }
48 
49   return true;
50 }
51 
Decode(const ByteBuffer & payload_buf)52 bool CommandHandler::DisconnectionResponse::Decode(
53     const ByteBuffer& payload_buf) {
54   const auto disconn_rsp_payload = payload_buf.To<PayloadT>();
55   local_cid_ = le16toh(disconn_rsp_payload.src_cid);
56   remote_cid_ = le16toh(disconn_rsp_payload.dst_cid);
57   return true;
58 }
59 
Responder(SignalingChannel::Responder * sig_responder,ChannelId local_cid,ChannelId remote_cid)60 CommandHandler::Responder::Responder(SignalingChannel::Responder* sig_responder,
61                                      ChannelId local_cid,
62                                      ChannelId remote_cid)
63     : sig_responder_(sig_responder),
64       local_cid_(local_cid),
65       remote_cid_(remote_cid) {}
66 
RejectNotUnderstood()67 void CommandHandler::Responder::RejectNotUnderstood() {
68   sig_responder_->RejectNotUnderstood();
69 }
70 
RejectInvalidChannelId()71 void CommandHandler::Responder::RejectInvalidChannelId() {
72   sig_responder_->RejectInvalidChannelId(local_cid(), remote_cid());
73 }
74 
SendDisconnectionRequest(ChannelId remote_cid,ChannelId local_cid,DisconnectionResponseCallback cb)75 bool CommandHandler::SendDisconnectionRequest(
76     ChannelId remote_cid,
77     ChannelId local_cid,
78     DisconnectionResponseCallback cb) {
79   auto on_discon_rsp =
80       BuildResponseHandler<DisconnectionResponse>(std::move(cb));
81 
82   DisconnectionRequestPayload payload = {htole16(remote_cid),
83                                          htole16(local_cid)};
84   return sig()->SendRequest(kDisconnectionRequest,
85                             BufferView(&payload, sizeof(payload)),
86                             std::move(on_discon_rsp));
87 }
88 
ServeDisconnectionRequest(DisconnectionRequestCallback cb)89 void CommandHandler::ServeDisconnectionRequest(
90     DisconnectionRequestCallback cb) {
91   auto on_discon_req = [cb = std::move(cb)](
92                            const ByteBuffer& request_payload,
93                            SignalingChannel::Responder* sig_responder) {
94     if (request_payload.size() != sizeof(DisconnectionRequestPayload)) {
95       bt_log(DEBUG,
96              "l2cap",
97              "cmd: rejecting malformed Disconnection Request, size %zu",
98              request_payload.size());
99       sig_responder->RejectNotUnderstood();
100       return;
101     }
102 
103     const auto& discon_req = request_payload.To<DisconnectionRequestPayload>();
104     const ChannelId local_cid = le16toh(discon_req.dst_cid);
105     const ChannelId remote_cid = le16toh(discon_req.src_cid);
106     DisconnectionResponder responder(sig_responder, local_cid, remote_cid);
107     cb(local_cid, remote_cid, &responder);
108   };
109 
110   sig()->ServeRequest(kDisconnectionRequest, std::move(on_discon_req));
111 }
112 
CommandHandler(SignalingChannelInterface * sig,fit::closure request_fail_callback)113 CommandHandler::CommandHandler(SignalingChannelInterface* sig,
114                                fit::closure request_fail_callback)
115     : sig_(sig), request_fail_callback_(std::move(request_fail_callback)) {
116   BT_ASSERT(sig_);
117 }
118 
119 }  // namespace bt::l2cap::internal
120