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 "hal/snoop_logger.h"
18
19 #include <arpa/inet.h>
20 #include <netinet/in.h>
21 #include <bitset>
22 #include <chrono>
23
24 #include "os/log.h"
25
26 namespace bluetooth {
27 namespace hal {
28
29 namespace {
30 typedef struct {
31 uint32_t length_original;
32 uint32_t length_captured;
33 uint32_t flags;
34 uint32_t dropped_packets;
35 uint64_t timestamp;
36 uint8_t type;
37 } __attribute__((__packed__)) btsnoop_packet_header_t;
38
39 typedef struct {
40 uint8_t identification_pattern[8];
41 uint32_t version_number;
42 uint32_t datalink_type;
43 } __attribute__((__packed__)) btsnoop_file_header_t;
44
45 constexpr uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
46
47 constexpr uint32_t kBytesToTest = 0x12345678;
48 constexpr uint8_t kFirstByte = (const uint8_t&)kBytesToTest;
49 constexpr bool isLittleEndian = kFirstByte == 0x78;
50 constexpr bool isBigEndian = kFirstByte == 0x12;
51 static_assert(isLittleEndian || isBigEndian && isLittleEndian != isBigEndian);
52
53 constexpr uint32_t BTSNOOP_VERSION_NUMBER = isLittleEndian ? 0x01000000 : 1;
54 constexpr uint32_t BTSNOOP_DATALINK_TYPE =
55 isLittleEndian ? 0xea030000 : 0x03ea; // Datalink Type code for HCI UART (H4) is 1002
htonll(uint64_t ll)56 uint64_t htonll(uint64_t ll) {
57 if constexpr (isLittleEndian) {
58 return static_cast<uint64_t>(htonl(ll & 0xffffffff)) << 32 | htonl(ll >> 32);
59 } else {
60 return ll;
61 }
62 }
63
64 constexpr btsnoop_file_header_t BTSNOOP_FILE_HEADER = {
65 .identification_pattern = {'b', 't', 's', 'n', 'o', 'o', 'p', 0x00},
66 .version_number = BTSNOOP_VERSION_NUMBER,
67 .datalink_type = BTSNOOP_DATALINK_TYPE};
68 } // namespace
69
SnoopLogger()70 SnoopLogger::SnoopLogger() {
71 bool file_exists;
72 {
73 std::ifstream btsnoop_istream(file_path);
74 file_exists = btsnoop_istream.is_open();
75 }
76 btsnoop_ostream_.open(file_path, std::ios::binary | std::ios::app | std::ios::out);
77 if (!file_exists) {
78 LOG_INFO("Creating new BTSNOOP");
79 btsnoop_ostream_.write(reinterpret_cast<const char*>(&BTSNOOP_FILE_HEADER), sizeof(btsnoop_file_header_t));
80 } else {
81 LOG_INFO("Appending to old BTSNOOP");
82 }
83 }
84
SetFilePath(const std::string & filename)85 void SnoopLogger::SetFilePath(const std::string& filename) {
86 file_path = filename;
87 }
88
capture(const HciPacket & packet,Direction direction,PacketType type)89 void SnoopLogger::capture(const HciPacket& packet, Direction direction, PacketType type) {
90 uint64_t timestamp_us =
91 std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch())
92 .count();
93 std::lock_guard<std::mutex> lock(file_mutex_);
94 std::bitset<32> flags = 0;
95 switch (type) {
96 case PacketType::CMD:
97 flags.set(0, false);
98 flags.set(1, true);
99 break;
100 case PacketType::ACL:
101 flags.set(0, direction == Direction::INCOMING);
102 flags.set(1, false);
103 break;
104 case PacketType::SCO:
105 flags.set(0, direction == Direction::INCOMING);
106 flags.set(1, false);
107 break;
108 case PacketType::EVT:
109 flags.set(0, true);
110 flags.set(1, true);
111 break;
112 }
113 uint32_t length = packet.size() + /* type byte */ 1;
114 btsnoop_packet_header_t header = {.length_original = htonl(length),
115 .length_captured = htonl(length),
116 .flags = htonl(static_cast<uint32_t>(flags.to_ulong())),
117 .dropped_packets = 0,
118 .timestamp = htonll(timestamp_us + BTSNOOP_EPOCH_DELTA),
119 .type = static_cast<uint8_t>(type)};
120 btsnoop_ostream_.write(reinterpret_cast<const char*>(&header), sizeof(btsnoop_packet_header_t));
121 btsnoop_ostream_.write(reinterpret_cast<const char*>(packet.data()), packet.size());
122 if (AlwaysFlush) btsnoop_ostream_.flush();
123 }
124
ListDependencies(ModuleList * list)125 void SnoopLogger::ListDependencies(ModuleList* list) {
126 // We have no dependencies
127 }
128
Start()129 void SnoopLogger::Start() {}
130
Stop()131 void SnoopLogger::Stop() {}
132
133 std::string SnoopLogger::file_path = SnoopLogger::DefaultFilePath;
134
__anonfd10c2230402() 135 const ModuleFactory SnoopLogger::Factory = ModuleFactory([]() {
136 return new SnoopLogger();
137 });
138
139 } // namespace hal
140 } // namespace bluetooth
141