• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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