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