1 /*
2  * Copyright 2023 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 #include "hci/le_scanning_reassembler.h"
17 
18 #include <bluetooth/log.h>
19 
20 #include <memory>
21 #include <unordered_map>
22 
23 #include "hci/acl_manager.h"
24 #include "hci/controller.h"
25 #include "hci/hci_layer.h"
26 #include "hci/hci_packets.h"
27 #include "hci/le_periodic_sync_manager.h"
28 #include "hci/le_scanning_interface.h"
29 #include "module.h"
30 #include "os/handler.h"
31 #include "storage/storage_module.h"
32 
33 namespace bluetooth::hci {
34 
35 std::optional<LeScanningReassembler::CompleteAdvertisingData>
ProcessAdvertisingReport(uint16_t event_type,uint8_t address_type,Address address,uint8_t advertising_sid,const std::vector<uint8_t> & advertising_data)36 LeScanningReassembler::ProcessAdvertisingReport(uint16_t event_type, uint8_t address_type,
37                                                 Address address, uint8_t advertising_sid,
38                                                 const std::vector<uint8_t>& advertising_data) {
39   bool is_scannable = event_type & (1 << kScannableBit);
40   bool is_scan_response = event_type & (1 << kScanResponseBit);
41   bool is_legacy = event_type & (1 << kLegacyBit);
42   DataStatus data_status = DataStatus((event_type >> kDataStatusBits) & 0x3);
43 
44   if (address_type != (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED &&
45       address == Address::kEmpty) {
46     log::warn("Ignoring non-anonymous advertising report with empty address");
47     return {};
48   }
49 
50   AdvertisingKey key(address, DirectAdvertisingAddressType(address_type), advertising_sid);
51 
52   // Ignore scan responses received without a matching advertising event.
53   if (is_scan_response && (ignore_scan_responses_ || !ContainsFragment(key))) {
54     log::info("Ignoring scan response received without advertising event");
55     return {};
56   }
57 
58   // Legacy advertising is always complete, we can drop
59   // the previous data as safety measure if the report is not a scan
60   // response.
61   if (is_legacy && !is_scan_response) {
62     log::verbose("Dropping repeated legacy advertising data");
63     RemoveFragment(key);
64   }
65 
66   // Concatenate the data with existing fragments.
67   std::list<AdvertisingFragment>::iterator advertising_fragment =
68           AppendFragment(key, event_type, advertising_data);
69 
70   // Trim the advertising data when the complete payload is received.
71   if (data_status != DataStatus::CONTINUING) {
72     advertising_fragment->data = TrimAdvertisingData(advertising_fragment->data);
73   }
74 
75   // TODO(b/272120114) waiting for a scan response here is prone to failure as the
76   // SCAN_REQ PDUs can be rejected by the advertiser according to the
77   // advertising filter parameter.
78   bool expect_scan_response = is_scannable && !is_scan_response && !ignore_scan_responses_;
79 
80   // Check if we should wait for additional fragments:
81   // - For legacy advertising, when a scan response is expected.
82   // - For extended advertising, when the current data is marked
83   //   incomplete OR when a scan response is expected.
84   if (data_status == DataStatus::CONTINUING || expect_scan_response) {
85     log::verbose(
86             "Ignoring advertising report when scan response is expected or current data is marked "
87             "incomplete");
88     return {};
89   }
90 
91   // Otherwise the full advertising report has been reassembled,
92   // removed the cache entry and return the complete advertising data.
93   CompleteAdvertisingData result{.extended_event_type = advertising_fragment->extended_event_type,
94                                  .data = std::move(advertising_fragment->data)};
95   cache_.erase(advertising_fragment);
96   log::verbose("Full advertising report has been reassembled");
97   return result;
98 }
99 
ProcessPeriodicAdvertisingReport(uint16_t sync_handle,DataStatus data_status,const std::vector<uint8_t> & advertising_data)100 std::optional<std::vector<uint8_t>> LeScanningReassembler::ProcessPeriodicAdvertisingReport(
101         uint16_t sync_handle, DataStatus data_status,
102         const std::vector<uint8_t>& advertising_data) {
103   // Concatenate the data with existing fragments.
104   std::list<PeriodicAdvertisingFragment>::iterator advertising_fragment =
105           AppendPeriodicFragment(sync_handle, advertising_data);
106 
107   // Return and wait for additional fragments if the data is marked as
108   // incomplete.
109   if (data_status == DataStatus::CONTINUING) {
110     return {};
111   }
112 
113   // The complete payload has been received; trim the advertising data,
114   // remove the cache entry and return the complete advertising data.
115   std::vector<uint8_t> result = TrimAdvertisingData(advertising_fragment->data);
116   periodic_cache_.erase(advertising_fragment);
117   return result;
118 }
119 
120 /// Trim the advertising data by removing empty or overflowing
121 /// GAP Data entries.
TrimAdvertisingData(const std::vector<uint8_t> & advertising_data)122 std::vector<uint8_t> LeScanningReassembler::TrimAdvertisingData(
123         const std::vector<uint8_t>& advertising_data) {
124   // Remove empty and overflowing entries from the advertising data.
125   std::vector<uint8_t> significant_advertising_data;
126   for (size_t offset = 0; offset < advertising_data.size();) {
127     size_t remaining_size = advertising_data.size() - offset;
128     uint8_t entry_size = advertising_data[offset];
129 
130     if (entry_size != 0 && entry_size < remaining_size) {
131       significant_advertising_data.push_back(entry_size);
132       significant_advertising_data.insert(significant_advertising_data.end(),
133                                           advertising_data.begin() + offset + 1,
134                                           advertising_data.begin() + offset + 1 + entry_size);
135     }
136 
137     offset += entry_size + 1;
138   }
139 
140   return significant_advertising_data;
141 }
142 
AdvertisingKey(Address address,DirectAdvertisingAddressType address_type,uint8_t sid)143 LeScanningReassembler::AdvertisingKey::AdvertisingKey(Address address,
144                                                       DirectAdvertisingAddressType address_type,
145                                                       uint8_t sid)
146     : address(), sid() {
147   // The address type is NO_ADDRESS_PROVIDED for anonymous advertising.
148   if (address_type != DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED) {
149     this->address = AddressWithType(address, AddressType(address_type));
150   }
151   // 0xff is reserved to indicate that the ADI field was not present
152   // in the ADV_EXT_IND PDU.
153   if (sid != 0xff) {
154     this->sid = sid;
155   }
156 }
157 
operator ==(const AdvertisingKey & other)158 bool LeScanningReassembler::AdvertisingKey::operator==(const AdvertisingKey& other) {
159   return address == other.address && sid == other.sid;
160 }
161 
162 /// Append to the current advertising data of the selected advertiser.
163 /// If the advertiser is unknown a new entry is added, optionally by
164 /// dropping the oldest advertiser.
165 std::list<LeScanningReassembler::AdvertisingFragment>::iterator
AppendFragment(const AdvertisingKey & key,uint16_t extended_event_type,const std::vector<uint8_t> & data)166 LeScanningReassembler::AppendFragment(const AdvertisingKey& key, uint16_t extended_event_type,
167                                       const std::vector<uint8_t>& data) {
168   auto it = FindFragment(key);
169   if (it != cache_.end()) {
170     // Legacy scan responses don't contain a 'connectable' bit, so this adds the
171     // 'connectable' bit from the initial report.
172     if ((extended_event_type & (1 << kLegacyBit)) &&
173         (extended_event_type & (1 << kScanResponseBit))) {
174       it->extended_event_type =
175               extended_event_type | (it->extended_event_type & (1 << kConnectableBit));
176     } else {
177       it->extended_event_type = extended_event_type;
178     }
179     it->data.insert(it->data.end(), data.cbegin(), data.cend());
180     return it;
181   }
182 
183   if (cache_.size() > kMaximumCacheSize) {
184     cache_.pop_back();
185   }
186 
187   cache_.emplace_front(key, extended_event_type, data);
188   return cache_.begin();
189 }
190 
RemoveFragment(const AdvertisingKey & key)191 void LeScanningReassembler::RemoveFragment(const AdvertisingKey& key) {
192   auto it = FindFragment(key);
193   if (it != cache_.end()) {
194     cache_.erase(it);
195   }
196 }
197 
ContainsFragment(const AdvertisingKey & key)198 bool LeScanningReassembler::ContainsFragment(const AdvertisingKey& key) {
199   return FindFragment(key) != cache_.end();
200 }
201 
FindFragment(const AdvertisingKey & key)202 std::list<LeScanningReassembler::AdvertisingFragment>::iterator LeScanningReassembler::FindFragment(
203         const AdvertisingKey& key) {
204   for (auto it = cache_.begin(); it != cache_.end(); it++) {
205     if (it->key == key) {
206       return it;
207     }
208   }
209   return cache_.end();
210 }
211 
212 /// Append to the current advertising data of the selected periodic advertiser.
213 /// If the advertiser is unknown a new entry is added, optionally by
214 /// dropping the oldest advertiser.
215 std::list<LeScanningReassembler::PeriodicAdvertisingFragment>::iterator
AppendPeriodicFragment(uint16_t sync_handle,const std::vector<uint8_t> & data)216 LeScanningReassembler::AppendPeriodicFragment(uint16_t sync_handle,
217                                               const std::vector<uint8_t>& data) {
218   auto it = FindPeriodicFragment(sync_handle);
219   if (it != periodic_cache_.end()) {
220     it->data.insert(it->data.end(), data.cbegin(), data.cend());
221     return it;
222   }
223 
224   if (periodic_cache_.size() > kMaximumPeriodicCacheSize) {
225     periodic_cache_.pop_back();
226   }
227 
228   periodic_cache_.emplace_front(sync_handle, data);
229   return periodic_cache_.begin();
230 }
231 
232 std::list<LeScanningReassembler::PeriodicAdvertisingFragment>::iterator
FindPeriodicFragment(uint16_t sync_handle)233 LeScanningReassembler::FindPeriodicFragment(uint16_t sync_handle) {
234   for (auto it = periodic_cache_.begin(); it != periodic_cache_.end(); it++) {
235     if (it->sync_handle == sync_handle) {
236       return it;
237     }
238   }
239   return periodic_cache_.end();
240 }
241 
242 }  // namespace bluetooth::hci
243