The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 1 | /****************************************************************************** |
| 2 | * |
Jakub Pawlowski | 5b790fe | 2017-09-18 09:00:20 -0700 | [diff] [blame] | 3 | * Copyright 2014 Google, Inc. |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 4 | * |
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | * you may not use this file except in compliance with the License. |
| 7 | * You may obtain a copy of the License at: |
| 8 | * |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | * |
| 11 | * Unless required by applicable law or agreed to in writing, software |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | * See the License for the specific language governing permissions and |
| 15 | * limitations under the License. |
| 16 | * |
| 17 | ******************************************************************************/ |
| 18 | |
Marie Janssen | 49120dc | 2015-07-07 16:47:20 -0700 | [diff] [blame] | 19 | #define LOG_TAG "bt_snoop" |
| 20 | |
Pavlin Radoslavov | 3060ec6 | 2017-02-16 11:51:48 -0800 | [diff] [blame] | 21 | #include <mutex> |
| 22 | |
Etan Cohen | 3e59b5b | 2015-03-31 17:15:53 -0700 | [diff] [blame] | 23 | #include <arpa/inet.h> |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 24 | #include <base/logging.h> |
Sharvil Nanavati | a7d7eb7 | 2014-06-14 23:45:16 -0700 | [diff] [blame] | 25 | #include <errno.h> |
| 26 | #include <fcntl.h> |
Pavlin Radoslavov | 4394720 | 2016-02-13 08:47:19 -0800 | [diff] [blame] | 27 | #include <inttypes.h> |
Scott James Remnant | 933926c | 2015-04-02 15:22:14 -0700 | [diff] [blame] | 28 | #include <limits.h> |
| 29 | #include <netinet/in.h> |
Sharvil Nanavati | a7d7eb7 | 2014-06-14 23:45:16 -0700 | [diff] [blame] | 30 | #include <stdbool.h> |
| 31 | #include <stdio.h> |
| 32 | #include <stdlib.h> |
Etan Cohen | 3e59b5b | 2015-03-31 17:15:53 -0700 | [diff] [blame] | 33 | #include <string.h> |
Sharvil Nanavati | a7d7eb7 | 2014-06-14 23:45:16 -0700 | [diff] [blame] | 34 | #include <sys/stat.h> |
| 35 | #include <sys/time.h> |
Jakub Pawlowski | 7a7e8e9 | 2017-10-09 20:53:39 -0700 | [diff] [blame] | 36 | #include <sys/uio.h> |
Sharvil Nanavati | a7d7eb7 | 2014-06-14 23:45:16 -0700 | [diff] [blame] | 37 | #include <unistd.h> |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 38 | #include <mutex> |
| 39 | #include <unordered_map> |
| 40 | #include <unordered_set> |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 41 | |
Marie Janssen | db55458 | 2015-06-26 14:53:46 -0700 | [diff] [blame] | 42 | #include "bt_types.h" |
Jack He | 959bc33 | 2018-08-15 12:38:37 -0700 | [diff] [blame] | 43 | #include "common/time_util.h" |
Andre Eisenbach | 89f5e41 | 2014-12-05 09:40:20 -0800 | [diff] [blame] | 44 | #include "hci/include/btsnoop.h" |
| 45 | #include "hci/include/btsnoop_mem.h" |
Zach Johnson | fbbd42b | 2014-08-15 17:00:17 -0700 | [diff] [blame] | 46 | #include "hci_layer.h" |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 47 | #include "internal_include/bt_trace.h" |
Sharvil Nanavati | 4480276 | 2014-12-23 23:08:58 -0800 | [diff] [blame] | 48 | #include "osi/include/log.h" |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 49 | #include "osi/include/properties.h" |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 50 | #include "stack/include/hcimsgs.h" |
| 51 | #include "stack/include/rfcdefs.h" |
| 52 | #include "stack/l2cap/l2c_int.h" |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 53 | #include "stack_config.h" |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 54 | |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 55 | // The number of of packets per btsnoop file before we rotate to the next |
| 56 | // file. As of right now there are two snoop files that are rotated through. |
| 57 | // The size can be dynamically configured by seting the relevant system |
| 58 | // property |
| 59 | #define DEFAULT_BTSNOOP_SIZE 0xffff |
| 60 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 61 | #define IS_DEBUGGABLE_PROPERTY "ro.debuggable" |
| 62 | |
| 63 | #define BTSNOOP_LOG_MODE_PROPERTY "persist.bluetooth.btsnooplogmode" |
| 64 | #define BTSNOOP_DEFAULT_MODE_PROPERTY "persist.bluetooth.btsnoopdefaultmode" |
| 65 | #define BTSNOOP_MODE_DISABLED "disabled" |
| 66 | #define BTSNOOP_MODE_FILTERED "filtered" |
| 67 | #define BTSNOOP_MODE_FULL "full" |
| 68 | |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 69 | #define BTSNOOP_PATH_PROPERTY "persist.bluetooth.btsnooppath" |
| 70 | #define DEFAULT_BTSNOOP_PATH "/data/misc/bluetooth/logs/btsnoop_hci.log" |
| 71 | #define BTSNOOP_MAX_PACKETS_PROPERTY "persist.bluetooth.btsnoopsize" |
| 72 | |
Sharvil Nanavati | 611f3ab | 2014-03-22 14:27:07 -0700 | [diff] [blame] | 73 | typedef enum { |
| 74 | kCommandPacket = 1, |
| 75 | kAclPacket = 2, |
| 76 | kScoPacket = 3, |
| 77 | kEventPacket = 4 |
Sharvil Nanavati | a7d7eb7 | 2014-06-14 23:45:16 -0700 | [diff] [blame] | 78 | } packet_type_t; |
Sharvil Nanavati | 611f3ab | 2014-03-22 14:27:07 -0700 | [diff] [blame] | 79 | |
Sharvil Nanavati | a7d7eb7 | 2014-06-14 23:45:16 -0700 | [diff] [blame] | 80 | // Epoch in microseconds since 01/01/0000. |
| 81 | static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL; |
| 82 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 83 | // Number of bytes into a packet where you can find the value for a channel. |
| 84 | static const size_t ACL_CHANNEL_OFFSET = 0; |
| 85 | static const size_t L2C_CHANNEL_OFFSET = 6; |
| 86 | static const size_t RFC_CHANNEL_OFFSET = 8; |
| 87 | static const size_t RFC_EVENT_OFFSET = 9; |
| 88 | |
| 89 | // The size of the L2CAP header. All information past this point is removed from |
| 90 | // a filtered packet. |
| 91 | static const uint32_t L2C_HEADER_SIZE = 9; |
| 92 | |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 93 | static int logfile_fd = INVALID_FD; |
Pavlin Radoslavov | 3060ec6 | 2017-02-16 11:51:48 -0800 | [diff] [blame] | 94 | static std::mutex btsnoop_mutex; |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 95 | |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 96 | static int32_t packets_per_file; |
| 97 | static int32_t packet_counter; |
| 98 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 99 | // Channel tracking variables for filtering. |
| 100 | |
| 101 | // Keeps track of L2CAP channels that need to be filtered out of the snoop |
| 102 | // logs. |
| 103 | class FilterTracker { |
| 104 | public: |
| 105 | // NOTE: 1 is used as a static CID for L2CAP signaling |
| 106 | std::unordered_set<uint16_t> l2c_local_cid = {1}; |
| 107 | std::unordered_set<uint16_t> l2c_remote_cid = {1}; |
| 108 | uint16_t rfc_local_cid = 0; |
| 109 | uint16_t rfc_remote_cid = 0; |
| 110 | std::unordered_set<uint16_t> rfc_channels = {0}; |
| 111 | |
| 112 | // Adds L2C channel to whitelist. |
| 113 | void addL2cCid(uint16_t local_cid, uint16_t remote_cid) { |
| 114 | l2c_local_cid.insert(local_cid); |
| 115 | l2c_remote_cid.insert(remote_cid); |
| 116 | } |
| 117 | |
| 118 | // Sets L2CAP channel that RFCOMM uses. |
| 119 | void setRfcCid(uint16_t local_cid, uint16_t remote_cid) { |
| 120 | rfc_local_cid = local_cid; |
| 121 | rfc_remote_cid = remote_cid; |
| 122 | } |
| 123 | |
| 124 | // Remove L2C channel from whitelist. |
| 125 | void removeL2cCid(uint16_t local_cid, uint16_t remote_cid) { |
| 126 | if (rfc_local_cid == local_cid) { |
| 127 | rfc_channels.clear(); |
| 128 | rfc_channels.insert(0); |
| 129 | rfc_local_cid = 0; |
| 130 | rfc_remote_cid = 0; |
| 131 | } |
| 132 | |
| 133 | l2c_local_cid.erase(local_cid); |
| 134 | l2c_remote_cid.erase(remote_cid); |
| 135 | } |
| 136 | |
| 137 | void addRfcDlci(uint8_t channel) { rfc_channels.insert(channel); } |
| 138 | |
| 139 | bool isWhitelistedL2c(bool local, uint16_t cid) { |
| 140 | const auto& set = local ? l2c_local_cid : l2c_remote_cid; |
| 141 | return (set.find(cid) != set.end()); |
| 142 | } |
| 143 | |
| 144 | bool isRfcChannel(bool local, uint16_t cid) { |
| 145 | const auto& channel = local ? rfc_local_cid : rfc_remote_cid; |
| 146 | return cid == channel; |
| 147 | } |
| 148 | |
| 149 | bool isWhitelistedDlci(uint8_t dlci) { |
| 150 | return rfc_channels.find(dlci) != rfc_channels.end(); |
| 151 | } |
| 152 | }; |
| 153 | |
| 154 | std::mutex filter_list_mutex; |
| 155 | std::unordered_map<uint16_t, FilterTracker> filter_list; |
| 156 | std::unordered_map<uint16_t, uint16_t> local_cid_to_acl; |
| 157 | |
| 158 | // Cached value for whether full snoop logs are enabled. So the property isn't |
| 159 | // checked for every packet. |
| 160 | static bool is_btsnoop_enabled; |
| 161 | static bool is_btsnoop_filtered; |
| 162 | |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 163 | // TODO(zachoverflow): merge btsnoop and btsnoop_net together |
Sharvil Nanavati | a7d7eb7 | 2014-06-14 23:45:16 -0700 | [diff] [blame] | 164 | void btsnoop_net_open(); |
| 165 | void btsnoop_net_close(); |
Myles Watson | 5ff20a2 | 2016-10-31 10:53:52 -0700 | [diff] [blame] | 166 | void btsnoop_net_write(const void* data, size_t length); |
Kim Schulz | f1d68e9 | 2013-09-23 12:48:47 +0200 | [diff] [blame] | 167 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 168 | static void delete_btsnoop_files(bool filtered); |
| 169 | static std::string get_btsnoop_log_path(bool filtered); |
| 170 | static std::string get_btsnoop_last_log_path(std::string log_path); |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 171 | static void open_next_snoop_file(); |
Andre Eisenbach | 796523d | 2016-11-10 16:11:00 -0800 | [diff] [blame] | 172 | static void btsnoop_write_packet(packet_type_t type, uint8_t* packet, |
Jack He | 071b507 | 2017-02-07 17:25:15 -0800 | [diff] [blame] | 173 | bool is_received, uint64_t timestamp_us); |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 174 | |
| 175 | // Module lifecycle functions |
| 176 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 177 | static future_t* start_up() { |
| 178 | std::array<char, PROPERTY_VALUE_MAX> property = {}; |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 179 | std::lock_guard<std::mutex> lock(btsnoop_mutex); |
| 180 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 181 | // Default mode is FILTERED on userdebug/eng build, DISABLED on user build. |
| 182 | // It can also be overwritten by modifying the global setting. |
| 183 | int is_debuggable = osi_property_get_int32(IS_DEBUGGABLE_PROPERTY, 0); |
| 184 | std::string default_mode = BTSNOOP_MODE_DISABLED; |
| 185 | if (is_debuggable) { |
| 186 | int len = osi_property_get(BTSNOOP_DEFAULT_MODE_PROPERTY, property.data(), |
Ajay Panicker | c33c998 | 2019-02-11 18:04:21 -0800 | [diff] [blame] | 187 | BTSNOOP_MODE_DISABLED); |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 188 | default_mode = std::string(property.data(), len); |
| 189 | } |
| 190 | |
| 191 | // Get the actual mode |
| 192 | int len = osi_property_get(BTSNOOP_LOG_MODE_PROPERTY, property.data(), |
| 193 | default_mode.c_str()); |
| 194 | std::string btsnoop_mode(property.data(), len); |
| 195 | |
| 196 | if (btsnoop_mode == BTSNOOP_MODE_FILTERED) { |
| 197 | LOG(INFO) << __func__ << ": Filtered Snoop Logs enabled"; |
| 198 | is_btsnoop_enabled = true; |
| 199 | is_btsnoop_filtered = true; |
| 200 | delete_btsnoop_files(false); |
| 201 | } else if (btsnoop_mode == BTSNOOP_MODE_FULL) { |
| 202 | LOG(INFO) << __func__ << ": Snoop Logs fully enabled"; |
| 203 | is_btsnoop_enabled = true; |
| 204 | is_btsnoop_filtered = false; |
| 205 | delete_btsnoop_files(true); |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 206 | } else { |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 207 | LOG(INFO) << __func__ << ": Snoop Logs disabled"; |
| 208 | is_btsnoop_enabled = false; |
| 209 | is_btsnoop_filtered = false; |
| 210 | delete_btsnoop_files(true); |
| 211 | delete_btsnoop_files(false); |
| 212 | } |
| 213 | |
| 214 | if (is_btsnoop_enabled) { |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 215 | open_next_snoop_file(); |
Jack He | 2b59c4a | 2017-05-04 13:27:25 -0700 | [diff] [blame] | 216 | packets_per_file = osi_property_get_int32(BTSNOOP_MAX_PACKETS_PROPERTY, |
| 217 | DEFAULT_BTSNOOP_SIZE); |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 218 | btsnoop_net_open(); |
| 219 | } |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 220 | |
| 221 | return NULL; |
| 222 | } |
| 223 | |
Myles Watson | 5ff20a2 | 2016-10-31 10:53:52 -0700 | [diff] [blame] | 224 | static future_t* shut_down(void) { |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 225 | std::lock_guard<std::mutex> lock(btsnoop_mutex); |
| 226 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 227 | if (is_btsnoop_enabled) { |
| 228 | if (is_btsnoop_filtered) { |
| 229 | delete_btsnoop_files(false); |
| 230 | } else { |
| 231 | delete_btsnoop_files(true); |
| 232 | } |
| 233 | } else { |
| 234 | delete_btsnoop_files(true); |
| 235 | delete_btsnoop_files(false); |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 236 | } |
| 237 | |
| 238 | if (logfile_fd != INVALID_FD) close(logfile_fd); |
| 239 | logfile_fd = INVALID_FD; |
| 240 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 241 | if (is_btsnoop_enabled) btsnoop_net_close(); |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 242 | |
| 243 | return NULL; |
| 244 | } |
| 245 | |
Pavlin Radoslavov | b2a292b | 2016-10-14 19:34:48 -0700 | [diff] [blame] | 246 | EXPORT_SYMBOL extern const module_t btsnoop_module = { |
Myles Watson | 5ff20a2 | 2016-10-31 10:53:52 -0700 | [diff] [blame] | 247 | .name = BTSNOOP_MODULE, |
| 248 | .init = NULL, |
| 249 | .start_up = start_up, |
| 250 | .shut_down = shut_down, |
| 251 | .clean_up = NULL, |
| 252 | .dependencies = {STACK_CONFIG_MODULE, NULL}}; |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 253 | |
| 254 | // Interface functions |
Myles Watson | 5ff20a2 | 2016-10-31 10:53:52 -0700 | [diff] [blame] | 255 | static void capture(const BT_HDR* buffer, bool is_received) { |
Andre Eisenbach | 796523d | 2016-11-10 16:11:00 -0800 | [diff] [blame] | 256 | uint8_t* p = const_cast<uint8_t*>(buffer->data + buffer->offset); |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 257 | |
Pavlin Radoslavov | 3060ec6 | 2017-02-16 11:51:48 -0800 | [diff] [blame] | 258 | std::lock_guard<std::mutex> lock(btsnoop_mutex); |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 259 | |
| 260 | struct timespec ts_now = {}; |
| 261 | clock_gettime(CLOCK_REALTIME, &ts_now); |
| 262 | uint64_t timestamp_us = |
| 263 | ((uint64_t)ts_now.tv_sec * 1000000L) + ((uint64_t)ts_now.tv_nsec / 1000); |
| 264 | |
Jack He | 071b507 | 2017-02-07 17:25:15 -0800 | [diff] [blame] | 265 | btsnoop_mem_capture(buffer, timestamp_us); |
Andre Eisenbach | 89f5e41 | 2014-12-05 09:40:20 -0800 | [diff] [blame] | 266 | |
Myles Watson | 5ff20a2 | 2016-10-31 10:53:52 -0700 | [diff] [blame] | 267 | if (logfile_fd == INVALID_FD) return; |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 268 | |
| 269 | switch (buffer->event & MSG_EVT_MASK) { |
| 270 | case MSG_HC_TO_STACK_HCI_EVT: |
Jack He | 071b507 | 2017-02-07 17:25:15 -0800 | [diff] [blame] | 271 | btsnoop_write_packet(kEventPacket, p, false, timestamp_us); |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 272 | break; |
| 273 | case MSG_HC_TO_STACK_HCI_ACL: |
| 274 | case MSG_STACK_TO_HC_HCI_ACL: |
Jack He | 071b507 | 2017-02-07 17:25:15 -0800 | [diff] [blame] | 275 | btsnoop_write_packet(kAclPacket, p, is_received, timestamp_us); |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 276 | break; |
| 277 | case MSG_HC_TO_STACK_HCI_SCO: |
| 278 | case MSG_STACK_TO_HC_HCI_SCO: |
Jack He | 071b507 | 2017-02-07 17:25:15 -0800 | [diff] [blame] | 279 | btsnoop_write_packet(kScoPacket, p, is_received, timestamp_us); |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 280 | break; |
| 281 | case MSG_STACK_TO_HC_HCI_CMD: |
Jack He | 071b507 | 2017-02-07 17:25:15 -0800 | [diff] [blame] | 282 | btsnoop_write_packet(kCommandPacket, p, true, timestamp_us); |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 283 | break; |
| 284 | } |
| 285 | } |
| 286 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 287 | static void whitelist_l2c_channel(uint16_t conn_handle, uint16_t local_cid, |
| 288 | uint16_t remote_cid) { |
| 289 | LOG(INFO) << __func__ |
| 290 | << ": Whitelisting l2cap channel. conn_handle=" << conn_handle |
| 291 | << " cid=" << loghex(local_cid) << ":" << loghex(remote_cid); |
| 292 | std::lock_guard lock(filter_list_mutex); |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 293 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 294 | // This will create the entry if there is no associated filter with the |
| 295 | // connection. |
| 296 | filter_list[conn_handle].addL2cCid(local_cid, remote_cid); |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 297 | } |
| 298 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 299 | static void whitelist_rfc_dlci(uint16_t local_cid, uint8_t dlci) { |
| 300 | LOG(INFO) << __func__ |
| 301 | << ": Whitelisting rfcomm channel. L2CAP CID=" << loghex(local_cid) |
| 302 | << " DLCI=" << loghex(dlci); |
| 303 | std::lock_guard lock(filter_list_mutex); |
| 304 | |
| 305 | tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(nullptr, local_cid); |
| 306 | filter_list[p_ccb->p_lcb->handle].addRfcDlci(dlci); |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 307 | } |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 308 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 309 | static void add_rfc_l2c_channel(uint16_t conn_handle, uint16_t local_cid, |
| 310 | uint16_t remote_cid) { |
| 311 | LOG(INFO) << __func__ |
| 312 | << ": rfcomm data going over l2cap channel. conn_handle=" |
| 313 | << conn_handle << " cid=" << loghex(local_cid) << ":" |
| 314 | << loghex(remote_cid); |
| 315 | std::lock_guard lock(filter_list_mutex); |
| 316 | |
| 317 | filter_list[conn_handle].setRfcCid(local_cid, remote_cid); |
| 318 | local_cid_to_acl.insert({local_cid, conn_handle}); |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 319 | } |
Pavlin Radoslavov | 3060ec6 | 2017-02-16 11:51:48 -0800 | [diff] [blame] | 320 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 321 | static void clear_l2cap_whitelist(uint16_t conn_handle, uint16_t local_cid, |
| 322 | uint16_t remote_cid) { |
| 323 | LOG(INFO) << __func__ |
| 324 | << ": Clearing whitelist from l2cap channel. conn_handle=" |
| 325 | << conn_handle << " cid=" << local_cid << ":" << remote_cid; |
| 326 | |
| 327 | std::lock_guard lock(filter_list_mutex); |
| 328 | filter_list[conn_handle].removeL2cCid(local_cid, remote_cid); |
| 329 | } |
| 330 | |
| 331 | static const btsnoop_t interface = {capture, whitelist_l2c_channel, |
| 332 | whitelist_rfc_dlci, add_rfc_l2c_channel, |
| 333 | clear_l2cap_whitelist}; |
| 334 | |
| 335 | const btsnoop_t* btsnoop_get_interface() { return &interface; } |
| 336 | |
| 337 | static void delete_btsnoop_files(bool filtered) { |
| 338 | LOG(INFO) << __func__ |
| 339 | << ": Deleting snoop logs if they exist. filtered = " << filtered; |
| 340 | auto log_path = get_btsnoop_log_path(filtered); |
| 341 | remove(log_path.c_str()); |
| 342 | remove(get_btsnoop_last_log_path(log_path).c_str()); |
| 343 | } |
| 344 | |
| 345 | std::string get_btsnoop_log_path(bool filtered) { |
| 346 | char btsnoop_path[PROPERTY_VALUE_MAX]; |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 347 | osi_property_get(BTSNOOP_PATH_PROPERTY, btsnoop_path, DEFAULT_BTSNOOP_PATH); |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 348 | std::string result(btsnoop_path); |
| 349 | if (filtered) result = result.append(".filtered"); |
| 350 | |
| 351 | return result; |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 352 | } |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 353 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 354 | std::string get_btsnoop_last_log_path(std::string btsnoop_path) { |
| 355 | return btsnoop_path.append(".last"); |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 356 | } |
Ajay Panicker | f786aac | 2017-03-30 10:33:19 -0700 | [diff] [blame] | 357 | |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 358 | static void open_next_snoop_file() { |
| 359 | packet_counter = 0; |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 360 | |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 361 | if (logfile_fd != INVALID_FD) { |
| 362 | close(logfile_fd); |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 363 | logfile_fd = INVALID_FD; |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 364 | } |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 365 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 366 | auto log_path = get_btsnoop_log_path(is_btsnoop_filtered); |
| 367 | auto last_log_path = get_btsnoop_last_log_path(log_path); |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 368 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 369 | if (rename(log_path.c_str(), last_log_path.c_str()) != 0 && errno != ENOENT) |
| 370 | LOG(ERROR) << __func__ << ": unable to rename '" << log_path << "' to '" |
| 371 | << last_log_path << "' : " << strerror(errno); |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 372 | |
| 373 | mode_t prevmask = umask(0); |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 374 | logfile_fd = open(log_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 375 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); |
| 376 | umask(prevmask); |
| 377 | if (logfile_fd == INVALID_FD) { |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 378 | LOG(ERROR) << __func__ << ": unable to open '" << log_path |
| 379 | << "' : " << strerror(errno); |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 380 | return; |
| 381 | } |
| 382 | |
| 383 | write(logfile_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16); |
Zach Johnson | 9891f32 | 2014-09-22 22:11:55 -0700 | [diff] [blame] | 384 | } |
| 385 | |
Andre Eisenbach | 796523d | 2016-11-10 16:11:00 -0800 | [diff] [blame] | 386 | typedef struct { |
| 387 | uint32_t length_original; |
| 388 | uint32_t length_captured; |
| 389 | uint32_t flags; |
| 390 | uint32_t dropped_packets; |
| 391 | uint64_t timestamp; |
| 392 | uint8_t type; |
| 393 | } __attribute__((__packed__)) btsnoop_header_t; |
Sharvil Nanavati | a7d7eb7 | 2014-06-14 23:45:16 -0700 | [diff] [blame] | 394 | |
Andre Eisenbach | 796523d | 2016-11-10 16:11:00 -0800 | [diff] [blame] | 395 | static uint64_t htonll(uint64_t ll) { |
Pavlin Radoslavov | 16b3e92 | 2017-02-06 18:48:18 -0800 | [diff] [blame] | 396 | const uint32_t l = 1; |
| 397 | if (*(reinterpret_cast<const uint8_t*>(&l)) == 1) |
| 398 | return static_cast<uint64_t>(htonl(ll & 0xffffffff)) << 32 | |
| 399 | htonl(ll >> 32); |
| 400 | |
Andre Eisenbach | 796523d | 2016-11-10 16:11:00 -0800 | [diff] [blame] | 401 | return ll; |
Sharvil Nanavati | 611f3ab | 2014-03-22 14:27:07 -0700 | [diff] [blame] | 402 | } |
Kim Schulz | f1d68e9 | 2013-09-23 12:48:47 +0200 | [diff] [blame] | 403 | |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 404 | static bool should_filter_log(bool is_received, uint8_t* packet) { |
| 405 | uint16_t acl_handle = |
| 406 | HCID_GET_HANDLE((((uint16_t)packet[ACL_CHANNEL_OFFSET + 1]) << 8) + |
| 407 | packet[ACL_CHANNEL_OFFSET]); |
| 408 | |
| 409 | std::lock_guard lock(filter_list_mutex); |
| 410 | auto& filters = filter_list[acl_handle]; |
| 411 | uint16_t l2c_channel = |
| 412 | (packet[L2C_CHANNEL_OFFSET + 1] << 8) + packet[L2C_CHANNEL_OFFSET]; |
| 413 | if (filters.isRfcChannel(is_received, l2c_channel)) { |
| 414 | uint8_t rfc_event = packet[RFC_EVENT_OFFSET] & 0b11101111; |
| 415 | if (rfc_event == RFCOMM_SABME || rfc_event == RFCOMM_UA) { |
| 416 | return false; |
| 417 | } |
| 418 | |
| 419 | uint8_t rfc_dlci = packet[RFC_CHANNEL_OFFSET] >> 2; |
| 420 | if (!filters.isWhitelistedDlci(rfc_dlci)) { |
| 421 | return true; |
| 422 | } |
| 423 | } else if (!filters.isWhitelistedL2c(is_received, l2c_channel)) { |
| 424 | return true; |
| 425 | } |
| 426 | |
| 427 | return false; |
| 428 | } |
| 429 | |
Andre Eisenbach | 796523d | 2016-11-10 16:11:00 -0800 | [diff] [blame] | 430 | static void btsnoop_write_packet(packet_type_t type, uint8_t* packet, |
Jack He | 071b507 | 2017-02-07 17:25:15 -0800 | [diff] [blame] | 431 | bool is_received, uint64_t timestamp_us) { |
Andre Eisenbach | 796523d | 2016-11-10 16:11:00 -0800 | [diff] [blame] | 432 | uint32_t length_he = 0; |
| 433 | uint32_t flags = 0; |
| 434 | |
Sharvil Nanavati | a7d7eb7 | 2014-06-14 23:45:16 -0700 | [diff] [blame] | 435 | switch (type) { |
| 436 | case kCommandPacket: |
| 437 | length_he = packet[2] + 4; |
| 438 | flags = 2; |
| 439 | break; |
| 440 | case kAclPacket: |
| 441 | length_he = (packet[3] << 8) + packet[2] + 5; |
| 442 | flags = is_received; |
| 443 | break; |
| 444 | case kScoPacket: |
| 445 | length_he = packet[2] + 4; |
| 446 | flags = is_received; |
| 447 | break; |
| 448 | case kEventPacket: |
| 449 | length_he = packet[1] + 3; |
| 450 | flags = 3; |
| 451 | break; |
| 452 | } |
Sharvil Nanavati | 611f3ab | 2014-03-22 14:27:07 -0700 | [diff] [blame] | 453 | |
Andre Eisenbach | 796523d | 2016-11-10 16:11:00 -0800 | [diff] [blame] | 454 | btsnoop_header_t header; |
| 455 | header.length_original = htonl(length_he); |
Ajay Panicker | 8303629 | 2018-11-16 13:06:47 -0800 | [diff] [blame] | 456 | |
| 457 | bool blacklisted = false; |
| 458 | if (is_btsnoop_filtered && type == kAclPacket) { |
| 459 | blacklisted = should_filter_log(is_received, packet); |
| 460 | } |
| 461 | |
| 462 | header.length_captured = |
| 463 | blacklisted ? htonl(L2C_HEADER_SIZE) : header.length_original; |
| 464 | if (blacklisted) length_he = L2C_HEADER_SIZE; |
Andre Eisenbach | 796523d | 2016-11-10 16:11:00 -0800 | [diff] [blame] | 465 | header.flags = htonl(flags); |
| 466 | header.dropped_packets = 0; |
Jack He | 071b507 | 2017-02-07 17:25:15 -0800 | [diff] [blame] | 467 | header.timestamp = htonll(timestamp_us + BTSNOOP_EPOCH_DELTA); |
Andre Eisenbach | 796523d | 2016-11-10 16:11:00 -0800 | [diff] [blame] | 468 | header.type = type; |
Kim Schulz | f1d68e9 | 2013-09-23 12:48:47 +0200 | [diff] [blame] | 469 | |
Andre Eisenbach | 796523d | 2016-11-10 16:11:00 -0800 | [diff] [blame] | 470 | btsnoop_net_write(&header, sizeof(btsnoop_header_t)); |
| 471 | btsnoop_net_write(packet, length_he - 1); |
Kim Schulz | f1d68e9 | 2013-09-23 12:48:47 +0200 | [diff] [blame] | 472 | |
Andre Eisenbach | 796523d | 2016-11-10 16:11:00 -0800 | [diff] [blame] | 473 | if (logfile_fd != INVALID_FD) { |
Ajay Panicker | 99c3422 | 2017-04-17 20:53:24 -0700 | [diff] [blame] | 474 | packet_counter++; |
| 475 | if (packet_counter > packets_per_file) { |
| 476 | open_next_snoop_file(); |
| 477 | } |
| 478 | |
Andre Eisenbach | 796523d | 2016-11-10 16:11:00 -0800 | [diff] [blame] | 479 | iovec iov[] = {{&header, sizeof(btsnoop_header_t)}, |
| 480 | {reinterpret_cast<void*>(packet), length_he - 1}}; |
| 481 | TEMP_FAILURE_RETRY(writev(logfile_fd, iov, 2)); |
| 482 | } |
The Android Open Source Project | 5738f83 | 2012-12-12 16:00:35 -0800 | [diff] [blame] | 483 | } |