• 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_command_handler.h"
16 
17 #include <pw_bytes/endian.h>
18 
19 #include <type_traits>
20 
21 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/packet_view.h"
24 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel_configuration.h"
25 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
26 
27 namespace bt::l2cap::internal {
28 
Decode(const ByteBuffer & payload_buf)29 bool BrEdrCommandHandler::ConnectionResponse::Decode(
30     const ByteBuffer& payload_buf) {
31   auto conn_rsp_payload = payload_buf.To<PayloadT>();
32   remote_cid_ = pw::bytes::ConvertOrderFrom(cpp20::endian::little,
33                                             conn_rsp_payload.dst_cid);
34   local_cid_ = pw::bytes::ConvertOrderFrom(cpp20::endian::little,
35                                            conn_rsp_payload.src_cid);
36   result_ = static_cast<ConnectionResult>(pw::bytes::ConvertOrderFrom(
37       cpp20::endian::little, static_cast<uint16_t>(conn_rsp_payload.result)));
38   conn_status_ = static_cast<ConnectionStatus>(pw::bytes::ConvertOrderFrom(
39       cpp20::endian::little, static_cast<uint16_t>(conn_rsp_payload.status)));
40   return true;
41 }
42 
Decode(const ByteBuffer & payload_buf)43 bool BrEdrCommandHandler::ConfigurationResponse::Decode(
44     const ByteBuffer& payload_buf) {
45   PacketView<PayloadT> config_rsp(&payload_buf,
46                                   payload_buf.size() - sizeof(PayloadT));
47   local_cid_ = pw::bytes::ConvertOrderFrom(cpp20::endian::little,
48                                            config_rsp.header().src_cid);
49   flags_ = pw::bytes::ConvertOrderFrom(cpp20::endian::little,
50                                        config_rsp.header().flags);
51   result_ = static_cast<ConfigurationResult>(pw::bytes::ConvertOrderFrom(
52       cpp20::endian::little,
53       static_cast<uint16_t>(config_rsp.header().result)));
54 
55   if (!config_.ReadOptions(config_rsp.payload_data())) {
56     bt_log(WARN,
57            "l2cap",
58            "could not decode channel configuration response option");
59     return false;
60   }
61   return true;
62 }
63 
Decode(const ByteBuffer & payload_buf)64 bool BrEdrCommandHandler::InformationResponse::Decode(
65     const ByteBuffer& payload_buf) {
66   PacketView<InformationResponsePayload> info_rsp(
67       &payload_buf, payload_buf.size() - sizeof(InformationResponsePayload));
68   type_ = InformationType{pw::bytes::ConvertOrderFrom(
69       cpp20::endian::little, static_cast<uint16_t>(info_rsp.header().type))};
70   result_ = InformationResult{pw::bytes::ConvertOrderFrom(
71       cpp20::endian::little, static_cast<uint16_t>(info_rsp.header().result))};
72   if (result_ != InformationResult::kSuccess) {
73     return true;
74   }
75 
76   size_t expected_size = 0;
77   switch (type_) {
78     case InformationType::kConnectionlessMTU:
79       expected_size = sizeof(uint16_t);
80       break;
81     case InformationType::kExtendedFeaturesSupported:
82       expected_size = sizeof(ExtendedFeatures);
83       break;
84     case InformationType::kFixedChannelsSupported:
85       expected_size = sizeof(FixedChannelsSupported);
86       break;
87     default:
88       bt_log(DEBUG,
89              "l2cap-bredr",
90              "cmd: passing Information Response with unknown type %#.4hx with "
91              "%zu data bytes",
92              static_cast<unsigned short>(type_),
93              info_rsp.payload_size());
94   }
95   if (info_rsp.payload_size() < expected_size) {
96     bt_log(DEBUG,
97            "l2cap-bredr",
98            "cmd: ignoring malformed Information Response, type %#.4hx with %zu "
99            "data bytes",
100            static_cast<unsigned short>(type_),
101            info_rsp.payload_size());
102     return false;
103   }
104   data_ = info_rsp.payload_data();
105   return true;
106 }
107 
ConnectionResponder(SignalingChannel::Responder * sig_responder,ChannelId remote_cid)108 BrEdrCommandHandler::ConnectionResponder::ConnectionResponder(
109     SignalingChannel::Responder* sig_responder, ChannelId remote_cid)
110     : Responder(sig_responder, kInvalidChannelId, remote_cid) {}
111 
Send(ChannelId local_cid,ConnectionResult result,ConnectionStatus status)112 void BrEdrCommandHandler::ConnectionResponder::Send(ChannelId local_cid,
113                                                     ConnectionResult result,
114                                                     ConnectionStatus status) {
115   ConnectionResponsePayload conn_rsp = {
116       pw::bytes::ConvertOrderTo(cpp20::endian::little, local_cid),
117       pw::bytes::ConvertOrderTo(cpp20::endian::little, remote_cid()),
118       static_cast<ConnectionResult>(pw::bytes::ConvertOrderTo(
119           cpp20::endian::little, static_cast<uint16_t>(result))),
120       static_cast<ConnectionStatus>(pw::bytes::ConvertOrderTo(
121           cpp20::endian::little, static_cast<uint16_t>(status)))};
122   sig_responder_->Send(BufferView(&conn_rsp, sizeof(conn_rsp)));
123 }
124 
ConfigurationResponder(SignalingChannel::Responder * sig_responder,ChannelId local_cid)125 BrEdrCommandHandler::ConfigurationResponder::ConfigurationResponder(
126     SignalingChannel::Responder* sig_responder, ChannelId local_cid)
127     : Responder(sig_responder, local_cid) {}
128 
Send(ChannelId remote_cid,uint16_t flags,ConfigurationResult result,ChannelConfiguration::ConfigurationOptions options)129 void BrEdrCommandHandler::ConfigurationResponder::Send(
130     ChannelId remote_cid,
131     uint16_t flags,
132     ConfigurationResult result,
133     ChannelConfiguration::ConfigurationOptions options) {
134   size_t options_size = 0;
135   for (auto& option : options) {
136     options_size += option->size();
137   }
138 
139   DynamicByteBuffer config_rsp_buf(sizeof(ConfigurationResponsePayload) +
140                                    options_size);
141   MutablePacketView<ConfigurationResponsePayload> config_rsp(&config_rsp_buf,
142                                                              options_size);
143   config_rsp.mutable_header()->src_cid =
144       pw::bytes::ConvertOrderTo(cpp20::endian::little, remote_cid);
145   config_rsp.mutable_header()->flags =
146       pw::bytes::ConvertOrderTo(cpp20::endian::little, flags);
147   config_rsp.mutable_header()->result =
148       static_cast<ConfigurationResult>(pw::bytes::ConvertOrderTo(
149           cpp20::endian::little, static_cast<uint16_t>(result)));
150 
151   auto payload_view = config_rsp.mutable_payload_data().mutable_view();
152   for (auto& option : options) {
153     auto encoded = option->Encode();
154     payload_view.Write(encoded.data(), encoded.size());
155     payload_view = payload_view.mutable_view(encoded.size());
156   }
157 
158   sig_responder_->Send(config_rsp.data());
159 }
160 
DisconnectionResponder(SignalingChannel::Responder * sig_responder,ChannelId local_cid,ChannelId remote_cid)161 BrEdrCommandHandler::DisconnectionResponder::DisconnectionResponder(
162     SignalingChannel::Responder* sig_responder,
163     ChannelId local_cid,
164     ChannelId remote_cid)
165     : Responder(sig_responder, local_cid, remote_cid) {}
166 
Send()167 void BrEdrCommandHandler::DisconnectionResponder::Send() {
168   DisconnectionResponsePayload discon_rsp = {
169       pw::bytes::ConvertOrderTo(cpp20::endian::little, local_cid()),
170       pw::bytes::ConvertOrderTo(cpp20::endian::little, remote_cid())};
171   sig_responder_->Send(BufferView(&discon_rsp, sizeof(discon_rsp)));
172 }
173 
InformationResponder(SignalingChannel::Responder * sig_responder,InformationType type)174 BrEdrCommandHandler::InformationResponder::InformationResponder(
175     SignalingChannel::Responder* sig_responder, InformationType type)
176     : Responder(sig_responder), type_(type) {}
177 
SendNotSupported()178 void BrEdrCommandHandler::InformationResponder::SendNotSupported() {
179   Send(InformationResult::kNotSupported, BufferView());
180 }
181 
SendConnectionlessMtu(uint16_t mtu)182 void BrEdrCommandHandler::InformationResponder::SendConnectionlessMtu(
183     uint16_t mtu) {
184   mtu = pw::bytes::ConvertOrderTo(cpp20::endian::little, mtu);
185   Send(InformationResult::kSuccess, BufferView(&mtu, sizeof(mtu)));
186 }
187 
SendExtendedFeaturesSupported(ExtendedFeatures extended_features)188 void BrEdrCommandHandler::InformationResponder::SendExtendedFeaturesSupported(
189     ExtendedFeatures extended_features) {
190   extended_features =
191       pw::bytes::ConvertOrderTo(cpp20::endian::little, extended_features);
192   Send(InformationResult::kSuccess,
193        BufferView(&extended_features, sizeof(extended_features)));
194 }
195 
SendFixedChannelsSupported(FixedChannelsSupported channels_supported)196 void BrEdrCommandHandler::InformationResponder::SendFixedChannelsSupported(
197     FixedChannelsSupported channels_supported) {
198   channels_supported =
199       pw::bytes::ConvertOrderTo(cpp20::endian::little, channels_supported);
200   Send(InformationResult::kSuccess,
201        BufferView(&channels_supported, sizeof(channels_supported)));
202 }
203 
Send(InformationResult result,const ByteBuffer & data)204 void BrEdrCommandHandler::InformationResponder::Send(InformationResult result,
205                                                      const ByteBuffer& data) {
206   constexpr size_t kMaxPayloadLength =
207       sizeof(InformationResponsePayload) + sizeof(uint64_t);
208   StaticByteBuffer<kMaxPayloadLength> info_rsp_buf;
209   MutablePacketView<InformationResponsePayload> info_rsp_view(&info_rsp_buf,
210                                                               data.size());
211 
212   info_rsp_view.mutable_header()->type =
213       static_cast<InformationType>(pw::bytes::ConvertOrderTo(
214           cpp20::endian::little, static_cast<uint16_t>(type_)));
215   info_rsp_view.mutable_header()->result =
216       static_cast<InformationResult>(pw::bytes::ConvertOrderTo(
217           cpp20::endian::little, static_cast<uint16_t>(result)));
218   info_rsp_view.mutable_payload_data().Write(data);
219   sig_responder_->Send(info_rsp_view.data());
220 }
221 
BrEdrCommandHandler(SignalingChannelInterface * sig,fit::closure request_fail_callback)222 BrEdrCommandHandler::BrEdrCommandHandler(SignalingChannelInterface* sig,
223                                          fit::closure request_fail_callback)
224     : CommandHandler(sig, std::move(request_fail_callback)) {}
225 
SendConnectionRequest(uint16_t psm,ChannelId local_cid,ConnectionResponseCallback cb)226 bool BrEdrCommandHandler::SendConnectionRequest(uint16_t psm,
227                                                 ChannelId local_cid,
228                                                 ConnectionResponseCallback cb) {
229   auto on_conn_rsp = BuildResponseHandler<ConnectionResponse>(std::move(cb));
230 
231   ConnectionRequestPayload payload = {
232       pw::bytes::ConvertOrderTo(cpp20::endian::little, psm),
233       pw::bytes::ConvertOrderTo(cpp20::endian::little, local_cid)};
234   return sig()->SendRequest(kConnectionRequest,
235                             BufferView(&payload, sizeof(payload)),
236                             std::move(on_conn_rsp));
237 }
238 
SendConfigurationRequest(ChannelId remote_cid,uint16_t flags,ChannelConfiguration::ConfigurationOptions options,ConfigurationResponseCallback cb)239 bool BrEdrCommandHandler::SendConfigurationRequest(
240     ChannelId remote_cid,
241     uint16_t flags,
242     ChannelConfiguration::ConfigurationOptions options,
243     ConfigurationResponseCallback cb) {
244   auto on_config_rsp =
245       BuildResponseHandler<ConfigurationResponse>(std::move(cb));
246 
247   size_t options_size = 0;
248   for (auto& option : options) {
249     options_size += option->size();
250   }
251 
252   DynamicByteBuffer config_req_buf(sizeof(ConfigurationRequestPayload) +
253                                    options_size);
254   MutablePacketView<ConfigurationRequestPayload> config_req(&config_req_buf,
255                                                             options_size);
256   config_req.mutable_header()->dst_cid =
257       pw::bytes::ConvertOrderTo(cpp20::endian::little, remote_cid);
258   config_req.mutable_header()->flags =
259       pw::bytes::ConvertOrderTo(cpp20::endian::little, flags);
260 
261   auto payload_view = config_req.mutable_payload_data().mutable_view();
262   for (auto& option : options) {
263     auto encoded = option->Encode();
264     payload_view.Write(encoded.data(), encoded.size());
265     payload_view = payload_view.mutable_view(encoded.size());
266   }
267 
268   return sig()->SendRequest(
269       kConfigurationRequest, config_req_buf, std::move(on_config_rsp));
270 }
271 
SendInformationRequest(InformationType type,InformationResponseCallback callback)272 bool BrEdrCommandHandler::SendInformationRequest(
273     InformationType type, InformationResponseCallback callback) {
274   auto on_info_rsp =
275       BuildResponseHandler<InformationResponse>(std::move(callback));
276 
277   InformationRequestPayload payload = {
278       InformationType{pw::bytes::ConvertOrderTo(cpp20::endian::little,
279                                                 static_cast<uint16_t>(type))}};
280   return sig()->SendRequest(kInformationRequest,
281                             BufferView(&payload, sizeof(payload)),
282                             std::move(on_info_rsp));
283 }
284 
ServeConnectionRequest(ConnectionRequestCallback callback)285 void BrEdrCommandHandler::ServeConnectionRequest(
286     ConnectionRequestCallback callback) {
287   auto on_conn_req = [cb = std::move(callback)](
288                          const ByteBuffer& request_payload,
289                          SignalingChannel::Responder* sig_responder) {
290     if (request_payload.size() != sizeof(ConnectionRequestPayload)) {
291       bt_log(DEBUG,
292              "l2cap-bredr",
293              "cmd: rejecting malformed Connection Request, size %zu",
294              request_payload.size());
295       sig_responder->RejectNotUnderstood();
296       return;
297     }
298 
299     const auto& conn_req = request_payload.To<ConnectionRequestPayload>();
300     const Psm psm =
301         pw::bytes::ConvertOrderFrom(cpp20::endian::little, conn_req.psm);
302     const ChannelId remote_cid =
303         pw::bytes::ConvertOrderFrom(cpp20::endian::little, conn_req.src_cid);
304 
305     ConnectionResponder responder(sig_responder, remote_cid);
306 
307     // v5.0 Vol 3, Part A, Sec 4.2: PSMs shall be odd and the least significant
308     // bit of the most significant byte shall be zero
309     if (((psm & 0x0001) != 0x0001) || ((psm & 0x0100) != 0x0000)) {
310       bt_log(DEBUG,
311              "l2cap-bredr",
312              "Rejecting connection for invalid PSM %#.4x from channel %#.4x",
313              psm,
314              remote_cid);
315       responder.Send(kInvalidChannelId,
316                      ConnectionResult::kPsmNotSupported,
317                      ConnectionStatus::kNoInfoAvailable);
318       return;
319     }
320 
321     // Check that source channel ID is in range (v5.0 Vol 3, Part A, Sec 2.1)
322     if (remote_cid < kFirstDynamicChannelId) {
323       bt_log(DEBUG,
324              "l2cap-bredr",
325              "Rejecting connection for PSM %#.4x from invalid channel %#.4x",
326              psm,
327              remote_cid);
328       responder.Send(kInvalidChannelId,
329                      ConnectionResult::kInvalidSourceCID,
330                      ConnectionStatus::kNoInfoAvailable);
331       return;
332     }
333 
334     cb(psm, remote_cid, &responder);
335   };
336 
337   sig()->ServeRequest(kConnectionRequest, std::move(on_conn_req));
338 }
339 
ServeConfigurationRequest(ConfigurationRequestCallback callback)340 void BrEdrCommandHandler::ServeConfigurationRequest(
341     ConfigurationRequestCallback callback) {
342   auto on_config_req = [cb = std::move(callback)](
343                            const ByteBuffer& request_payload,
344                            SignalingChannel::Responder* sig_responder) {
345     if (request_payload.size() < sizeof(ConfigurationRequestPayload)) {
346       bt_log(DEBUG,
347              "l2cap-bredr",
348              "cmd: rejecting malformed Configuration Request, size %zu",
349              request_payload.size());
350       sig_responder->RejectNotUnderstood();
351       return;
352     }
353 
354     PacketView<ConfigurationRequestPayload> config_req(
355         &request_payload,
356         request_payload.size() - sizeof(ConfigurationRequestPayload));
357     const auto local_cid = static_cast<ChannelId>(pw::bytes::ConvertOrderFrom(
358         cpp20::endian::little, config_req.header().dst_cid));
359     const uint16_t flags = pw::bytes::ConvertOrderFrom(
360         cpp20::endian::little, config_req.header().flags);
361     ConfigurationResponder responder(sig_responder, local_cid);
362 
363     ChannelConfiguration config;
364     if (!config.ReadOptions(config_req.payload_data())) {
365       bt_log(WARN,
366              "l2cap",
367              "could not decode configuration option in configuration request");
368     }
369 
370     cb(local_cid, flags, std::move(config), &responder);
371   };
372 
373   sig()->ServeRequest(kConfigurationRequest, std::move(on_config_req));
374 }
375 
ServeInformationRequest(InformationRequestCallback callback)376 void BrEdrCommandHandler::ServeInformationRequest(
377     InformationRequestCallback callback) {
378   auto on_info_req = [cb = std::move(callback)](
379                          const ByteBuffer& request_payload,
380                          SignalingChannel::Responder* sig_responder) {
381     if (request_payload.size() != sizeof(InformationRequestPayload)) {
382       bt_log(DEBUG,
383              "l2cap-bredr",
384              "cmd: rejecting malformed Information Request, size %zu",
385              request_payload.size());
386       sig_responder->RejectNotUnderstood();
387       return;
388     }
389 
390     const auto& info_req = request_payload.To<InformationRequestPayload>();
391     const auto type = static_cast<InformationType>(pw::bytes::ConvertOrderFrom(
392         cpp20::endian::little, static_cast<uint16_t>(info_req.type)));
393     InformationResponder responder(sig_responder, type);
394     cb(type, &responder);
395   };
396 
397   sig()->ServeRequest(kInformationRequest, std::move(on_info_req));
398 }
399 
400 }  // namespace bt::l2cap::internal
401