1 /*
2  * Copyright 2022 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 "hci/pcap_filter.h"
18 
19 #include <packet_runtime.h>
20 
21 #include <algorithm>
22 #include <array>
23 #include <cstddef>
24 #include <cstdint>
25 #include <cstdio>
26 #include <cstring>
27 #include <memory>
28 #include <utility>
29 #include <vector>
30 
31 #include "log.h"
32 #include "packets/hci_packets.h"
33 
34 using namespace bluetooth::hci;
35 
36 namespace rootcanal {
37 
create_packet_view(std::vector<uint8_t> const & packet)38 static pdl::packet::slice create_packet_view(std::vector<uint8_t> const& packet) {
39   // Wrap the reference to the packet in a shared_ptr with created
40   // a no-op deleter. The packet view will be short lived so there is no
41   // risk of the reference leaking.
42   return pdl::packet::slice(std::shared_ptr<std::vector<uint8_t> const>(
43           &packet, [](std::vector<uint8_t> const* /* ptr */) {}));
44 }
45 
46 static std::vector<uint8_t> FilterHciAcl(std::vector<uint8_t> const& packet);
47 static std::vector<uint8_t> FilterHciSco(std::vector<uint8_t> const& packet);
48 static std::vector<uint8_t> FilterHciIso(std::vector<uint8_t> const& packet);
49 
FilterHciPacket(std::vector<uint8_t> const & packet,uint8_t idc)50 std::vector<uint8_t> PcapFilter::FilterHciPacket(std::vector<uint8_t> const& packet, uint8_t idc) {
51   switch (idc) {
52     case 0x1:
53       return FilterHciCommand(packet);
54     case 0x2:
55       return FilterHciAcl(packet);
56     case 0x3:
57       return FilterHciSco(packet);
58     case 0x4:
59       return FilterHciEvent(packet);
60     case 0x5:
61       return FilterHciIso(packet);
62     default:
63       break;
64   }
65   return std::vector<uint8_t>(packet);
66 }
67 
FilterHciCommand(std::vector<uint8_t> const & packet)68 std::vector<uint8_t> PcapFilter::FilterHciCommand(std::vector<uint8_t> const& packet) {
69   auto command = CommandView::Create(create_packet_view(packet));
70   ASSERT(command.IsValid());
71   switch (command.GetOpCode()) {
72     case OpCode::WRITE_LOCAL_NAME:
73       return FilterWriteLocalName(command);
74     case OpCode::WRITE_EXTENDED_INQUIRY_RESPONSE:
75       return FilterWriteExtendedInquiryResponse(command);
76     case OpCode::LE_SET_ADVERTISING_DATA:
77       return FilterLeSetAdvertisingData(command);
78     case OpCode::LE_SET_SCAN_RESPONSE_DATA:
79       return FilterLeSetScanResponseData(command);
80     case OpCode::LE_SET_EXTENDED_ADVERTISING_DATA:
81       return FilterLeSetExtendedAdvertisingData(command);
82     case OpCode::LE_SET_EXTENDED_SCAN_RESPONSE_DATA:
83       return FilterLeSetExtendedScanResponseData(command);
84     case OpCode::LE_SET_PERIODIC_ADVERTISING_DATA:
85       return FilterLeSetPeriodicAdvertisingData(command);
86     default:
87       break;
88   }
89   return std::vector<uint8_t>(packet);
90 }
91 
FilterHciEvent(std::vector<uint8_t> const & packet)92 std::vector<uint8_t> PcapFilter::FilterHciEvent(std::vector<uint8_t> const& packet) {
93   auto event = EventView::Create(create_packet_view(packet));
94   ASSERT(event.IsValid());
95   switch (event.GetEventCode()) {
96     case EventCode::LE_META_EVENT: {
97       auto le_meta_event = LeMetaEventView::Create(event);
98       ASSERT(le_meta_event.IsValid());
99       switch (le_meta_event.GetSubeventCode()) {
100         case SubeventCode::LE_ADVERTISING_REPORT:
101           return FilterLeAdvertisingReport(le_meta_event);
102         case SubeventCode::LE_EXTENDED_ADVERTISING_REPORT:
103           return FilterLeExtendedAdvertisingReport(le_meta_event);
104         default:
105           break;
106       }
107       break;
108     }
109     case EventCode::COMMAND_COMPLETE: {
110       auto command_complete = CommandCompleteView::Create(event);
111       ASSERT(command_complete.IsValid());
112       switch (command_complete.GetCommandOpCode()) {
113         case OpCode::READ_LOCAL_NAME:
114           return FilterReadLocalNameComplete(command_complete);
115         case OpCode::READ_EXTENDED_INQUIRY_RESPONSE:
116           return FilterReadExtendedInquiryResponseComplete(command_complete);
117         default:
118           break;
119       }
120       break;
121     }
122     case EventCode::REMOTE_NAME_REQUEST_COMPLETE:
123       return FilterRemoteNameRequestComplete(event);
124     case EventCode::EXTENDED_INQUIRY_RESULT:
125       return FilterExtendedInquiryResult(event);
126     default:
127       break;
128   }
129   return std::vector<uint8_t>(packet);
130 }
131 
FilterHciAcl(std::vector<uint8_t> const & packet)132 static std::vector<uint8_t> FilterHciAcl(std::vector<uint8_t> const& packet) {
133   auto acl = AclView::Create(create_packet_view(packet));
134   std::vector<uint8_t> payload;
135   payload.resize(acl.GetPayload().size());
136   ASSERT(acl.IsValid());
137   return AclBuilder::Create(acl.GetHandle(), acl.GetPacketBoundaryFlag(), acl.GetBroadcastFlag(),
138                             std::move(payload))
139           ->SerializeToBytes();
140 }
141 
FilterHciSco(std::vector<uint8_t> const & packet)142 static std::vector<uint8_t> FilterHciSco(std::vector<uint8_t> const& packet) {
143   auto sco = ScoView::Create(create_packet_view(packet));
144   std::vector<uint8_t> data;
145   data.resize(sco.GetData().size());
146   ASSERT(sco.IsValid());
147   return ScoBuilder::Create(sco.GetHandle(), sco.GetPacketStatusFlag(), data)->SerializeToBytes();
148 }
149 
FilterHciIso(std::vector<uint8_t> const & packet)150 static std::vector<uint8_t> FilterHciIso(std::vector<uint8_t> const& packet) {
151   auto iso = IsoView::Create(create_packet_view(packet));
152   std::vector<uint8_t> payload;
153   payload.resize(iso.GetPayload().size());
154   ASSERT(iso.IsValid());
155   return IsoBuilder::Create(iso.GetConnectionHandle(), iso.GetPbFlag(), iso.GetTsFlag(),
156                             std::move(payload))
157           ->SerializeToBytes();
158 }
159 
160 // Replace device names in GAP entries.
161 // TODO: extended advertising reports can be chunked across multiple
162 // events, and a single GAP data entry can be segmented in two.
163 // The filter should account for that and keep a state for partial
164 // GAP entries.
FilterGapData(uint8_t * gap_data,size_t gap_data_len)165 void PcapFilter::FilterGapData(uint8_t* gap_data, size_t gap_data_len) {
166   size_t offset = 0;
167   while ((offset + 2) <= gap_data_len) {
168     size_t length = gap_data[offset];
169     GapDataType data_type = static_cast<GapDataType>(gap_data[offset + 1]);
170 
171     // Truncated entry.
172     if ((offset + length + 1) > gap_data_len) {
173       break;
174     }
175 
176     // Empty entry.
177     if (length == 0) {
178       offset += 1;
179       continue;
180     }
181 
182     // Apply the filter to entries that contain user data.
183     switch (data_type) {
184       case GapDataType::COMPLETE_LOCAL_NAME:
185       case GapDataType::SHORTENED_LOCAL_NAME: {
186         auto start_pos = gap_data + offset + 1;
187         auto end_pos = gap_data + offset + length;
188         std::vector<uint8_t> new_name = ChangeDeviceName(std::vector<uint8_t>{start_pos, end_pos});
189         std::copy(new_name.begin(), new_name.end(), start_pos);
190         break;
191       }
192       default:
193         break;
194     }
195 
196     offset += length + 1;
197   }
198 }
199 
FilterGapData(std::vector<uint8_t> & gap_data)200 void PcapFilter::FilterGapData(std::vector<uint8_t>& gap_data) {
201   FilterGapData(gap_data.data(), gap_data.size());
202 }
203 
204 // Replace the local device name.
FilterWriteLocalName(CommandView & command)205 std::vector<uint8_t> PcapFilter::FilterWriteLocalName(CommandView& command) {
206   auto parameters = WriteLocalNameView::Create(command);
207   ASSERT(parameters.IsValid());
208 
209   std::array<uint8_t, 248> local_name = ChangeDeviceName(parameters.GetLocalName());
210   return WriteLocalNameBuilder::Create(local_name)->SerializeToBytes();
211 }
212 
213 // Replace the device names in the GAP entries of the extended inquiry response.
FilterWriteExtendedInquiryResponse(CommandView & command)214 std::vector<uint8_t> PcapFilter::FilterWriteExtendedInquiryResponse(CommandView& command) {
215   auto parameters = WriteExtendedInquiryResponseView::Create(command);
216   ASSERT(parameters.IsValid());
217 
218   std::array<uint8_t, 240> extended_inquiry_response = parameters.GetExtendedInquiryResponse();
219   FilterGapData(extended_inquiry_response.data(), extended_inquiry_response.size());
220   return WriteExtendedInquiryResponseBuilder::Create(parameters.GetFecRequired(),
221                                                      extended_inquiry_response)
222           ->SerializeToBytes();
223 }
224 
225 // Replace the device names in the GAP entries of the advertising data.
FilterLeSetAdvertisingData(CommandView & command)226 std::vector<uint8_t> PcapFilter::FilterLeSetAdvertisingData(CommandView& command) {
227   auto parameters = LeSetAdvertisingDataView::Create(command);
228   ASSERT(parameters.IsValid());
229 
230   std::vector<uint8_t> advertising_data = parameters.GetAdvertisingData();
231   FilterGapData(advertising_data);
232   return LeSetAdvertisingDataBuilder::Create(advertising_data)->SerializeToBytes();
233 }
234 
235 // Replace the device names in the GAP entries of the scan response data.
FilterLeSetScanResponseData(CommandView & command)236 std::vector<uint8_t> PcapFilter::FilterLeSetScanResponseData(CommandView& command) {
237   auto parameters = LeSetScanResponseDataView::Create(command);
238   ASSERT(parameters.IsValid());
239 
240   std::vector<uint8_t> advertising_data = parameters.GetAdvertisingData();
241   FilterGapData(advertising_data);
242   return LeSetScanResponseDataBuilder::Create(advertising_data)->SerializeToBytes();
243 }
244 
245 // Replace the device names in the GAP entries of the extended advertising data.
FilterLeSetExtendedAdvertisingData(CommandView & command)246 std::vector<uint8_t> PcapFilter::FilterLeSetExtendedAdvertisingData(CommandView& command) {
247   auto parameters = LeSetExtendedAdvertisingDataView::Create(command);
248   ASSERT(parameters.IsValid());
249 
250   std::vector<uint8_t> advertising_data = parameters.GetAdvertisingData();
251   FilterGapData(advertising_data);
252   return LeSetExtendedAdvertisingDataBuilder::Create(
253                  parameters.GetAdvertisingHandle(), parameters.GetOperation(),
254                  parameters.GetFragmentPreference(), advertising_data)
255           ->SerializeToBytes();
256 }
257 
258 // Replace the device names in the GAP entries of the extended scan response
259 // data.
FilterLeSetExtendedScanResponseData(CommandView & command)260 std::vector<uint8_t> PcapFilter::FilterLeSetExtendedScanResponseData(CommandView& command) {
261   auto parameters = LeSetExtendedScanResponseDataView::Create(command);
262   ASSERT(parameters.IsValid());
263 
264   std::vector<uint8_t> advertising_data = parameters.GetScanResponseData();
265   FilterGapData(advertising_data);
266   return LeSetExtendedScanResponseDataBuilder::Create(
267                  parameters.GetAdvertisingHandle(), parameters.GetOperation(),
268                  parameters.GetFragmentPreference(), advertising_data)
269           ->SerializeToBytes();
270 }
271 
272 // Replace the device names in the GAP entries of the periodic advertising
273 // data.
FilterLeSetPeriodicAdvertisingData(bluetooth::hci::CommandView & command)274 std::vector<uint8_t> PcapFilter::FilterLeSetPeriodicAdvertisingData(
275         bluetooth::hci::CommandView& command) {
276   auto parameters = LeSetPeriodicAdvertisingDataView::Create(command);
277   ASSERT(parameters.IsValid());
278 
279   std::vector<uint8_t> advertising_data = parameters.GetAdvertisingData();
280   FilterGapData(advertising_data);
281   return LeSetPeriodicAdvertisingDataBuilder::Create(parameters.GetAdvertisingHandle(),
282                                                      parameters.GetOperation(), advertising_data)
283           ->SerializeToBytes();
284 }
285 
286 // Replace the local device name in the read local name complete event.
FilterReadLocalNameComplete(bluetooth::hci::CommandCompleteView & command_complete)287 std::vector<uint8_t> PcapFilter::FilterReadLocalNameComplete(
288         bluetooth::hci::CommandCompleteView& command_complete) {
289   auto parameters = ReadLocalNameCompleteView::Create(command_complete);
290   ASSERT(parameters.IsValid());
291 
292   std::array<uint8_t, 248> local_name = parameters.GetLocalName();
293   if (parameters.GetStatus() == ErrorCode::SUCCESS) {
294     local_name = ChangeDeviceName(local_name);
295   }
296 
297   return ReadLocalNameCompleteBuilder::Create(parameters.GetNumHciCommandPackets(),
298                                               parameters.GetStatus(), local_name)
299           ->SerializeToBytes();
300 }
301 
302 // Replace the device names in the GAP entries of the extended inquiry response.
FilterReadExtendedInquiryResponseComplete(bluetooth::hci::CommandCompleteView & command_complete)303 std::vector<uint8_t> PcapFilter::FilterReadExtendedInquiryResponseComplete(
304         bluetooth::hci::CommandCompleteView& command_complete) {
305   auto parameters = ReadExtendedInquiryResponseCompleteView::Create(command_complete);
306   ASSERT(parameters.IsValid());
307 
308   std::array<uint8_t, 240> extended_inquiry_response = parameters.GetExtendedInquiryResponse();
309   if (parameters.GetStatus() == ErrorCode::SUCCESS) {
310     FilterGapData(extended_inquiry_response.data(), extended_inquiry_response.size());
311   }
312 
313   return ReadExtendedInquiryResponseCompleteBuilder::Create(
314                  parameters.GetNumHciCommandPackets(), parameters.GetStatus(),
315                  parameters.GetFecRequired(), extended_inquiry_response)
316           ->SerializeToBytes();
317 }
318 
319 // Replace the remote device name in the remote name request complete event.
FilterRemoteNameRequestComplete(bluetooth::hci::EventView & event)320 std::vector<uint8_t> PcapFilter::FilterRemoteNameRequestComplete(bluetooth::hci::EventView& event) {
321   auto parameters = RemoteNameRequestCompleteView::Create(event);
322   ASSERT(parameters.IsValid());
323 
324   std::array<uint8_t, 248> remote_name = parameters.GetRemoteName();
325   if (parameters.GetStatus() == ErrorCode::SUCCESS) {
326     remote_name = ChangeDeviceName(remote_name);
327   }
328 
329   return RemoteNameRequestCompleteBuilder::Create(parameters.GetStatus(), parameters.GetBdAddr(),
330                                                   remote_name)
331           ->SerializeToBytes();
332 }
333 
334 // Replace the device names in the GAP entries in the extended inquiry result.
FilterExtendedInquiryResult(bluetooth::hci::EventView & event)335 std::vector<uint8_t> PcapFilter::FilterExtendedInquiryResult(bluetooth::hci::EventView& event) {
336   auto parameters = ExtendedInquiryResultView::Create(event);
337   ASSERT(parameters.IsValid());
338 
339   std::array<uint8_t, 240> extended_inquiry_response = parameters.GetExtendedInquiryResponse();
340   FilterGapData(extended_inquiry_response.data(), extended_inquiry_response.size());
341   return ExtendedInquiryResultBuilder::Create(
342                  parameters.GetAddress(), parameters.GetPageScanRepetitionMode(),
343                  parameters.GetClassOfDevice(), parameters.GetClockOffset(), parameters.GetRssi(),
344                  extended_inquiry_response)
345           ->SerializeToBytes();
346 }
347 
348 // Replace the device names in the GAP entries in the advertising report.
FilterLeAdvertisingReport(bluetooth::hci::LeMetaEventView & event)349 std::vector<uint8_t> PcapFilter::FilterLeAdvertisingReport(bluetooth::hci::LeMetaEventView& event) {
350   auto parameters = LeAdvertisingReportView::Create(event);
351   ASSERT(parameters.IsValid());
352 
353   std::vector<LeAdvertisingResponse> responses = parameters.GetResponses();
354   for (auto& response : responses) {
355     FilterGapData(response.advertising_data_);
356   }
357 
358   return LeAdvertisingReportBuilder::Create(responses)->SerializeToBytes();
359 }
360 
361 // Replace the device names in the GAP entries in the extended advertising
362 // report.
FilterLeExtendedAdvertisingReport(bluetooth::hci::LeMetaEventView & event)363 std::vector<uint8_t> PcapFilter::FilterLeExtendedAdvertisingReport(
364         bluetooth::hci::LeMetaEventView& event) {
365   auto parameters = LeExtendedAdvertisingReportView::Create(event);
366   ASSERT(parameters.IsValid());
367 
368   std::vector<LeExtendedAdvertisingResponse> responses = parameters.GetResponses();
369   for (auto& response : responses) {
370     FilterGapData(response.advertising_data_);
371   }
372 
373   return LeExtendedAdvertisingReportBuilder::Create(responses)->SerializeToBytes();
374 }
375 
376 // Generate a device name of the specified length.
377 // device_nr is a unique identifier used for the generation.
378 // padded indicates if the name should be padded to length with
379 // spaces.
generate_device_name(size_t device_nr,size_t device_name_len,bool padded)380 static std::vector<uint8_t> generate_device_name(size_t device_nr, size_t device_name_len,
381                                                  bool padded) {
382   std::vector<uint8_t> output;
383   output.resize(device_name_len + 1);
384   int written_len = std::snprintf(reinterpret_cast<char*>(output.data()), output.size(),
385                                   "#%02zu device", device_nr);
386   // Remove the null terminator, not used for the device name
387   // since it is framed in most cases.
388   output.resize(device_name_len);
389   // Pad the device name with spaces.
390   if (padded && written_len >= 0 && written_len < (int)output.size()) {
391     std::memset(&output[written_len], ' ', output.size() - written_len);
392   }
393   return output;
394 }
395 
ChangeDeviceName(std::vector<uint8_t> const & device_name)396 std::vector<uint8_t> PcapFilter::ChangeDeviceName(std::vector<uint8_t> const& device_name) {
397   for (auto const& [old_device_name, new_device_name] : device_name_map) {
398     if (old_device_name == device_name) {
399       return std::vector<uint8_t>(new_device_name);
400     }
401   }
402 
403   std::vector<uint8_t> new_device_name =
404           generate_device_name(device_name_map.size(), device_name.size(), true);
405   device_name_map.push_back(std::pair{
406           std::vector<uint8_t>(device_name),
407           new_device_name,
408   });
409   return new_device_name;
410 }
411 
ChangeDeviceName(std::array<uint8_t,248> const & device_name)412 std::array<uint8_t, 248> PcapFilter::ChangeDeviceName(std::array<uint8_t, 248> const& device_name) {
413   for (auto const& [old_device_name, new_device_name] : device_name_map) {
414     if (std::equal(old_device_name.begin(), old_device_name.end(), device_name.begin(),
415                    device_name.end())) {
416       std::array<uint8_t, 248> out_device_name{};
417       std::copy(new_device_name.begin(), new_device_name.end(), out_device_name.begin());
418       return out_device_name;
419     }
420   }
421 
422   std::vector<uint8_t> new_device_name =
423           generate_device_name(device_name_map.size(), device_name.size(), false);
424   std::array<uint8_t, 248> out_device_name{};
425   std::copy(new_device_name.begin(), new_device_name.end(), out_device_name.begin());
426   device_name_map.push_back(std::pair{
427           std::vector<uint8_t>(device_name.begin(), device_name.end()),
428           std::move(new_device_name),
429   });
430   return out_device_name;
431 }
432 
433 }  // namespace rootcanal
434