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