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