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 #pragma once
17 
18 #include <gtest/gtest_prod.h>
19 
20 #include <cstdint>
21 #include <list>
22 #include <optional>
23 #include <vector>
24 
25 #include "hci/address_with_type.h"
26 #include "hci/hci_packets.h"
27 
28 namespace bluetooth::hci {
29 
30 /// The LE Scanning reassembler is responsible for defragmenting
31 /// LE advertising reports that are too large to fit inside an HCI event
32 /// and were fragmented by the controller.
33 /// The reassembler also joins scan response data with the
34 /// matching advertising data.
35 
36 class LeScanningReassembler {
37 public:
38   struct CompleteAdvertisingData {
39     uint16_t extended_event_type;
40     std::vector<uint8_t> data;
41   };
42 
LeScanningReassembler()43   LeScanningReassembler() {}
44 
45   LeScanningReassembler(const LeScanningReassembler&) = delete;
46 
47   LeScanningReassembler& operator=(const LeScanningReassembler&) = delete;
48 
49   /// Process an incoming advertsing report, extracted from any of the
50   /// HCI LE Advertising Report or the HCI LE Extended Advertising Report
51   /// events.
52   /// Returns the completed advertising data if the event was complete, or the
53   /// completion of a fragmented advertising event.
54   std::optional<CompleteAdvertisingData> ProcessAdvertisingReport(
55           uint16_t event_type, uint8_t address_type, Address address, uint8_t advertising_sid,
56           const std::vector<uint8_t>& advertising_data);
57 
58   /// Process an incoming periodic advertising report, extracted from the
59   /// HCI LE Periodic Advertising Report events.
60   /// Returns the completed advertising data if the event was complete,
61   /// or the completion of a fragmented advertising event.
62   std::optional<std::vector<uint8_t>> ProcessPeriodicAdvertisingReport(
63           uint16_t sync_handle, DataStatus status, const std::vector<uint8_t>& advertising_data);
64 
65   /// Configure the scan response filter.
66   /// If true all scan responses are ignored.
SetIgnoreScanResponses(bool ignore_scan_responses)67   void SetIgnoreScanResponses(bool ignore_scan_responses) {
68     ignore_scan_responses_ = ignore_scan_responses;
69   }
70 
71 private:
72   /// Determine if scan responses should be processed or ignored.
73   bool ignore_scan_responses_{false};
74 
75   /// Constants for parsing event_type.
76   static constexpr uint8_t kConnectableBit = 0;
77   static constexpr uint8_t kScannableBit = 1;
78   static constexpr uint8_t kDirectedBit = 2;
79   static constexpr uint8_t kScanResponseBit = 3;
80   static constexpr uint8_t kLegacyBit = 4;
81   static constexpr uint8_t kDataStatusBits = 5;
82 
83   /// Packs the information necessary to disambiguate advertising events:
84   /// - For legacy advertising events, the advertising address and
85   ///   advertising address type are used to disambiguate advertisers.
86   /// - For extended advertising events, the SID is optionally used to
87   ///   differentiate between advertising sets of the same advertiser.
88   ///   The advertiser can also be anonymous in which case
89   ///   the address is not provided. In this case, and when the SID
90   ///   is missing, we trust the controller to send fragments of the same
91   ///   advertisement together and not interleaved with that of other
92   ///   advertisers.
93   struct AdvertisingKey {
94     std::optional<AddressWithType> address;
95     std::optional<uint8_t> sid;
96 
97     AdvertisingKey(Address address, DirectAdvertisingAddressType address_type, uint8_t sid);
98     bool operator==(const AdvertisingKey& other);
99   };
100 
101   /// Packs incomplete advertising data.
102   struct AdvertisingFragment {
103     AdvertisingKey key;
104     uint16_t extended_event_type;
105     std::vector<uint8_t> data;
106 
AdvertisingFragmentAdvertisingFragment107     AdvertisingFragment(const AdvertisingKey& key, uint16_t extended_event_type,
108                         const std::vector<uint8_t>& data)
109         : key(key), extended_event_type(extended_event_type), data(data.begin(), data.end()) {}
110   };
111 
112   /// Packs incomplete periodic advertising data.
113   struct PeriodicAdvertisingFragment {
114     std::optional<uint16_t> sync_handle;
115     std::vector<uint8_t> data;
116 
PeriodicAdvertisingFragmentPeriodicAdvertisingFragment117     PeriodicAdvertisingFragment(uint16_t sync_handle, const std::vector<uint8_t>& data)
118         : sync_handle(sync_handle), data(data.begin(), data.end()) {}
119   };
120 
121   /// Advertising cache for de-fragmenting extended advertising reports,
122   /// and joining advertising reports with the matching scan response when
123   /// applicable.
124   /// The cached advertising data is removed as soon as the complete
125   /// advertisement is got (including the scan response).
126   static constexpr size_t kMaximumCacheSize = 16;
127   std::list<AdvertisingFragment> cache_;
128 
129   /// Advertising cache management methods.
130   std::list<AdvertisingFragment>::iterator AppendFragment(const AdvertisingKey& key,
131                                                           uint16_t extended_event_type,
132                                                           const std::vector<uint8_t>& data);
133 
134   void RemoveFragment(const AdvertisingKey& key);
135 
136   bool ContainsFragment(const AdvertisingKey& key);
137 
138   std::list<AdvertisingFragment>::iterator FindFragment(const AdvertisingKey& key);
139 
140   /// Advertising cache for de-fragmenting periodic advertising reports.
141   static constexpr size_t kMaximumPeriodicCacheSize = 16;
142   std::list<PeriodicAdvertisingFragment> periodic_cache_;
143 
144   std::list<PeriodicAdvertisingFragment>::iterator AppendPeriodicFragment(
145           uint16_t sync_handle, const std::vector<uint8_t>& data);
146 
147   std::list<PeriodicAdvertisingFragment>::iterator FindPeriodicFragment(uint16_t sync_handle);
148 
149   /// Trim the advertising data by removing empty or overflowing
150   /// GAP Data entries.
151   static std::vector<uint8_t> TrimAdvertisingData(const std::vector<uint8_t>& advertising_data);
152 
153   FRIEND_TEST(LeScanningReassemblerTest, trim_advertising_data);
154 };
155 
156 }  // namespace bluetooth::hci
157