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