1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "l2cap/internal/dynamic_channel_allocator.h"
18 
19 #include <bluetooth/log.h>
20 
21 #include <unordered_map>
22 
23 #include "l2cap/cid.h"
24 #include "l2cap/classic/internal/link.h"
25 #include "l2cap/classic/security_policy.h"
26 #include "l2cap/internal/dynamic_channel_impl.h"
27 #include "os/log.h"
28 
29 namespace bluetooth {
30 namespace l2cap {
31 namespace internal {
32 
AllocateChannel(Psm psm,Cid remote_cid)33 std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateChannel(Psm psm, Cid remote_cid) {
34   if (used_remote_cid_.find(remote_cid) != used_remote_cid_.end()) {
35     log::info("Remote cid 0x{:x} is used", remote_cid);
36     return nullptr;
37   }
38   Cid cid = kFirstDynamicChannel;
39   for (; cid <= kLastDynamicChannel; cid++) {
40     if (used_cid_.find(cid) == used_cid_.end()) break;
41   }
42   if (cid > kLastDynamicChannel) {
43     log::warn("All cid are used");
44     return nullptr;
45   }
46   auto elem =
47       channels_.try_emplace(cid, std::make_shared<DynamicChannelImpl>(psm, cid, remote_cid, link_, l2cap_handler_));
48   log::assert_that(
49       elem.second,
50       "Failed to create channel for psm 0x{:x} device {}",
51       psm,
52       ADDRESS_TO_LOGGABLE_CSTR(link_->GetDevice()));
53   log::assert_that(elem.first->second != nullptr, "assert failed: elem.first->second != nullptr");
54   used_remote_cid_.insert(remote_cid);
55   used_cid_.insert(cid);
56   return elem.first->second;
57 }
58 
AllocateReservedChannel(Cid reserved_cid,Psm psm,Cid remote_cid)59 std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateReservedChannel(Cid reserved_cid, Psm psm,
60                                                                                      Cid remote_cid) {
61   if (used_remote_cid_.find(remote_cid) != used_remote_cid_.end()) {
62     log::info("Remote cid 0x{:x} is used", remote_cid);
63     return nullptr;
64   }
65   auto elem = channels_.try_emplace(
66       reserved_cid, std::make_shared<DynamicChannelImpl>(psm, reserved_cid, remote_cid, link_, l2cap_handler_));
67   log::assert_that(
68       elem.second,
69       "Failed to create channel for psm 0x{:x} device {}",
70       psm,
71       ADDRESS_TO_LOGGABLE_CSTR(link_->GetDevice()));
72   log::assert_that(elem.first->second != nullptr, "assert failed: elem.first->second != nullptr");
73   used_remote_cid_.insert(remote_cid);
74   return elem.first->second;
75 }
76 
ReserveChannel()77 Cid DynamicChannelAllocator::ReserveChannel() {
78   Cid cid = kFirstDynamicChannel;
79   for (; cid <= kLastDynamicChannel; cid++) {
80     if (used_cid_.find(cid) == used_cid_.end()) break;
81   }
82   if (cid > kLastDynamicChannel) {
83     log::warn("All cid are used");
84     return kInvalidCid;
85   }
86   used_cid_.insert(cid);
87   return cid;
88 }
89 
FreeChannel(Cid cid)90 void DynamicChannelAllocator::FreeChannel(Cid cid) {
91   used_cid_.erase(cid);
92   auto channel = FindChannelByCid(cid);
93   if (channel == nullptr) {
94     log::info("Channel is not in use: cid {}, device {}", cid, link_->GetDevice());
95     return;
96   }
97   used_remote_cid_.erase(channel->GetRemoteCid());
98   channels_.erase(cid);
99 }
100 
IsPsmUsed(Psm psm) const101 bool DynamicChannelAllocator::IsPsmUsed(Psm psm) const {
102   for (const auto& channel : channels_) {
103     if (channel.second->GetPsm() == psm) {
104       return true;
105     }
106   }
107   return false;
108 }
109 
FindChannelByCid(Cid cid)110 std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::FindChannelByCid(Cid cid) {
111   if (channels_.find(cid) == channels_.end()) {
112     log::warn("Can't find cid {}", cid);
113     return nullptr;
114   }
115   return channels_.find(cid)->second;
116 }
117 
FindChannelByRemoteCid(Cid remote_cid)118 std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::FindChannelByRemoteCid(Cid remote_cid) {
119   for (auto& channel : channels_) {
120     if (channel.second->GetRemoteCid() == remote_cid) {
121       return channel.second;
122     }
123   }
124   return nullptr;
125 }
126 
NumberOfChannels() const127 size_t DynamicChannelAllocator::NumberOfChannels() const {
128   return channels_.size();
129 }
130 
OnAclDisconnected(hci::ErrorCode reason)131 void DynamicChannelAllocator::OnAclDisconnected(hci::ErrorCode reason) {
132   for (auto& elem : channels_) {
133     elem.second->OnClosed(reason);
134   }
135 }
136 
137 }  // namespace internal
138 }  // namespace l2cap
139 }  // namespace bluetooth
140