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