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