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_dynamic_channel.h"
16
17 #include <endian.h>
18
19 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
20 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
21 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel_configuration.h"
22 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
23
24 #pragma clang diagnostic ignored "-Wswitch-enum"
25
26 namespace bt::l2cap::internal {
27 namespace {
28
29 ChannelConfiguration::RetransmissionAndFlowControlOption
WriteRfcOutboundTimeouts(ChannelConfiguration::RetransmissionAndFlowControlOption rfc_option)30 WriteRfcOutboundTimeouts(
31 ChannelConfiguration::RetransmissionAndFlowControlOption rfc_option) {
32 rfc_option.set_rtx_timeout(kErtmReceiverReadyPollTimerMsecs);
33 rfc_option.set_monitor_timeout(kErtmMonitorTimerMsecs);
34 return rfc_option;
35 }
36
37 constexpr uint16_t kBrEdrDynamicChannelCount =
38 kLastACLDynamicChannelId - kFirstDynamicChannelId + 1;
39
40 const uint8_t kMaxNumBasicConfigRequests = 2;
41 } // namespace
42
BrEdrDynamicChannelRegistry(SignalingChannelInterface * sig,DynamicChannelCallback close_cb,ServiceRequestCallback service_request_cb,bool random_channel_ids)43 BrEdrDynamicChannelRegistry::BrEdrDynamicChannelRegistry(
44 SignalingChannelInterface* sig,
45 DynamicChannelCallback close_cb,
46 ServiceRequestCallback service_request_cb,
47 bool random_channel_ids)
48 : DynamicChannelRegistry(kBrEdrDynamicChannelCount,
49 std::move(close_cb),
50 std::move(service_request_cb),
51 random_channel_ids),
52 state_(0u),
53 sig_(sig) {
54 BT_DEBUG_ASSERT(sig_);
55 BrEdrCommandHandler cmd_handler(sig_);
56 cmd_handler.ServeConnectionRequest(
57 fit::bind_member<&BrEdrDynamicChannelRegistry::OnRxConnReq>(this));
58 cmd_handler.ServeConfigurationRequest(
59 fit::bind_member<&BrEdrDynamicChannelRegistry::OnRxConfigReq>(this));
60 cmd_handler.ServeDisconnectionRequest(
61 fit::bind_member<&BrEdrDynamicChannelRegistry::OnRxDisconReq>(this));
62 cmd_handler.ServeInformationRequest(
63 fit::bind_member<&BrEdrDynamicChannelRegistry::OnRxInfoReq>(this));
64 SendInformationRequests();
65 }
66
MakeOutbound(Psm psm,ChannelId local_cid,ChannelParameters params)67 DynamicChannelPtr BrEdrDynamicChannelRegistry::MakeOutbound(
68 Psm psm, ChannelId local_cid, ChannelParameters params) {
69 return BrEdrDynamicChannel::MakeOutbound(
70 this, sig_, psm, local_cid, params, PeerSupportsERTM());
71 }
72
MakeInbound(Psm psm,ChannelId local_cid,ChannelId remote_cid,ChannelParameters params)73 DynamicChannelPtr BrEdrDynamicChannelRegistry::MakeInbound(
74 Psm psm,
75 ChannelId local_cid,
76 ChannelId remote_cid,
77 ChannelParameters params) {
78 return BrEdrDynamicChannel::MakeInbound(
79 this, sig_, psm, local_cid, remote_cid, params, PeerSupportsERTM());
80 }
81
OnRxConnReq(Psm psm,ChannelId remote_cid,BrEdrCommandHandler::ConnectionResponder * responder)82 void BrEdrDynamicChannelRegistry::OnRxConnReq(
83 Psm psm,
84 ChannelId remote_cid,
85 BrEdrCommandHandler::ConnectionResponder* responder) {
86 bt_log(TRACE,
87 "l2cap-bredr",
88 "Got Connection Request for PSM %#.4x from channel %#.4x",
89 psm,
90 remote_cid);
91
92 if (remote_cid == kInvalidChannelId) {
93 bt_log(DEBUG,
94 "l2cap-bredr",
95 "Invalid source CID; rejecting connection for PSM %#.4x from "
96 "channel %#.4x",
97 psm,
98 remote_cid);
99 responder->Send(kInvalidChannelId,
100 ConnectionResult::kInvalidSourceCID,
101 ConnectionStatus::kNoInfoAvailable);
102 return;
103 }
104
105 if (FindChannelByRemoteId(remote_cid) != nullptr) {
106 bt_log(DEBUG,
107 "l2cap-bredr",
108 "Remote CID already in use; rejecting connection for PSM %#.4x from "
109 "channel %#.4x",
110 psm,
111 remote_cid);
112 responder->Send(kInvalidChannelId,
113 ConnectionResult::kSourceCIDAlreadyAllocated,
114 ConnectionStatus::kNoInfoAvailable);
115 return;
116 }
117
118 ChannelId local_cid = FindAvailableChannelId();
119 if (local_cid == kInvalidChannelId) {
120 bt_log(DEBUG,
121 "l2cap-bredr",
122 "Out of IDs; rejecting connection for PSM %#.4x from channel %#.4x",
123 psm,
124 remote_cid);
125 responder->Send(kInvalidChannelId,
126 ConnectionResult::kNoResources,
127 ConnectionStatus::kNoInfoAvailable);
128 return;
129 }
130
131 auto dyn_chan = RequestService(psm, local_cid, remote_cid);
132 if (!dyn_chan) {
133 bt_log(DEBUG,
134 "l2cap-bredr",
135 "Rejecting connection for unsupported PSM %#.4x from channel %#.4x",
136 psm,
137 remote_cid);
138 responder->Send(kInvalidChannelId,
139 ConnectionResult::kPsmNotSupported,
140 ConnectionStatus::kNoInfoAvailable);
141 return;
142 }
143
144 static_cast<BrEdrDynamicChannel*>(dyn_chan)->CompleteInboundConnection(
145 responder);
146 }
147
OnRxConfigReq(ChannelId local_cid,uint16_t flags,ChannelConfiguration config,BrEdrCommandHandler::ConfigurationResponder * responder)148 void BrEdrDynamicChannelRegistry::OnRxConfigReq(
149 ChannelId local_cid,
150 uint16_t flags,
151 ChannelConfiguration config,
152 BrEdrCommandHandler::ConfigurationResponder* responder) {
153 auto channel =
154 static_cast<BrEdrDynamicChannel*>(FindChannelByLocalId(local_cid));
155 if (channel == nullptr) {
156 bt_log(WARN,
157 "l2cap-bredr",
158 "ID %#.4x not found for Configuration Request",
159 local_cid);
160 responder->RejectInvalidChannelId();
161 return;
162 }
163
164 channel->OnRxConfigReq(flags, std::move(config), responder);
165 }
166
OnRxDisconReq(ChannelId local_cid,ChannelId remote_cid,BrEdrCommandHandler::DisconnectionResponder * responder)167 void BrEdrDynamicChannelRegistry::OnRxDisconReq(
168 ChannelId local_cid,
169 ChannelId remote_cid,
170 BrEdrCommandHandler::DisconnectionResponder* responder) {
171 auto channel =
172 static_cast<BrEdrDynamicChannel*>(FindChannelByLocalId(local_cid));
173 if (channel == nullptr || channel->remote_cid() != remote_cid) {
174 bt_log(WARN,
175 "l2cap-bredr",
176 "ID %#.4x not found for Disconnection Request (remote ID %#.4x)",
177 local_cid,
178 remote_cid);
179 responder->RejectInvalidChannelId();
180 return;
181 }
182
183 channel->OnRxDisconReq(responder);
184 }
185
OnRxInfoReq(InformationType type,BrEdrCommandHandler::InformationResponder * responder)186 void BrEdrDynamicChannelRegistry::OnRxInfoReq(
187 InformationType type,
188 BrEdrCommandHandler::InformationResponder* responder) {
189 bt_log(TRACE,
190 "l2cap-bredr",
191 "Got Information Request for type %#.4hx",
192 static_cast<unsigned short>(type));
193
194 // TODO(fxbug.dev/42175069): The responses here will likely remain hardcoded
195 // magics, but maybe they should live elsewhere.
196 switch (type) {
197 case InformationType::kConnectionlessMTU: {
198 responder->SendNotSupported();
199 break;
200 }
201
202 case InformationType::kExtendedFeaturesSupported: {
203 const ExtendedFeatures extended_features =
204 kExtendedFeaturesBitFixedChannels | kExtendedFeaturesBitFCSOption |
205 kExtendedFeaturesBitEnhancedRetransmission;
206
207 // Express support for the Fixed Channel Supported feature
208 responder->SendExtendedFeaturesSupported(extended_features);
209 break;
210 }
211
212 case InformationType::kFixedChannelsSupported: {
213 const FixedChannelsSupported channels_supported =
214 kFixedChannelsSupportedBitSignaling;
215
216 // Express support for the ACL-U Signaling Channel (as required)
217 // TODO(fxbug.dev/42175069): Set the bit for SM's fixed channel
218 responder->SendFixedChannelsSupported(channels_supported);
219 break;
220 }
221
222 default:
223 responder->RejectNotUnderstood();
224 bt_log(DEBUG,
225 "l2cap-bredr",
226 "Rejecting Information Request type %#.4hx",
227 static_cast<unsigned short>(type));
228 }
229 }
230
OnRxExtendedFeaturesInfoRsp(const BrEdrCommandHandler::InformationResponse & rsp)231 void BrEdrDynamicChannelRegistry::OnRxExtendedFeaturesInfoRsp(
232 const BrEdrCommandHandler::InformationResponse& rsp) {
233 if (rsp.status() == BrEdrCommandHandler::Status::kReject) {
234 bt_log(ERROR,
235 "l2cap-bredr",
236 "Extended Features Information Request rejected, reason %#.4hx, "
237 "disconnecting",
238 static_cast<unsigned short>(rsp.reject_reason()));
239 return;
240 }
241
242 if (rsp.result() != InformationResult::kSuccess) {
243 bt_log(DEBUG,
244 "l2cap-bredr",
245 "Extended Features Information Response failure result (result: "
246 "%#.4hx)",
247 static_cast<uint16_t>(rsp.result()));
248 // Treat failure result as if feature mask indicated no ERTM support so that
249 // configuration can fall back to basic mode.
250 ForEach([](DynamicChannel* chan) {
251 static_cast<BrEdrDynamicChannel*>(chan)->SetEnhancedRetransmissionSupport(
252 false);
253 });
254 return;
255 }
256
257 if (rsp.type() != InformationType::kExtendedFeaturesSupported) {
258 bt_log(
259 ERROR,
260 "l2cap-bredr",
261 "Incorrect extended features information response type (type: %#.4hx)",
262 static_cast<unsigned short>(rsp.type()));
263 return;
264 }
265
266 if ((state_ & kExtendedFeaturesReceived) ||
267 !(state_ & kExtendedFeaturesSent)) {
268 bt_log(ERROR,
269 "l2cap-bredr",
270 "Unexpected extended features information response (state: %#x)",
271 state_);
272 return;
273 }
274
275 bt_log(
276 TRACE,
277 "l2cap-bredr",
278 "Received Extended Features Information Response (feature mask: %#.4x)",
279 rsp.extended_features());
280
281 state_ |= kExtendedFeaturesReceived;
282
283 extended_features_ = rsp.extended_features();
284
285 // Notify all channels created before extended features received.
286 bool ertm_support =
287 *extended_features_ & kExtendedFeaturesBitEnhancedRetransmission;
288 ForEach([ertm_support](DynamicChannel* chan) {
289 static_cast<BrEdrDynamicChannel*>(chan)->SetEnhancedRetransmissionSupport(
290 ertm_support);
291 });
292 }
293
SendInformationRequests()294 void BrEdrDynamicChannelRegistry::SendInformationRequests() {
295 if (state_ & kExtendedFeaturesSent) {
296 bt_log(
297 DEBUG, "l2cap-bredr", "Skipping sending info requests, already sent");
298 return;
299 }
300 BrEdrCommandHandler cmd_handler(sig_);
301 auto on_rx_info_rsp = [self = GetWeakPtr(), this](auto& rsp) {
302 if (self.is_alive()) {
303 OnRxExtendedFeaturesInfoRsp(rsp);
304 }
305 };
306 if (!cmd_handler.SendInformationRequest(
307 InformationType::kExtendedFeaturesSupported,
308 std::move(on_rx_info_rsp))) {
309 bt_log(ERROR,
310 "l2cap-bredr",
311 "Failed to send Extended Features Information Request");
312 return;
313 }
314
315 state_ |= kExtendedFeaturesSent;
316 }
317
PeerSupportsERTM() const318 std::optional<bool> BrEdrDynamicChannelRegistry::PeerSupportsERTM() const {
319 if (!extended_features_) {
320 return std::nullopt;
321 }
322 return *extended_features_ & kExtendedFeaturesBitEnhancedRetransmission;
323 }
324
MakeOutbound(DynamicChannelRegistry * registry,SignalingChannelInterface * signaling_channel,Psm psm,ChannelId local_cid,ChannelParameters params,std::optional<bool> peer_supports_ertm)325 BrEdrDynamicChannelPtr BrEdrDynamicChannel::MakeOutbound(
326 DynamicChannelRegistry* registry,
327 SignalingChannelInterface* signaling_channel,
328 Psm psm,
329 ChannelId local_cid,
330 ChannelParameters params,
331 std::optional<bool> peer_supports_ertm) {
332 return std::unique_ptr<BrEdrDynamicChannel>(
333 new BrEdrDynamicChannel(registry,
334 signaling_channel,
335 psm,
336 local_cid,
337 kInvalidChannelId,
338 params,
339 peer_supports_ertm));
340 }
341
MakeInbound(DynamicChannelRegistry * registry,SignalingChannelInterface * signaling_channel,Psm psm,ChannelId local_cid,ChannelId remote_cid,ChannelParameters params,std::optional<bool> peer_supports_ertm)342 BrEdrDynamicChannelPtr BrEdrDynamicChannel::MakeInbound(
343 DynamicChannelRegistry* registry,
344 SignalingChannelInterface* signaling_channel,
345 Psm psm,
346 ChannelId local_cid,
347 ChannelId remote_cid,
348 ChannelParameters params,
349 std::optional<bool> peer_supports_ertm) {
350 auto channel = std::unique_ptr<BrEdrDynamicChannel>(
351 new BrEdrDynamicChannel(registry,
352 signaling_channel,
353 psm,
354 local_cid,
355 remote_cid,
356 params,
357 peer_supports_ertm));
358 channel->state_ |= kConnRequested;
359 return channel;
360 }
361
Open(fit::closure open_result_cb)362 void BrEdrDynamicChannel::Open(fit::closure open_result_cb) {
363 open_result_cb_ = std::move(open_result_cb);
364
365 if (state_ & kConnRequested) {
366 return;
367 }
368
369 auto on_conn_rsp = [self = weak_self_.GetWeakPtr()](
370 const BrEdrCommandHandler::ConnectionResponse& rsp) {
371 if (self.is_alive()) {
372 return self->OnRxConnRsp(rsp);
373 }
374 return BrEdrCommandHandler::ResponseHandlerAction::
375 kCompleteOutboundTransaction;
376 };
377
378 auto on_conn_rsp_timeout = [this, self = weak_self_.GetWeakPtr()] {
379 if (self.is_alive()) {
380 bt_log(WARN,
381 "l2cap-bredr",
382 "Channel %#.4x: Timed out waiting for Connection Response",
383 local_cid());
384 PassOpenError();
385 }
386 };
387
388 BrEdrCommandHandler cmd_handler(signaling_channel_,
389 std::move(on_conn_rsp_timeout));
390 if (!cmd_handler.SendConnectionRequest(
391 psm(), local_cid(), std::move(on_conn_rsp))) {
392 bt_log(ERROR,
393 "l2cap-bredr",
394 "Channel %#.4x: Failed to send Connection Request",
395 local_cid());
396 PassOpenError();
397 return;
398 }
399
400 bt_log(TRACE,
401 "l2cap-bredr",
402 "Channel %#.4x: Sent Connection Request",
403 local_cid());
404
405 state_ |= kConnRequested;
406 }
407
Disconnect(DisconnectDoneCallback done_cb)408 void BrEdrDynamicChannel::Disconnect(DisconnectDoneCallback done_cb) {
409 BT_ASSERT(done_cb);
410 if (!IsConnected()) {
411 done_cb();
412 return;
413 }
414
415 state_ |= kDisconnected;
416
417 // Don't send disconnect request if the peer never responded (also can't,
418 // because we don't have their end's ID).
419 if (remote_cid() == kInvalidChannelId) {
420 done_cb();
421 return;
422 }
423
424 auto on_discon_rsp =
425 [local_cid = local_cid(),
426 remote_cid = remote_cid(),
427 self = weak_self_.GetWeakPtr(),
428 done_cb = done_cb.share()](
429 const BrEdrCommandHandler::DisconnectionResponse& rsp) mutable {
430 if (rsp.local_cid() != local_cid || rsp.remote_cid() != remote_cid) {
431 bt_log(WARN,
432 "l2cap-bredr",
433 "Channel %#.4x: Got Disconnection Response with ID %#.4x/"
434 "remote ID %#.4x on channel with remote ID %#.4x",
435 local_cid,
436 rsp.local_cid(),
437 rsp.remote_cid(),
438 remote_cid);
439 } else {
440 bt_log(TRACE,
441 "l2cap-bredr",
442 "Channel %#.4x: Got Disconnection Response",
443 local_cid);
444 }
445
446 if (self.is_alive()) {
447 done_cb();
448 }
449 };
450
451 auto on_discon_rsp_timeout = [local_cid = local_cid(),
452 self = weak_self_.GetWeakPtr(),
453 done_cb = done_cb.share()]() mutable {
454 bt_log(WARN,
455 "l2cap-bredr",
456 "Channel %#.4x: Timed out waiting for Disconnection Response; "
457 "completing disconnection",
458 local_cid);
459 if (self.is_alive()) {
460 done_cb();
461 }
462 };
463
464 BrEdrCommandHandler cmd_handler(signaling_channel_,
465 std::move(on_discon_rsp_timeout));
466 if (!cmd_handler.SendDisconnectionRequest(
467 remote_cid(), local_cid(), std::move(on_discon_rsp))) {
468 bt_log(WARN,
469 "l2cap-bredr",
470 "Channel %#.4x: Failed to send Disconnection Request",
471 local_cid());
472 done_cb();
473 return;
474 }
475
476 bt_log(TRACE,
477 "l2cap-bredr",
478 "Channel %#.4x: Sent Disconnection Request",
479 local_cid());
480 }
481
IsConnected() const482 bool BrEdrDynamicChannel::IsConnected() const {
483 // Remote-initiated channels have remote_cid_ already set.
484 return (state_ & kConnRequested) && (state_ & kConnResponded) &&
485 (remote_cid() != kInvalidChannelId) && !(state_ & kDisconnected);
486 }
487
IsOpen() const488 bool BrEdrDynamicChannel::IsOpen() const {
489 return IsConnected() && BothConfigsAccepted() &&
490 AcceptedChannelModesAreConsistent();
491 }
492
info() const493 ChannelInfo BrEdrDynamicChannel::info() const {
494 BT_ASSERT(local_config().retransmission_flow_control_option().has_value());
495 BT_ASSERT(local_config().mtu_option().has_value());
496
497 const auto max_rx_sdu_size = local_config().mtu_option()->mtu();
498 const auto peer_mtu = remote_config().mtu_option()->mtu();
499 const auto flush_timeout = parameters_.flush_timeout;
500 if (local_config().retransmission_flow_control_option()->mode() ==
501 RetransmissionAndFlowControlMode::kBasic) {
502 const auto max_tx_sdu_size = peer_mtu;
503 return ChannelInfo::MakeBasicMode(
504 max_rx_sdu_size, max_tx_sdu_size, psm(), flush_timeout);
505 }
506 const auto n_frames_in_tx_window =
507 remote_config().retransmission_flow_control_option()->tx_window_size();
508 const auto max_transmissions =
509 remote_config().retransmission_flow_control_option()->max_transmit();
510 const auto max_tx_pdu_payload_size =
511 remote_config().retransmission_flow_control_option()->mps();
512 const auto max_tx_sdu_size = std::min(peer_mtu, max_tx_pdu_payload_size);
513 if (max_tx_pdu_payload_size < peer_mtu) {
514 bt_log(DEBUG,
515 "l2cap-bredr",
516 "Channel %#.4x: reporting MPS of %hu to service to avoid segmenting "
517 "outbound SDUs, "
518 "which would otherwise be %hu according to MTU",
519 local_cid(),
520 max_tx_sdu_size,
521 peer_mtu);
522 }
523 auto info =
524 ChannelInfo::MakeEnhancedRetransmissionMode(max_rx_sdu_size,
525 max_tx_sdu_size,
526 n_frames_in_tx_window,
527 max_transmissions,
528 max_tx_pdu_payload_size,
529 psm(),
530 flush_timeout);
531 return info;
532 }
533
OnRxConfigReq(uint16_t flags,ChannelConfiguration config,BrEdrCommandHandler::ConfigurationResponder * responder)534 void BrEdrDynamicChannel::OnRxConfigReq(
535 uint16_t flags,
536 ChannelConfiguration config,
537 BrEdrCommandHandler::ConfigurationResponder* responder) {
538 bool continuation = flags & kConfigurationContinuation;
539 bt_log(TRACE,
540 "l2cap-bredr",
541 "Channel %#.4x: Got Configuration Request (C: %d, options: %s)",
542 local_cid(),
543 continuation,
544 bt_str(config));
545
546 if (!IsConnected()) {
547 bt_log(WARN,
548 "l2cap-bredr",
549 "Channel %#.4x: Unexpected Configuration Request, state %x",
550 local_cid(),
551 state_);
552 return;
553 }
554
555 // Always add options to accumulator, even if C = 0, for later code
556 // simplicity.
557 if (remote_config_accum_.has_value()) {
558 remote_config_accum_->Merge(std::move(config));
559 } else {
560 // TODO(fxbug.dev/42115983): if channel is being re-configured, merge with
561 // existing configuration
562 remote_config_accum_ = std::move(config);
563 }
564
565 if (continuation) {
566 // keep responding with success until all options have been received (C flag
567 // is 0)
568 responder->Send(remote_cid(),
569 kConfigurationContinuation,
570 ConfigurationResult::kSuccess,
571 ChannelConfiguration::ConfigurationOptions());
572 bt_log(TRACE,
573 "l2cap-bredr",
574 "Channel %#.4x: Sent Configuration Response (C: 1)",
575 local_cid());
576 return;
577 }
578
579 auto req_config = std::exchange(remote_config_accum_, std::nullopt).value();
580
581 const auto req_mode =
582 req_config.retransmission_flow_control_option()
583 ? req_config.retransmission_flow_control_option()->mode()
584 : RetransmissionAndFlowControlMode::kBasic;
585
586 // Record peer support for ERTM even if they haven't sent a Extended Features
587 // Mask.
588 if (req_mode == RetransmissionAndFlowControlMode::kEnhancedRetransmission) {
589 SetEnhancedRetransmissionSupport(true);
590 }
591
592 // Set default config options if not already in request.
593 if (!req_config.mtu_option()) {
594 req_config.set_mtu_option(ChannelConfiguration::MtuOption(kDefaultMTU));
595 }
596
597 if (state_ & kRemoteConfigReceived) {
598 // Disconnect if second configuration request does not contain desired mode.
599 const auto local_mode =
600 local_config_.retransmission_flow_control_option()->mode();
601 if (req_mode != local_mode) {
602 bt_log(TRACE,
603 "l2cap-bredr",
604 "Channel %#.4x: second configuration request doesn't have desired "
605 "mode, sending unacceptable parameters response and disconnecting "
606 "(req mode: %#.2x, desired: %#.2x)",
607 local_cid(),
608 static_cast<uint8_t>(req_mode),
609 static_cast<uint8_t>(local_mode));
610 ChannelConfiguration::ConfigurationOptions options;
611 options.push_back(
612 std::make_unique<
613 ChannelConfiguration::RetransmissionAndFlowControlOption>(
614 *local_config().retransmission_flow_control_option()));
615 responder->Send(remote_cid(),
616 0x0000,
617 ConfigurationResult::kUnacceptableParameters,
618 std::move(options));
619 PassOpenError();
620 return;
621 }
622
623 bt_log(DEBUG,
624 "l2cap-bredr",
625 "Channel %#.4x: Reconfiguring, state %x",
626 local_cid(),
627 state_);
628 }
629
630 state_ |= kRemoteConfigReceived;
631
632 // Reject request if it contains unknown options.
633 // See Core Spec v5.1, Volume 3, Section 4.5: Configuration Options
634 if (!req_config.unknown_options().empty()) {
635 ChannelConfiguration::ConfigurationOptions unknown_options;
636 std::string unknown_string;
637 for (auto& option : req_config.unknown_options()) {
638 unknown_options.push_back(
639 std::make_unique<ChannelConfiguration::UnknownOption>(option));
640 unknown_string += std::string(" ") + option.ToString();
641 }
642
643 bt_log(DEBUG,
644 "l2cap-bredr",
645 "Channel %#.4x: config request contained unknown options (options: "
646 "%s)\n",
647 local_cid(),
648 unknown_string.c_str());
649
650 responder->Send(remote_cid(),
651 0x0000,
652 ConfigurationResult::kUnknownOptions,
653 std::move(unknown_options));
654 return;
655 }
656
657 auto unacceptable_config = CheckForUnacceptableConfigReqOptions(req_config);
658 auto unacceptable_options = unacceptable_config.Options();
659 if (!unacceptable_options.empty()) {
660 responder->Send(remote_cid(),
661 0x0000,
662 ConfigurationResult::kUnacceptableParameters,
663 std::move(unacceptable_options));
664 bt_log(TRACE,
665 "l2cap-bredr",
666 "Channel %#.4x: Sent unacceptable parameters configuration response "
667 "(options: %s)",
668 local_cid(),
669 bt_str(unacceptable_config));
670 return;
671 }
672
673 // TODO(fxbug.dev/42057179): Defer accepting config req using a Pending
674 // response
675 state_ |= kRemoteConfigAccepted;
676
677 ChannelConfiguration response_config;
678
679 // Successful response should include actual MTU local device will use. This
680 // must be min(received MTU, local outgoing MTU capability). Currently, we
681 // accept any MTU.
682 // TODO(fxbug.dev/42117452): determine the upper bound of what we are actually
683 // capable of sending
684 uint16_t actual_mtu = req_config.mtu_option()->mtu();
685 response_config.set_mtu_option(ChannelConfiguration::MtuOption(actual_mtu));
686 req_config.set_mtu_option(response_config.mtu_option());
687
688 if (req_mode == RetransmissionAndFlowControlMode::kEnhancedRetransmission) {
689 auto outbound_rfc_option = WriteRfcOutboundTimeouts(
690 req_config.retransmission_flow_control_option().value());
691 response_config.set_retransmission_flow_control_option(
692 std::move(outbound_rfc_option));
693 } else {
694 response_config.set_retransmission_flow_control_option(
695 req_config.retransmission_flow_control_option());
696 }
697
698 responder->Send(remote_cid(),
699 0x0000,
700 ConfigurationResult::kSuccess,
701 response_config.Options());
702
703 bt_log(TRACE,
704 "l2cap-bredr",
705 "Channel %#.4x: Sent Configuration Response (options: %s)",
706 local_cid(),
707 bt_str(response_config));
708
709 // Save accepted options.
710 remote_config_.Merge(std::move(req_config));
711
712 if (!remote_config_.retransmission_flow_control_option()) {
713 remote_config_.set_retransmission_flow_control_option(
714 ChannelConfiguration::RetransmissionAndFlowControlOption::
715 MakeBasicMode());
716 }
717
718 if (BothConfigsAccepted() && !AcceptedChannelModesAreConsistent()) {
719 bt_log(WARN,
720 "l2cap-bredr",
721 "Channel %#.4x: inconsistent channel mode negotiation (local mode: "
722 "%#.2x, remote "
723 "mode: %#.2x); falling back to Basic Mode",
724 local_cid(),
725 static_cast<uint8_t>(
726 local_config().retransmission_flow_control_option()->mode()),
727 static_cast<uint8_t>(
728 remote_config().retransmission_flow_control_option()->mode()));
729
730 // The most applicable guidance for the case where the peer send conflicting
731 // modes is in Core Spec v5.0 Vol 3, Part A, Sec 5.4: "If the mode proposed
732 // by the remote device has a higher precedence (according to the state 1
733 // precedence) then the algorithm will operate such that creation of a
734 // channel using the remote device's mode has higher priority than
735 // disconnecting the channel."
736 //
737 // Note also that, "In state 1, Basic L2CAP mode has the highest precedence
738 // and shall take precedence over Enhanced Retransmission mode..."
739 //
740 // So, if we are to continue the connection, it makes the most sense to use
741 // Basic Mode.
742 local_config_.set_retransmission_flow_control_option(
743 ChannelConfiguration::RetransmissionAndFlowControlOption::
744 MakeBasicMode());
745 remote_config_.set_retransmission_flow_control_option(
746 ChannelConfiguration::RetransmissionAndFlowControlOption::
747 MakeBasicMode());
748 PassOpenResult();
749 return;
750 }
751
752 if (IsOpen()) {
753 set_opened();
754 PassOpenResult();
755 }
756 }
757
OnRxDisconReq(BrEdrCommandHandler::DisconnectionResponder * responder)758 void BrEdrDynamicChannel::OnRxDisconReq(
759 BrEdrCommandHandler::DisconnectionResponder* responder) {
760 bt_log(TRACE,
761 "l2cap-bredr",
762 "Channel %#.4x: Got Disconnection Request",
763 local_cid());
764
765 // Unconnected channels only exist if they are waiting for a Connection
766 // Response from the peer or are disconnected yet undestroyed for some reason.
767 // Getting a Disconnection Request implies some error condition or misbehavior
768 // but the reaction should still be to terminate this channel.
769 if (!IsConnected()) {
770 bt_log(WARN,
771 "l2cap-bredr",
772 "Channel %#.4x: Unexpected Disconnection Request",
773 local_cid());
774 }
775
776 state_ |= kDisconnected;
777 responder->Send();
778 if (opened()) {
779 OnDisconnected();
780 } else {
781 PassOpenError();
782 }
783 }
784
CompleteInboundConnection(BrEdrCommandHandler::ConnectionResponder * responder)785 void BrEdrDynamicChannel::CompleteInboundConnection(
786 BrEdrCommandHandler::ConnectionResponder* responder) {
787 bt_log(DEBUG,
788 "l2cap-bredr",
789 "Channel %#.4x: connected for PSM %#.4x from remote channel %#.4x",
790 local_cid(),
791 psm(),
792 remote_cid());
793
794 responder->Send(local_cid(),
795 ConnectionResult::kSuccess,
796 ConnectionStatus::kNoInfoAvailable);
797 bt_log(TRACE,
798 "l2cap-bredr",
799 "Channel %#.4x: Sent Connection Response",
800 local_cid());
801 state_ |= kConnResponded;
802
803 UpdateLocalConfigForErtm();
804 if (!IsWaitingForPeerErtmSupport()) {
805 TrySendLocalConfig();
806 }
807 }
808
BrEdrDynamicChannel(DynamicChannelRegistry * registry,SignalingChannelInterface * signaling_channel,Psm psm,ChannelId local_cid,ChannelId remote_cid,ChannelParameters params,std::optional<bool> peer_supports_ertm)809 BrEdrDynamicChannel::BrEdrDynamicChannel(
810 DynamicChannelRegistry* registry,
811 SignalingChannelInterface* signaling_channel,
812 Psm psm,
813 ChannelId local_cid,
814 ChannelId remote_cid,
815 ChannelParameters params,
816 std::optional<bool> peer_supports_ertm)
817 : DynamicChannel(registry, psm, local_cid, remote_cid),
818 signaling_channel_(signaling_channel),
819 parameters_(params),
820 state_(0u),
821 peer_supports_ertm_(peer_supports_ertm),
822 weak_self_(this) {
823 BT_DEBUG_ASSERT(signaling_channel_);
824 BT_DEBUG_ASSERT(local_cid != kInvalidChannelId);
825
826 UpdateLocalConfigForErtm();
827 }
828
PassOpenResult()829 void BrEdrDynamicChannel::PassOpenResult() {
830 if (open_result_cb_) {
831 // Guard against use-after-free if this object's owner destroys it while
832 // running |open_result_cb_|.
833 auto cb = std::move(open_result_cb_);
834 cb();
835 }
836 }
837
838 // This only checks that the channel had failed to open before passing to the
839 // client. The channel may still be connected, in case it's useful to perform
840 // channel configuration at this point.
PassOpenError()841 void BrEdrDynamicChannel::PassOpenError() {
842 BT_ASSERT(!IsOpen());
843 PassOpenResult();
844 }
845
UpdateLocalConfigForErtm()846 void BrEdrDynamicChannel::UpdateLocalConfigForErtm() {
847 local_config_.set_mtu_option(
848 ChannelConfiguration::MtuOption(CalculateLocalMtu()));
849
850 if (ShouldRequestEnhancedRetransmission()) {
851 // Core Spec v5.0 Vol 3, Part A, Sec 8.6.2.1 "When configuring a channel
852 // over an ACL-U logical link the values sent in a Configuration Request
853 // packet for Retransmission timeout and Monitor timeout shall be 0."
854 auto option = ChannelConfiguration::RetransmissionAndFlowControlOption::
855 MakeEnhancedRetransmissionMode(
856 /*tx_window_size=*/kErtmMaxUnackedInboundFrames,
857 /*max_transmit=*/kErtmMaxInboundRetransmissions,
858 /*rtx_timeout=*/0,
859 /*monitor_timeout=*/0,
860 /*mps=*/kMaxInboundPduPayloadSize);
861 local_config_.set_retransmission_flow_control_option(option);
862 } else {
863 local_config_.set_retransmission_flow_control_option(
864 ChannelConfiguration::RetransmissionAndFlowControlOption::
865 MakeBasicMode());
866 }
867 }
868
CalculateLocalMtu() const869 uint16_t BrEdrDynamicChannel::CalculateLocalMtu() const {
870 const bool request_ertm = ShouldRequestEnhancedRetransmission();
871 const auto kDefaultPreferredMtu =
872 request_ertm ? kMaxInboundPduPayloadSize : kMaxMTU;
873 uint16_t mtu = parameters_.max_rx_sdu_size.value_or(kDefaultPreferredMtu);
874 if (mtu < kMinACLMTU) {
875 bt_log(WARN,
876 "l2cap-bredr",
877 "Channel %#.4x: preferred MTU channel parameter below minimum "
878 "allowed, using minimum "
879 "instead (mtu param: %#x, min mtu: %#x)",
880 local_cid(),
881 mtu,
882 kMinACLMTU);
883 mtu = kMinACLMTU;
884 }
885 if (request_ertm && mtu > kMaxInboundPduPayloadSize) {
886 bt_log(DEBUG,
887 "l2cap-bredr",
888 "Channel %#.4x: preferred MTU channel parameter above MPS; using "
889 "MPS instead to avoid "
890 "segmentation (mtu param: %#x, max pdu: %#x)",
891 local_cid(),
892 mtu,
893 kMaxInboundPduPayloadSize);
894 mtu = kMaxInboundPduPayloadSize;
895 }
896 return mtu;
897 }
898
ShouldRequestEnhancedRetransmission() const899 bool BrEdrDynamicChannel::ShouldRequestEnhancedRetransmission() const {
900 return parameters_.mode &&
901 *parameters_.mode ==
902 RetransmissionAndFlowControlMode::kEnhancedRetransmission &&
903 peer_supports_ertm_.value_or(false);
904 }
905
IsWaitingForPeerErtmSupport()906 bool BrEdrDynamicChannel::IsWaitingForPeerErtmSupport() {
907 const auto local_mode =
908 parameters_.mode.value_or(RetransmissionAndFlowControlMode::kBasic);
909 return !peer_supports_ertm_.has_value() &&
910 (local_mode != RetransmissionAndFlowControlMode::kBasic);
911 }
912
TrySendLocalConfig()913 void BrEdrDynamicChannel::TrySendLocalConfig() {
914 if (state_ & kLocalConfigSent) {
915 return;
916 }
917
918 BT_ASSERT(!IsWaitingForPeerErtmSupport());
919
920 SendLocalConfig();
921 }
922
SendLocalConfig()923 void BrEdrDynamicChannel::SendLocalConfig() {
924 auto on_config_rsp_timeout = [this, self = weak_self_.GetWeakPtr()] {
925 if (self.is_alive()) {
926 bt_log(WARN,
927 "l2cap-bredr",
928 "Channel %#.4x: Timed out waiting for Configuration Response",
929 local_cid());
930 PassOpenError();
931 }
932 };
933
934 BrEdrCommandHandler cmd_handler(signaling_channel_,
935 std::move(on_config_rsp_timeout));
936
937 auto request_config = local_config_;
938
939 // Don't send Retransmission & Flow Control option for basic mode
940 if (request_config.retransmission_flow_control_option()->mode() ==
941 RetransmissionAndFlowControlMode::kBasic) {
942 request_config.set_retransmission_flow_control_option(std::nullopt);
943 }
944
945 if (!request_config.retransmission_flow_control_option()) {
946 num_basic_config_requests_++;
947 }
948
949 if (!cmd_handler.SendConfigurationRequest(
950 remote_cid(),
951 0,
952 request_config.Options(),
953 [self = weak_self_.GetWeakPtr()](auto& rsp) {
954 if (self.is_alive()) {
955 return self->OnRxConfigRsp(rsp);
956 }
957 return ResponseHandlerAction::kCompleteOutboundTransaction;
958 })) {
959 bt_log(ERROR,
960 "l2cap-bredr",
961 "Channel %#.4x: Failed to send Configuration Request",
962 local_cid());
963 PassOpenError();
964 return;
965 }
966
967 bt_log(TRACE,
968 "l2cap-bredr",
969 "Channel %#.4x: Sent Configuration Request (options: %s)",
970 local_cid(),
971 bt_str(request_config));
972
973 state_ |= kLocalConfigSent;
974 }
975
BothConfigsAccepted() const976 bool BrEdrDynamicChannel::BothConfigsAccepted() const {
977 return (state_ & kLocalConfigAccepted) && (state_ & kRemoteConfigAccepted);
978 }
979
AcceptedChannelModesAreConsistent() const980 bool BrEdrDynamicChannel::AcceptedChannelModesAreConsistent() const {
981 BT_ASSERT(BothConfigsAccepted());
982 auto local_mode = local_config_.retransmission_flow_control_option()->mode();
983 auto remote_mode =
984 remote_config_.retransmission_flow_control_option()->mode();
985 return local_mode == remote_mode;
986 }
987
CheckForUnacceptableConfigReqOptions(const ChannelConfiguration & config) const988 ChannelConfiguration BrEdrDynamicChannel::CheckForUnacceptableConfigReqOptions(
989 const ChannelConfiguration& config) const {
990 // TODO(fxbug.dev/42115983): reject reconfiguring MTU if mode is Enhanced
991 // Retransmission or Streaming mode.
992 ChannelConfiguration unacceptable;
993
994 // Reject MTUs below minimum size
995 if (config.mtu_option()->mtu() < kMinACLMTU) {
996 bt_log(DEBUG,
997 "l2cap",
998 "Channel %#.4x: config request contains MTU below minimum (mtu: "
999 "%hu, min: %hu)",
1000 local_cid(),
1001 config.mtu_option()->mtu(),
1002 kMinACLMTU);
1003 // Respond back with a proposed MTU value of the required minimum (Core Spec
1004 // v5.1, Vol 3, Part A, Section 5.1: "It is implementation specific whether
1005 // the local device continues the configuration process or disconnects the
1006 // channel.")
1007 unacceptable.set_mtu_option(ChannelConfiguration::MtuOption(kMinACLMTU));
1008 }
1009
1010 const auto req_mode =
1011 config.retransmission_flow_control_option()
1012 ? config.retransmission_flow_control_option()->mode()
1013 : RetransmissionAndFlowControlMode::kBasic;
1014 const auto local_mode =
1015 local_config().retransmission_flow_control_option()->mode();
1016 switch (req_mode) {
1017 case RetransmissionAndFlowControlMode::kBasic:
1018 // Local device must accept, as basic mode has highest precedence.
1019 if (local_mode ==
1020 RetransmissionAndFlowControlMode::kEnhancedRetransmission) {
1021 bt_log(DEBUG,
1022 "l2cap-bredr",
1023 "Channel %#.4x: accepting peer basic mode configuration option "
1024 "when preferred mode "
1025 "was ERTM",
1026 local_cid());
1027 }
1028 break;
1029 case RetransmissionAndFlowControlMode::kEnhancedRetransmission:
1030 // Basic mode has highest precedence, so if local mode is basic, reject
1031 // ERTM and send local mode.
1032 if (local_mode == RetransmissionAndFlowControlMode::kBasic) {
1033 bt_log(DEBUG,
1034 "l2cap-bredr",
1035 "Channel %#.4x: rejecting peer ERTM mode configuration option "
1036 "because preferred "
1037 "mode is basic",
1038 local_cid());
1039 unacceptable.set_retransmission_flow_control_option(
1040 ChannelConfiguration::RetransmissionAndFlowControlOption::
1041 MakeBasicMode());
1042 break;
1043 }
1044 unacceptable.set_retransmission_flow_control_option(
1045 CheckForUnacceptableErtmOptions(config));
1046 break;
1047 default:
1048 bt_log(DEBUG,
1049 "l2cap-bredr",
1050 "Channel %#.4x: rejecting unsupported retransmission and flow "
1051 "control configuration "
1052 "option (mode: %#.2x)",
1053 local_cid(),
1054 static_cast<uint8_t>(req_mode));
1055
1056 // All other modes are lower precedence than what local device supports,
1057 // so send local mode.
1058 if (local_mode ==
1059 RetransmissionAndFlowControlMode::kEnhancedRetransmission) {
1060 // Retransmission & Flow Control fields for ERTM are not negotiable, so
1061 // do not propose acceptable values per Core Spec v5.0, Vol 3, Part A,
1062 // Sec 7.1.4.
1063 unacceptable.set_retransmission_flow_control_option(
1064 ChannelConfiguration::RetransmissionAndFlowControlOption::
1065 MakeEnhancedRetransmissionMode(
1066 /*tx_window_size=*/0,
1067 /*max_transmit=*/0,
1068 /*rtx_timeout=*/0,
1069 /*monitor_timeout=*/0,
1070 /*mps=*/0));
1071 } else {
1072 unacceptable.set_retransmission_flow_control_option(
1073 local_config().retransmission_flow_control_option());
1074 }
1075 }
1076
1077 return unacceptable;
1078 }
1079
1080 std::optional<ChannelConfiguration::RetransmissionAndFlowControlOption>
CheckForUnacceptableErtmOptions(const ChannelConfiguration & config) const1081 BrEdrDynamicChannel::CheckForUnacceptableErtmOptions(
1082 const ChannelConfiguration& config) const {
1083 BT_ASSERT(config.retransmission_flow_control_option()->mode() ==
1084 RetransmissionAndFlowControlMode::kEnhancedRetransmission);
1085 BT_ASSERT(local_config().retransmission_flow_control_option()->mode() ==
1086 RetransmissionAndFlowControlMode::kEnhancedRetransmission);
1087
1088 std::optional<ChannelConfiguration::RetransmissionAndFlowControlOption>
1089 unacceptable_rfc_option;
1090 const auto& peer_rfc_option =
1091 config.retransmission_flow_control_option().value();
1092
1093 // TxWindow has a range of 1 to 63 (Core Spec v5.0, Vol 3, Part A, Sec 5.4).
1094 if (peer_rfc_option.tx_window_size() < kErtmMinUnackedInboundFrames) {
1095 bt_log(DEBUG,
1096 "l2cap-bredr",
1097 "Channel %#.4x: rejecting too-small ERTM TxWindow of %hhu",
1098 local_cid(),
1099 peer_rfc_option.tx_window_size());
1100 unacceptable_rfc_option = unacceptable_rfc_option.value_or(peer_rfc_option);
1101 unacceptable_rfc_option->set_tx_window_size(kErtmMinUnackedInboundFrames);
1102 } else if (peer_rfc_option.tx_window_size() > kErtmMaxUnackedInboundFrames) {
1103 bt_log(DEBUG,
1104 "l2cap-bredr",
1105 "Channel %#.4x: rejecting too-small ERTM TxWindow of %hhu",
1106 local_cid(),
1107 peer_rfc_option.tx_window_size());
1108 unacceptable_rfc_option = unacceptable_rfc_option.value_or(peer_rfc_option);
1109 unacceptable_rfc_option->set_tx_window_size(kErtmMaxUnackedInboundFrames);
1110 }
1111
1112 // NOTE(fxbug.dev/42054330): MPS must be large enough to fit the largest SDU
1113 // in the minimum MTU case, because ERTM does not segment in the outbound
1114 // direction.
1115 if (peer_rfc_option.mps() < kMinACLMTU) {
1116 bt_log(DEBUG,
1117 "l2cap-bredr",
1118 "Channel %#.4x: rejecting too-small ERTM MPS of %hu",
1119 local_cid(),
1120 peer_rfc_option.mps());
1121 unacceptable_rfc_option = unacceptable_rfc_option.value_or(peer_rfc_option);
1122 unacceptable_rfc_option->set_mps(kMinACLMTU);
1123 }
1124
1125 return unacceptable_rfc_option;
1126 }
1127
TryRecoverFromUnacceptableParametersConfigRsp(const ChannelConfiguration & rsp_config)1128 bool BrEdrDynamicChannel::TryRecoverFromUnacceptableParametersConfigRsp(
1129 const ChannelConfiguration& rsp_config) {
1130 // Check if channel mode was unacceptable.
1131 if (rsp_config.retransmission_flow_control_option()) {
1132 // Check if peer rejected basic mode. Do not disconnect, in case peer will
1133 // accept resending basic mode (as is the case with PTS test
1134 // L2CAP/COS/CFD/BV-02-C).
1135 if (local_config().retransmission_flow_control_option()->mode() ==
1136 RetransmissionAndFlowControlMode::kBasic) {
1137 bt_log(WARN,
1138 "l2cap-bredr",
1139 "Channel %#.4x: Peer rejected basic mode with unacceptable "
1140 "parameters result (rsp mode: %#.2x)",
1141 local_cid(),
1142 static_cast<uint8_t>(
1143 rsp_config.retransmission_flow_control_option()->mode()));
1144 }
1145
1146 // Core Spec v5.1, Vol 3, Part A, Sec 5.4:
1147 // If the mode in the remote device's negative Configuration Response does
1148 // not match the mode in the remote device's Configuration Request then the
1149 // local device shall disconnect the channel.
1150 if (state_ & kRemoteConfigAccepted) {
1151 const auto rsp_mode =
1152 rsp_config.retransmission_flow_control_option()->mode();
1153 const auto remote_mode =
1154 remote_config_.retransmission_flow_control_option()->mode();
1155 if (rsp_mode != remote_mode) {
1156 bt_log(ERROR,
1157 "l2cap-bredr",
1158 "Channel %#.4x: Unsuccessful config: mode in unacceptable "
1159 "parameters config "
1160 "response does not match mode in remote config request (rsp "
1161 "mode: %#.2x, req mode: "
1162 "%#.2x)",
1163 local_cid(),
1164 static_cast<uint8_t>(rsp_mode),
1165 static_cast<uint8_t>(remote_mode));
1166 return false;
1167 }
1168 }
1169
1170 bt_log(TRACE,
1171 "l2cap-bredr",
1172 "Channel %#.4x: Attempting to recover from unacceptable parameters "
1173 "config response by "
1174 "falling back to basic mode and resending config request",
1175 local_cid());
1176
1177 // Fall back to basic mode and try sending config again up to
1178 // kMaxNumBasicConfigRequests times
1179 peer_supports_ertm_ = false;
1180 if (num_basic_config_requests_ == kMaxNumBasicConfigRequests) {
1181 bt_log(WARN,
1182 "l2cap-bredr",
1183 "Channel %#.4x: Peer rejected config request. Channel's limit of "
1184 "%#.2x basic mode config request attempts has been met",
1185 local_cid(),
1186 kMaxNumBasicConfigRequests);
1187 return false;
1188 }
1189 UpdateLocalConfigForErtm();
1190 SendLocalConfig();
1191 return true;
1192 }
1193
1194 // Other unacceptable parameters cannot be recovered from.
1195 bt_log(WARN,
1196 "l2cap-bredr",
1197 "Channel %#.4x: Unsuccessful config: could not recover from "
1198 "unacceptable parameters config "
1199 "response",
1200 local_cid());
1201 return false;
1202 }
1203
OnRxConnRsp(const BrEdrCommandHandler::ConnectionResponse & rsp)1204 BrEdrDynamicChannel::ResponseHandlerAction BrEdrDynamicChannel::OnRxConnRsp(
1205 const BrEdrCommandHandler::ConnectionResponse& rsp) {
1206 if (rsp.status() == BrEdrCommandHandler::Status::kReject) {
1207 bt_log(ERROR,
1208 "l2cap-bredr",
1209 "Channel %#.4x: Connection Request rejected reason %#.4hx",
1210 local_cid(),
1211 static_cast<unsigned short>(rsp.reject_reason()));
1212 PassOpenError();
1213 return ResponseHandlerAction::kCompleteOutboundTransaction;
1214 }
1215
1216 if (rsp.local_cid() != local_cid()) {
1217 bt_log(
1218 ERROR,
1219 "l2cap-bredr",
1220 "Channel %#.4x: Got Connection Response for another channel ID %#.4x",
1221 local_cid(),
1222 rsp.local_cid());
1223 PassOpenError();
1224 return ResponseHandlerAction::kCompleteOutboundTransaction;
1225 }
1226
1227 if ((state_ & kConnResponded) || !(state_ & kConnRequested)) {
1228 bt_log(ERROR,
1229 "l2cap-bredr",
1230 "Channel %#.4x: Unexpected Connection Response, state %#x",
1231 local_cid(),
1232 state_);
1233 PassOpenError();
1234 return ResponseHandlerAction::kCompleteOutboundTransaction;
1235 }
1236
1237 if (rsp.result() == ConnectionResult::kPending) {
1238 bt_log(TRACE,
1239 "l2cap-bredr",
1240 "Channel %#.4x: Remote is pending open, status %#.4hx",
1241 local_cid(),
1242 static_cast<unsigned short>(rsp.conn_status()));
1243
1244 if (rsp.remote_cid() == kInvalidChannelId) {
1245 return ResponseHandlerAction::kExpectAdditionalResponse;
1246 }
1247
1248 // If the remote provides a channel ID, then we store it. It can be used for
1249 // disconnection from this point forward.
1250 if (!SetRemoteChannelId(rsp.remote_cid())) {
1251 bt_log(ERROR,
1252 "l2cap-bredr",
1253 "Channel %#.4x: Remote channel ID %#.4x is not unique",
1254 local_cid(),
1255 rsp.remote_cid());
1256 PassOpenError();
1257 return ResponseHandlerAction::kCompleteOutboundTransaction;
1258 }
1259
1260 bt_log(TRACE,
1261 "l2cap-bredr",
1262 "Channel %#.4x: Got remote channel ID %#.4x",
1263 local_cid(),
1264 remote_cid());
1265 return ResponseHandlerAction::kExpectAdditionalResponse;
1266 }
1267
1268 if (rsp.result() != ConnectionResult::kSuccess) {
1269 bt_log(ERROR,
1270 "l2cap-bredr",
1271 "Channel %#.4x: Unsuccessful Connection Response result %#.4hx, "
1272 "status %#.4x",
1273 local_cid(),
1274 static_cast<unsigned short>(rsp.result()),
1275 static_cast<unsigned int>(rsp.status()));
1276 PassOpenError();
1277 return ResponseHandlerAction::kCompleteOutboundTransaction;
1278 }
1279
1280 if (rsp.remote_cid() < kFirstDynamicChannelId) {
1281 bt_log(ERROR,
1282 "l2cap-bredr",
1283 "Channel %#.4x: received Connection Response with invalid channel "
1284 "ID %#.4x, disconnecting",
1285 local_cid(),
1286 remote_cid());
1287
1288 // This results in sending a Disconnection Request for non-zero remote IDs,
1289 // which is probably what we want because there's no other way to send back
1290 // a failure in this case.
1291 PassOpenError();
1292 return ResponseHandlerAction::kCompleteOutboundTransaction;
1293 }
1294
1295 // TODO(xow): To be stricter, we can disconnect if the remote ID changes on us
1296 // during connection like this, but not sure if that would be beneficial.
1297 if (remote_cid() != kInvalidChannelId && remote_cid() != rsp.remote_cid()) {
1298 bt_log(WARN,
1299 "l2cap-bredr",
1300 "Channel %#.4x: using new remote ID %#.4x after previous Connection "
1301 "Response provided %#.4x",
1302 local_cid(),
1303 rsp.remote_cid(),
1304 remote_cid());
1305 }
1306
1307 state_ |= kConnResponded;
1308
1309 if (!SetRemoteChannelId(rsp.remote_cid())) {
1310 bt_log(ERROR,
1311 "l2cap-bredr",
1312 "Channel %#.4x: Remote channel ID %#.4x is not unique",
1313 local_cid(),
1314 rsp.remote_cid());
1315 PassOpenError();
1316 return ResponseHandlerAction::kCompleteOutboundTransaction;
1317 }
1318
1319 bt_log(TRACE,
1320 "l2cap-bredr",
1321 "Channel %#.4x: Got remote channel ID %#.4x",
1322 local_cid(),
1323 rsp.remote_cid());
1324
1325 UpdateLocalConfigForErtm();
1326 if (!IsWaitingForPeerErtmSupport()) {
1327 TrySendLocalConfig();
1328 }
1329 return ResponseHandlerAction::kCompleteOutboundTransaction;
1330 }
1331
OnRxConfigRsp(const BrEdrCommandHandler::ConfigurationResponse & rsp)1332 BrEdrDynamicChannel::ResponseHandlerAction BrEdrDynamicChannel::OnRxConfigRsp(
1333 const BrEdrCommandHandler::ConfigurationResponse& rsp) {
1334 if (rsp.status() == BrEdrCommandHandler::Status::kReject) {
1335 bt_log(ERROR,
1336 "l2cap-bredr",
1337 "Channel %#.4x: Configuration Request rejected, reason %#.4hx, "
1338 "disconnecting",
1339 local_cid(),
1340 static_cast<unsigned short>(rsp.reject_reason()));
1341
1342 // Configuration Request being rejected is fatal because the remote is not
1343 // trying to negotiate parameters (any more).
1344 PassOpenError();
1345 return ResponseHandlerAction::kCompleteOutboundTransaction;
1346 }
1347
1348 // Pending responses may contain return values and adjustments to
1349 // non-negotiated values.
1350 if (rsp.result() == ConfigurationResult::kPending) {
1351 bt_log(TRACE,
1352 "l2cap-bredr",
1353 "Channel %#.4x: remote pending config (options: %s)",
1354 local_cid(),
1355 bt_str(rsp.config()));
1356
1357 if (rsp.config().mtu_option()) {
1358 local_config_.set_mtu_option(rsp.config().mtu_option());
1359 }
1360
1361 return ResponseHandlerAction::kExpectAdditionalResponse;
1362 }
1363
1364 if (rsp.result() == ConfigurationResult::kUnacceptableParameters) {
1365 bt_log(DEBUG,
1366 "l2cap-bredr",
1367 "Channel %#.4x: Received unacceptable parameters config response "
1368 "(options: %s)",
1369 local_cid(),
1370 bt_str(rsp.config()));
1371
1372 if (!TryRecoverFromUnacceptableParametersConfigRsp(rsp.config())) {
1373 PassOpenError();
1374 }
1375 return ResponseHandlerAction::kCompleteOutboundTransaction;
1376 }
1377
1378 if (rsp.result() != ConfigurationResult::kSuccess) {
1379 bt_log(ERROR,
1380 "l2cap-bredr",
1381 "Channel %#.4x: unsuccessful config (result: %#.4hx, options: %s)",
1382 local_cid(),
1383 static_cast<unsigned short>(rsp.result()),
1384 bt_str(rsp.config()));
1385 PassOpenError();
1386 return ResponseHandlerAction::kCompleteOutboundTransaction;
1387 }
1388
1389 if (rsp.local_cid() != local_cid()) {
1390 bt_log(ERROR,
1391 "l2cap-bredr",
1392 "Channel %#.4x: dropping Configuration Response for %#.4x",
1393 local_cid(),
1394 rsp.local_cid());
1395 PassOpenError();
1396 return ResponseHandlerAction::kCompleteOutboundTransaction;
1397 }
1398
1399 state_ |= kLocalConfigAccepted;
1400
1401 bt_log(TRACE,
1402 "l2cap-bredr",
1403 "Channel %#.4x: Got Configuration Response (options: %s)",
1404 local_cid(),
1405 bt_str(rsp.config()));
1406
1407 if (rsp.config().mtu_option()) {
1408 local_config_.set_mtu_option(rsp.config().mtu_option());
1409 }
1410
1411 if (BothConfigsAccepted() && !AcceptedChannelModesAreConsistent()) {
1412 bt_log(WARN,
1413 "l2cap-bredr",
1414 "Channel %#.4x: inconsistent channel mode negotiation (local mode: "
1415 "%#.2x, remote "
1416 "mode: %#.2x); falling back to Basic Mode",
1417 local_cid(),
1418 static_cast<uint8_t>(
1419 local_config().retransmission_flow_control_option()->mode()),
1420 static_cast<uint8_t>(
1421 remote_config().retransmission_flow_control_option()->mode()));
1422
1423 // See spec justification in OnRxConfigReq.
1424 local_config_.set_retransmission_flow_control_option(
1425 ChannelConfiguration::RetransmissionAndFlowControlOption::
1426 MakeBasicMode());
1427 remote_config_.set_retransmission_flow_control_option(
1428 ChannelConfiguration::RetransmissionAndFlowControlOption::
1429 MakeBasicMode());
1430 PassOpenResult();
1431 return ResponseHandlerAction::kCompleteOutboundTransaction;
1432 }
1433
1434 if (IsOpen()) {
1435 set_opened();
1436 PassOpenResult();
1437 }
1438
1439 return ResponseHandlerAction::kCompleteOutboundTransaction;
1440 }
1441
SetEnhancedRetransmissionSupport(bool supported)1442 void BrEdrDynamicChannel::SetEnhancedRetransmissionSupport(bool supported) {
1443 peer_supports_ertm_ = supported;
1444
1445 UpdateLocalConfigForErtm();
1446
1447 // Don't send local config before connection response.
1448 if (state_ & kConnResponded) {
1449 TrySendLocalConfig();
1450 }
1451 }
1452
1453 } // namespace bt::l2cap::internal
1454