xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/l2cap/dynamic_channel_registry_test.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/dynamic_channel_registry.h"
16 
17 #include "pw_unit_test/framework.h"
18 
19 namespace bt::l2cap::internal {
20 namespace {
21 
22 constexpr uint16_t kNumChannelsAllowed = 256;
23 constexpr uint16_t kPsm = 0x0001;
24 constexpr ChannelId kRemoteCId = 0x60a3;
25 constexpr ChannelParameters kChannelParams;
26 
27 class FakeDynamicChannel final : public DynamicChannel {
28  public:
FakeDynamicChannel(DynamicChannelRegistry * registry,Psm psm,ChannelId local_cid,ChannelId remote_cid)29   FakeDynamicChannel(DynamicChannelRegistry* registry,
30                      Psm psm,
31                      ChannelId local_cid,
32                      ChannelId remote_cid)
33       : DynamicChannel(registry, psm, local_cid, remote_cid) {}
34 
35   // DynamicChannel overrides
IsConnected() const36   bool IsConnected() const override { return connected_; }
IsOpen() const37   bool IsOpen() const override { return open_; }
38 
info() const39   ChannelInfo info() const override {
40     return ChannelInfo::MakeBasicMode(kDefaultMTU, kDefaultMTU);
41   }
42 
DoConnect(ChannelId remote_cid)43   void DoConnect(ChannelId remote_cid) {
44     ASSERT_TRUE(SetRemoteChannelId(remote_cid))
45         << "Could not set non-unique remote_cid " << remote_cid;
46     connected_ = true;
47   }
48 
DoOpen(bool new_open=true)49   void DoOpen(bool new_open = true) {
50     open_ = new_open;
51     if (new_open) {
52       set_opened();
53     }
54     open_result_cb_();
55   }
56 
DoRemoteClose()57   void DoRemoteClose() {
58     open_ = false;
59     connected_ = false;
60     OnDisconnected();
61   }
62 
63   // After calling |set_defer_disconnect_callback|, this returns the callback
64   // passed to |Disconnect|, or an empty callback if |Disconnect| hasn't been
65   // called.
disconnect_done_callback()66   DisconnectDoneCallback& disconnect_done_callback() {
67     return disconnect_done_callback_;
68   }
69 
set_defer_disconnect_done_callback()70   void set_defer_disconnect_done_callback() {
71     defer_disconnect_done_callback_ = true;
72   }
73 
74  private:
75   // DynamicChannel overrides
Open(fit::closure open_result_cb)76   void Open(fit::closure open_result_cb) override {
77     open_result_cb_ = std::move(open_result_cb);
78   }
Disconnect(DisconnectDoneCallback done_cb)79   void Disconnect(DisconnectDoneCallback done_cb) override {
80     open_ = false;
81     connected_ = false;
82 
83     bt_log(DEBUG,
84            "l2cap",
85            "Got Disconnect %#.4x callback: %d",
86            local_cid(),
87            psm());
88 
89     ASSERT_FALSE(disconnect_done_callback_);
90     if (defer_disconnect_done_callback_) {
91       disconnect_done_callback_ = std::move(done_cb);
92     } else {
93       done_cb();
94     }
95   }
96 
97   fit::closure open_result_cb_;
98   DisconnectDoneCallback disconnect_done_callback_;
99 
100   // If true, the Disconnect call does not immediately signal its callback. The
101   // test will have to call it explicitly with |disconnect_callback()|.
102   bool defer_disconnect_done_callback_ = false;
103 
104   bool connected_ = false;
105   bool open_ = false;
106 };
107 
108 // Fake registry subclass for testing inherited logic. Stubs out |MakeOutbound|
109 // to vend FakeDynamicChannels.
110 class TestDynamicChannelRegistry final : public DynamicChannelRegistry {
111  public:
TestDynamicChannelRegistry(DynamicChannelCallback close_cb,ServiceRequestCallback service_request_cb)112   TestDynamicChannelRegistry(DynamicChannelCallback close_cb,
113                              ServiceRequestCallback service_request_cb)
114       : DynamicChannelRegistry(kNumChannelsAllowed,
115                                std::move(close_cb),
116                                std::move(service_request_cb),
117                                /*random_channel_ids=*/true) {}
118 
119   // Returns previous channel created.
last_channel()120   FakeDynamicChannel* last_channel() { return last_channel_; }
121 
122   // Make public for testing.
123   using DynamicChannelRegistry::AliveChannelCount;
124   using DynamicChannelRegistry::FindAvailableChannelId;
125   using DynamicChannelRegistry::FindChannelByLocalId;
126   using DynamicChannelRegistry::FindChannelByRemoteId;
127   using DynamicChannelRegistry::ForEach;
128   using DynamicChannelRegistry::RequestService;
129 
130  private:
131   // DynamicChannelRegistry overrides
MakeOutbound(Psm psm,ChannelId local_cid,ChannelParameters)132   DynamicChannelPtr MakeOutbound(Psm psm,
133                                  ChannelId local_cid,
134                                  ChannelParameters) override {
135     return MakeChannelInternal(psm, local_cid, kInvalidChannelId);
136   }
137 
MakeInbound(Psm psm,ChannelId local_cid,ChannelId remote_cid,ChannelParameters)138   DynamicChannelPtr MakeInbound(Psm psm,
139                                 ChannelId local_cid,
140                                 ChannelId remote_cid,
141                                 ChannelParameters) override {
142     auto channel = MakeChannelInternal(psm, local_cid, remote_cid);
143     channel->DoConnect(remote_cid);
144     return channel;
145   }
146 
MakeChannelInternal(Psm psm,ChannelId local_cid,ChannelId remote_cid)147   std::unique_ptr<FakeDynamicChannel> MakeChannelInternal(
148       Psm psm, ChannelId local_cid, ChannelId remote_cid) {
149     auto channel =
150         std::make_unique<FakeDynamicChannel>(this, psm, local_cid, remote_cid);
151     last_channel_ = channel.get();
152     return channel;
153   }
154 
155   FakeDynamicChannel* last_channel_ = nullptr;
156 };
157 
158 // DynamicChannelCallback static handler
DoNothing(const DynamicChannel *)159 void DoNothing(const DynamicChannel*) {}
160 
161 // ServiceRequestCallback static handler
RejectAllServices(Psm)162 std::optional<DynamicChannelRegistry::ServiceInfo> RejectAllServices(
163     Psm /*psm*/) {
164   return std::nullopt;
165 }
166 
TEST(DynamicChannelRegistryTest,OpenAndRemoteCloseChannel)167 TEST(DynamicChannelRegistryTest, OpenAndRemoteCloseChannel) {
168   ChannelId local_cid = kInvalidChannelId;
169   ChannelId remote_cid = kInvalidChannelId;
170   bool close_cb_called = false;
171   auto close_cb = [&](const DynamicChannel* chan) {
172     EXPECT_FALSE(close_cb_called);
173     close_cb_called = true;
174     EXPECT_TRUE(chan);
175     EXPECT_FALSE(chan->IsConnected());
176     EXPECT_FALSE(chan->IsOpen());
177     EXPECT_EQ(local_cid, chan->local_cid());
178     EXPECT_EQ(remote_cid, chan->remote_cid());
179   };
180 
181   TestDynamicChannelRegistry registry(std::move(close_cb), RejectAllServices);
182   EXPECT_NE(kInvalidChannelId, registry.FindAvailableChannelId());
183 
184   bool open_result_cb_called = false;
185   auto open_result_cb = [&](const DynamicChannel* chan) {
186     EXPECT_FALSE(open_result_cb_called);
187     open_result_cb_called = true;
188     EXPECT_TRUE(chan);
189     EXPECT_EQ(kPsm, chan->psm());
190     local_cid = chan->local_cid();
191     remote_cid = chan->remote_cid();
192   };
193 
194   registry.OpenOutbound(kPsm, kChannelParams, std::move(open_result_cb));
195   registry.last_channel()->DoConnect(kRemoteCId);
196   registry.last_channel()->DoOpen();
197 
198   EXPECT_TRUE(open_result_cb_called);
199   EXPECT_FALSE(close_cb_called);
200   auto channel_by_local_id = registry.FindChannelByLocalId(local_cid);
201   auto channel_by_remote_id = registry.FindChannelByRemoteId(remote_cid);
202   EXPECT_TRUE(channel_by_local_id);
203   EXPECT_TRUE(channel_by_remote_id);
204   EXPECT_EQ(channel_by_local_id, channel_by_remote_id);
205 
206   registry.last_channel()->DoRemoteClose();
207   EXPECT_TRUE(close_cb_called);
208   EXPECT_FALSE(registry.FindChannelByLocalId(local_cid));
209   EXPECT_FALSE(registry.FindChannelByRemoteId(remote_cid));
210 }
211 
TEST(DynamicChannelRegistryTest,OpenAndLocalCloseChannel)212 TEST(DynamicChannelRegistryTest, OpenAndLocalCloseChannel) {
213   bool registry_close_cb_called = false;
214   auto registry_close_cb = [&](const DynamicChannel*) {
215     registry_close_cb_called = true;
216   };
217 
218   TestDynamicChannelRegistry registry(std::move(registry_close_cb),
219                                       RejectAllServices);
220 
221   bool open_result_cb_called = false;
222   ChannelId local_cid = kInvalidChannelId;
223   auto open_result_cb = [&](const DynamicChannel* chan) {
224     EXPECT_FALSE(open_result_cb_called);
225     open_result_cb_called = true;
226     EXPECT_TRUE(chan);
227     local_cid = chan->local_cid();
228   };
229 
230   registry.OpenOutbound(kPsm, kChannelParams, std::move(open_result_cb));
231   registry.last_channel()->DoConnect(kRemoteCId);
232   registry.last_channel()->DoOpen();
233 
234   EXPECT_TRUE(open_result_cb_called);
235   EXPECT_TRUE(registry.FindChannelByLocalId(local_cid));
236 
237   bool close_cb_called = false;
238   registry.CloseChannel(local_cid, [&] { close_cb_called = true; });
239   EXPECT_FALSE(registry_close_cb_called);
240   EXPECT_TRUE(close_cb_called);
241   EXPECT_FALSE(registry.FindChannelByLocalId(local_cid));
242 }
243 
TEST(DynamicChannelRegistryTest,RejectServiceRequest)244 TEST(DynamicChannelRegistryTest, RejectServiceRequest) {
245   bool service_request_cb_called = false;
246   auto service_request_cb = [&service_request_cb_called](Psm psm) {
247     EXPECT_FALSE(service_request_cb_called);
248     EXPECT_EQ(kPsm, psm);
249     service_request_cb_called = true;
250     return std::nullopt;
251   };
252 
253   TestDynamicChannelRegistry registry(DoNothing, std::move(service_request_cb));
254 
255   registry.RequestService(kPsm, registry.FindAvailableChannelId(), kRemoteCId);
256   EXPECT_TRUE(service_request_cb_called);
257   EXPECT_FALSE(registry.last_channel());
258 }
259 
TEST(DynamicChannelRegistryTest,AcceptServiceRequestThenOpenOk)260 TEST(DynamicChannelRegistryTest, AcceptServiceRequestThenOpenOk) {
261   bool open_result_cb_called = false;
262   ChannelId local_cid = kInvalidChannelId;
263   ChannelId remote_cid = kInvalidChannelId;
264   DynamicChannelRegistry::DynamicChannelCallback open_result_cb =
265       [&](const DynamicChannel* chan) {
266         EXPECT_FALSE(open_result_cb_called);
267         open_result_cb_called = true;
268         EXPECT_TRUE(chan);
269         EXPECT_EQ(kPsm, chan->psm());
270         local_cid = chan->local_cid();
271         remote_cid = chan->remote_cid();
272       };
273 
274   bool service_request_cb_called = false;
275   auto service_request_cb = [&service_request_cb_called,
276                              open_result_cb =
277                                  std::move(open_result_cb)](Psm psm) mutable {
278     EXPECT_FALSE(service_request_cb_called);
279     EXPECT_EQ(kPsm, psm);
280     service_request_cb_called = true;
281     return DynamicChannelRegistry::ServiceInfo{ChannelParameters(),
282                                                open_result_cb.share()};
283   };
284 
285   TestDynamicChannelRegistry registry(DoNothing, std::move(service_request_cb));
286 
287   registry.RequestService(kPsm, registry.FindAvailableChannelId(), kRemoteCId);
288   EXPECT_TRUE(service_request_cb_called);
289   ASSERT_TRUE(registry.last_channel());
290   registry.last_channel()->DoOpen();
291 
292   EXPECT_TRUE(open_result_cb_called);
293   EXPECT_NE(kInvalidChannelId, local_cid);
294   EXPECT_NE(kInvalidChannelId, remote_cid);
295   EXPECT_TRUE(registry.FindChannelByLocalId(local_cid));
296 
297   bool close_cb_called = false;
298   registry.CloseChannel(local_cid, [&] { close_cb_called = true; });
299   EXPECT_TRUE(close_cb_called);
300   EXPECT_FALSE(registry.FindChannelByLocalId(local_cid));
301 }
302 
TEST(DynamicChannelRegistryTest,AcceptServiceRequestThenOpenFails)303 TEST(DynamicChannelRegistryTest, AcceptServiceRequestThenOpenFails) {
304   bool open_result_cb_called = false;
305   DynamicChannelRegistry::DynamicChannelCallback open_result_cb =
306       [&open_result_cb_called](const DynamicChannel*) {
307         open_result_cb_called = true;
308       };
309 
310   bool service_request_cb_called = false;
311   auto service_request_cb = [&service_request_cb_called,
312                              open_result_cb =
313                                  std::move(open_result_cb)](Psm psm) mutable {
314     EXPECT_FALSE(service_request_cb_called);
315     EXPECT_EQ(kPsm, psm);
316     service_request_cb_called = true;
317     return DynamicChannelRegistry::ServiceInfo{ChannelParameters(),
318                                                open_result_cb.share()};
319   };
320 
321   TestDynamicChannelRegistry registry(DoNothing, std::move(service_request_cb));
322 
323   ChannelId local_cid = registry.FindAvailableChannelId();
324   EXPECT_NE(kInvalidChannelId, local_cid);
325   registry.RequestService(kPsm, local_cid, kRemoteCId);
326   EXPECT_TRUE(service_request_cb_called);
327   ASSERT_TRUE(registry.last_channel());
328   registry.last_channel()->DoOpen(false);
329 
330   // Don't get channels that failed to open.
331   EXPECT_FALSE(open_result_cb_called);
332   EXPECT_FALSE(registry.FindChannelByLocalId(local_cid));
333 
334   // The channel should be released upon this failure.
335   EXPECT_EQ(0u, registry.AliveChannelCount());
336 }
337 
TEST(DynamicChannelRegistryTest,DestroyRegistryWithOpenChannelNoDisconnectionRequest)338 TEST(DynamicChannelRegistryTest,
339      DestroyRegistryWithOpenChannelNoDisconnectionRequest) {
340   bool close_cb_called = false;
341   auto close_cb = [&close_cb_called](const DynamicChannel*) {
342     close_cb_called = true;
343   };
344 
345   TestDynamicChannelRegistry registry(std::move(close_cb), RejectAllServices);
346 
347   bool open_result_cb_called = false;
348   auto open_result_cb = [&open_result_cb_called](const DynamicChannel* chan) {
349     EXPECT_FALSE(open_result_cb_called);
350     open_result_cb_called = true;
351     EXPECT_TRUE(chan);
352   };
353 
354   registry.OpenOutbound(kPsm, kChannelParams, std::move(open_result_cb));
355   registry.last_channel()->DoConnect(kRemoteCId);
356   registry.last_channel()->DoOpen();
357 
358   EXPECT_TRUE(open_result_cb_called);
359   EXPECT_TRUE(registry.FindChannelByRemoteId(kRemoteCId));
360   EXPECT_FALSE(close_cb_called);
361 }
362 
TEST(DynamicChannelRegistryTest,ErrorConnectingChannel)363 TEST(DynamicChannelRegistryTest, ErrorConnectingChannel) {
364   bool open_result_cb_called = false;
365   auto open_result_cb = [&open_result_cb_called](const DynamicChannel* chan) {
366     EXPECT_FALSE(open_result_cb_called);
367     open_result_cb_called = true;
368     EXPECT_FALSE(chan);
369   };
370   bool close_cb_called = false;
371   auto close_cb = [&close_cb_called](auto) { close_cb_called = true; };
372 
373   TestDynamicChannelRegistry registry(std::move(close_cb), RejectAllServices);
374 
375   registry.OpenOutbound(kPsm, kChannelParams, std::move(open_result_cb));
376   registry.last_channel()->DoOpen(false);
377 
378   EXPECT_TRUE(open_result_cb_called);
379   EXPECT_FALSE(close_cb_called);
380 
381   // Should be no alive channels anymore.
382   EXPECT_EQ(0u, registry.AliveChannelCount());
383 }
384 
TEST(DynamicChannelRegistryTest,ExhaustedChannelIds)385 TEST(DynamicChannelRegistryTest, ExhaustedChannelIds) {
386   int open_result_cb_count = 0;
387 
388   // This callback expects the channel to be creatable.
389   DynamicChannelRegistry::DynamicChannelCallback success_open_result_cb =
390       [&open_result_cb_count](const DynamicChannel* chan) {
391         ASSERT_NE(nullptr, chan);
392         EXPECT_NE(kInvalidChannelId, chan->local_cid());
393         open_result_cb_count++;
394       };
395 
396   int close_cb_count = 0;
397   auto close_cb = [&close_cb_count](auto) { close_cb_count++; };
398 
399   TestDynamicChannelRegistry registry(std::move(close_cb), RejectAllServices);
400 
401   // Open a lot of channels.
402   for (ChannelId i = 0; i < kNumChannelsAllowed; i++) {
403     registry.OpenOutbound(
404         kPsm + i, kChannelParams, success_open_result_cb.share());
405     registry.last_channel()->DoConnect(kRemoteCId + i);
406     registry.last_channel()->DoOpen();
407   }
408   EXPECT_EQ(kNumChannelsAllowed, open_result_cb_count);
409   EXPECT_EQ(0, close_cb_count);
410 
411   // Ensure that channel IDs are exhausted.
412   EXPECT_EQ(kInvalidChannelId, registry.FindAvailableChannelId());
413 
414   // This callback expects the channel to fail creation.
415   auto fail_open_result_cb =
416       [&open_result_cb_count](const DynamicChannel* chan) {
417         EXPECT_FALSE(chan);
418         open_result_cb_count++;
419       };
420 
421   // Try to open a new channel.
422   registry.OpenOutbound(kPsm, kChannelParams, std::move(fail_open_result_cb));
423   EXPECT_EQ(kNumChannelsAllowed + 1, open_result_cb_count);
424   EXPECT_EQ(0, close_cb_count);
425 
426   // Close the most recently opened channel.
427   auto last_remote_cid = registry.last_channel()->remote_cid();
428   registry.last_channel()->DoRemoteClose();
429   EXPECT_EQ(1, close_cb_count);
430   EXPECT_NE(kInvalidChannelId, registry.FindAvailableChannelId());
431 
432   // Try to open a channel again.
433   registry.OpenOutbound(kPsm, kChannelParams, success_open_result_cb.share());
434   registry.last_channel()->DoConnect(last_remote_cid);
435   registry.last_channel()->DoOpen();
436   EXPECT_EQ(kNumChannelsAllowed + 2, open_result_cb_count);
437   EXPECT_EQ(1, close_cb_count);
438 
439   ChannelId last_local_cid = registry.last_channel()->local_cid();
440 
441   int close_cb_called = 0;
442   for (ChannelId i = 0; i < kNumChannelsAllowed; i++) {
443     registry.CloseChannel(kFirstDynamicChannelId + i,
444                           [&] { close_cb_called++; });
445   }
446   EXPECT_EQ(close_cb_called, kNumChannelsAllowed);
447   EXPECT_FALSE(registry.FindChannelByLocalId(last_local_cid));
448 }
449 
TEST(DynamicChannelRegistryTest,ChannelIdNotReusedUntilDisconnectionCompletes)450 TEST(DynamicChannelRegistryTest,
451      ChannelIdNotReusedUntilDisconnectionCompletes) {
452   TestDynamicChannelRegistry registry(DoNothing, RejectAllServices);
453 
454   // This callback expects the channel to be creatable.
455   int open_result_cb_count = 0;
456   DynamicChannelRegistry::DynamicChannelCallback success_open_result_cb =
457       [&](const DynamicChannel* chan) {
458         ASSERT_NE(nullptr, chan);
459         EXPECT_NE(kInvalidChannelId, chan->local_cid());
460         open_result_cb_count++;
461       };
462 
463   // Open all but one of the available channels.
464   for (ChannelId i = 0; i < kNumChannelsAllowed - 1; i++) {
465     registry.OpenOutbound(
466         kPsm + i, kChannelParams, success_open_result_cb.share());
467     registry.last_channel()->DoConnect(kRemoteCId + i);
468     registry.last_channel()->DoOpen();
469   }
470   EXPECT_EQ(kNumChannelsAllowed - 1, open_result_cb_count);
471 
472   // This callback records the info on channel that was created
473   ChannelId last_local_cid = kInvalidChannelId;
474   auto record_open_result_cb = [&](const DynamicChannel* chan) {
475     ASSERT_TRUE(chan);
476     last_local_cid = chan->local_cid();
477   };
478 
479   // Ensure that channel IDs are not exhausted.
480   EXPECT_NE(kInvalidChannelId, registry.FindAvailableChannelId());
481 
482   // Open a the last available channel.
483   registry.OpenOutbound(kPsm, kChannelParams, std::move(record_open_result_cb));
484 
485   registry.last_channel()->DoConnect(kRemoteCId + kNumChannelsAllowed - 1);
486   registry.last_channel()->DoOpen();
487 
488   EXPECT_NE(kInvalidChannelId, last_local_cid);
489   ASSERT_TRUE(registry.FindChannelByLocalId(last_local_cid));
490 
491   // The channels are exhausted now.
492   ASSERT_EQ(kInvalidChannelId, registry.FindAvailableChannelId());
493 
494   // Close the channel but don't let the disconnection complete.
495   FakeDynamicChannel* const last_channel = registry.last_channel();
496   last_channel->set_defer_disconnect_done_callback();
497   int close_cb_called = 0;
498   registry.CloseChannel(last_local_cid, [&] { close_cb_called++; });
499 
500   // New channels should not reuse the "mostly disconnected" channel's ID.
501   EXPECT_EQ(close_cb_called, 0);
502   // There should still be no channels left.
503   EXPECT_EQ(kInvalidChannelId, registry.FindAvailableChannelId());
504   ASSERT_TRUE(registry.FindChannelByLocalId(last_local_cid));
505   EXPECT_FALSE(registry.FindChannelByLocalId(last_local_cid)->IsConnected());
506 
507   // Complete the disconnection for the first channel opened.
508   ASSERT_TRUE(last_channel->disconnect_done_callback());
509   last_channel->disconnect_done_callback()();
510   EXPECT_EQ(close_cb_called, 1);
511   EXPECT_EQ(last_local_cid, registry.FindAvailableChannelId());
512 
513   // Open a new channel and make sure that last ID can be reused now.
514   bool open_result_cb_called = false;
515   auto open_result_cb = [&](const DynamicChannel* chan) {
516     EXPECT_FALSE(open_result_cb_called);
517     open_result_cb_called = true;
518     ASSERT_TRUE(chan);
519     EXPECT_EQ(last_local_cid, chan->local_cid());
520   };
521   registry.OpenOutbound(kPsm, kChannelParams, std::move(open_result_cb));
522   registry.last_channel()->DoConnect(kRemoteCId + kNumChannelsAllowed - 1);
523   registry.last_channel()->DoOpen();
524   EXPECT_TRUE(open_result_cb_called);
525 
526   close_cb_called = 0;
527   for (ChannelId i = 0; i < kNumChannelsAllowed; i++) {
528     registry.CloseChannel(kFirstDynamicChannelId + i,
529                           [&] { close_cb_called++; });
530   }
531   EXPECT_EQ(close_cb_called, kNumChannelsAllowed);
532   EXPECT_FALSE(registry.FindChannelByLocalId(last_local_cid));
533 }
534 
535 // Removing a channel from the channel map while iterating the channels in
536 // ForEach should not cause a use-after-free of the invalidated pointer.
TEST(DynamicChannelRegistryTest,CloseChannelInForEachCallback)537 TEST(DynamicChannelRegistryTest, CloseChannelInForEachCallback) {
538   bool registry_close_cb_called = false;
539   auto registry_close_cb = [&](const DynamicChannel*) {
540     registry_close_cb_called = true;
541   };
542 
543   TestDynamicChannelRegistry registry(std::move(registry_close_cb),
544                                       RejectAllServices);
545 
546   bool open_result_cb_called = false;
547   ChannelId local_cid = kInvalidChannelId;
548   auto open_result_cb = [&](const DynamicChannel* chan) {
549     EXPECT_FALSE(open_result_cb_called);
550     open_result_cb_called = true;
551     EXPECT_TRUE(chan);
552     local_cid = chan->local_cid();
553   };
554 
555   registry.OpenOutbound(kPsm, kChannelParams, std::move(open_result_cb));
556   registry.last_channel()->DoConnect(kRemoteCId);
557   registry.last_channel()->DoOpen();
558 
559   EXPECT_TRUE(open_result_cb_called);
560   EXPECT_TRUE(registry.FindChannelByLocalId(local_cid));
561 
562   // Even if the next iterator is "end", it would still be unsafe to advance the
563   // erased iterator.
564   registry.ForEach([&](DynamicChannel* chan) {
565     registry.CloseChannel(chan->local_cid(), [] {});
566   });
567 
568   EXPECT_FALSE(registry.FindChannelByLocalId(local_cid));
569 }
570 
571 }  // namespace
572 }  // namespace bt::l2cap::internal
573