OSDN Git Service

Add Filtering for snoop logs based on L2CAP and RFCOMM Channels (1/4)
authorAjay Panicker <apanicke@google.com>
Fri, 16 Nov 2018 21:06:47 +0000 (13:06 -0800)
committerAjay Panicker <apanicke@google.com>
Tue, 15 Jan 2019 19:53:48 +0000 (11:53 -0800)
* Change btsnoop logging into disabled, filtered, and full modes
* When ro.isdebuggable is 1, filtered logging is enabled by default
* Otherwise, disabled by default
* When legacy mode is enabled, translate it to full and reset legacy
  property to empty

Bug: 112970672
Bug: 67669544
Test: See that the snoop file always exists but is filtered when
snooplogs are disabled and unfiltered when enabled.
Change-Id: I894d36cfd976d03c788626b9197fea1182a6f3ba

18 files changed:
hci/include/btsnoop.h
hci/src/btsnoop.cc
stack/avct/avct_api.cc
stack/avdt/avdt_api.cc
stack/bnep/bnep_main.cc
stack/gap/gap_conn.cc
stack/gatt/gatt_main.cc
stack/hid/hidd_conn.cc
stack/hid/hidh_conn.cc
stack/include/l2c_api.h
stack/l2cap/l2c_api.cc
stack/l2cap/l2c_int.h
stack/l2cap/l2c_main.cc
stack/l2cap/l2c_utils.cc
stack/rfcomm/rfc_l2cap_if.cc
stack/rfcomm/rfc_port_fsm.cc
stack/sdp/sdp_main.cc
stack/test/rfcomm/stack_rfcomm_test.cc

index e897a96..476c62d 100644 (file)
@@ -29,6 +29,28 @@ typedef struct btsnoop_t {
   // true, the packet is marked as incoming. Otherwise, the packet is marked
   // as outgoing.
   void (*capture)(const BT_HDR* packet, bool is_received);
+
+  // Set a L2CAP channel as whitelisted, allowing packets with that L2CAP CID
+  // to show up in the snoop logs.
+  void (*whitelist_l2c_channel)(uint16_t conn_handle, uint16_t local_cid,
+                                uint16_t remote_cid);
+
+  // Set a RFCOMM dlci as whitelisted, allowing packets with that RFCOMM CID
+  // to show up in the snoop logs. The local_cid is used to associate it with
+  // its corrisponding ACL connection. The dlci is the channel with direction
+  // so there is no chance of a collision if two services are using the same
+  // channel but in different directions.
+  void (*whitelist_rfc_dlci)(uint16_t local_cid, uint8_t dlci);
+
+  // Indicate that the provided L2CAP channel is being used for RFCOMM.
+  // If packets with the provided L2CAP CID are encountered, they will be
+  // filtered on RFCOMM based on channels provided to |filter_rfc_channel|.
+  void (*add_rfc_l2c_channel)(uint16_t conn_handle, uint16_t local_cid,
+                              uint16_t remote_cid);
+
+  // Clear an L2CAP channel from being filtered.
+  void (*clear_l2cap_whitelist)(uint16_t conn_handle, uint16_t local_cid,
+                                uint16_t remote_cid);
 } btsnoop_t;
 
 const btsnoop_t* btsnoop_get_interface(void);
index 6938725..e8db278 100644 (file)
@@ -21,6 +21,7 @@
 #include <mutex>
 
 #include <arpa/inet.h>
+#include <base/logging.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
 #include <sys/time.h>
 #include <sys/uio.h>
 #include <unistd.h>
+#include <mutex>
+#include <unordered_map>
+#include <unordered_set>
 
 #include "bt_types.h"
 #include "common/time_util.h"
 #include "hci/include/btsnoop.h"
 #include "hci/include/btsnoop_mem.h"
 #include "hci_layer.h"
+#include "internal_include/bt_trace.h"
 #include "osi/include/log.h"
 #include "osi/include/properties.h"
+#include "stack/include/hcimsgs.h"
+#include "stack/include/rfcdefs.h"
+#include "stack/l2cap/l2c_int.h"
 #include "stack_config.h"
 
 // The number of of packets per btsnoop file before we rotate to the next
 // property
 #define DEFAULT_BTSNOOP_SIZE 0xffff
 
-#define BTSNOOP_ENABLE_PROPERTY "persist.bluetooth.btsnoopenable"
+#define IS_DEBUGGABLE_PROPERTY "ro.debuggable"
+
+#define BTSNOOP_LOG_MODE_PROPERTY "persist.bluetooth.btsnooplogmode"
+#define BTSNOOP_DEFAULT_MODE_PROPERTY "persist.bluetooth.btsnoopdefaultmode"
+#define BTSNOOP_MODE_DISABLED "disabled"
+#define BTSNOOP_MODE_FILTERED "filtered"
+#define BTSNOOP_MODE_FULL "full"
+
 #define BTSNOOP_PATH_PROPERTY "persist.bluetooth.btsnooppath"
 #define DEFAULT_BTSNOOP_PATH "/data/misc/bluetooth/logs/btsnoop_hci.log"
 #define BTSNOOP_MAX_PACKETS_PROPERTY "persist.bluetooth.btsnoopsize"
@@ -65,33 +80,138 @@ typedef enum {
 // Epoch in microseconds since 01/01/0000.
 static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
 
+// Number of bytes into a packet where you can find the value for a channel.
+static const size_t ACL_CHANNEL_OFFSET = 0;
+static const size_t L2C_CHANNEL_OFFSET = 6;
+static const size_t RFC_CHANNEL_OFFSET = 8;
+static const size_t RFC_EVENT_OFFSET = 9;
+
+// The size of the L2CAP header. All information past this point is removed from
+// a filtered packet.
+static const uint32_t L2C_HEADER_SIZE = 9;
+
 static int logfile_fd = INVALID_FD;
 static std::mutex btsnoop_mutex;
 
 static int32_t packets_per_file;
 static int32_t packet_counter;
 
+// Channel tracking variables for filtering.
+
+// Keeps track of L2CAP channels that need to be filtered out of the snoop
+// logs.
+class FilterTracker {
+ public:
+  // NOTE: 1 is used as a static CID for L2CAP signaling
+  std::unordered_set<uint16_t> l2c_local_cid = {1};
+  std::unordered_set<uint16_t> l2c_remote_cid = {1};
+  uint16_t rfc_local_cid = 0;
+  uint16_t rfc_remote_cid = 0;
+  std::unordered_set<uint16_t> rfc_channels = {0};
+
+  // Adds L2C channel to whitelist.
+  void addL2cCid(uint16_t local_cid, uint16_t remote_cid) {
+    l2c_local_cid.insert(local_cid);
+    l2c_remote_cid.insert(remote_cid);
+  }
+
+  // Sets L2CAP channel that RFCOMM uses.
+  void setRfcCid(uint16_t local_cid, uint16_t remote_cid) {
+    rfc_local_cid = local_cid;
+    rfc_remote_cid = remote_cid;
+  }
+
+  // Remove L2C channel from whitelist.
+  void removeL2cCid(uint16_t local_cid, uint16_t remote_cid) {
+    if (rfc_local_cid == local_cid) {
+      rfc_channels.clear();
+      rfc_channels.insert(0);
+      rfc_local_cid = 0;
+      rfc_remote_cid = 0;
+    }
+
+    l2c_local_cid.erase(local_cid);
+    l2c_remote_cid.erase(remote_cid);
+  }
+
+  void addRfcDlci(uint8_t channel) { rfc_channels.insert(channel); }
+
+  bool isWhitelistedL2c(bool local, uint16_t cid) {
+    const auto& set = local ? l2c_local_cid : l2c_remote_cid;
+    return (set.find(cid) != set.end());
+  }
+
+  bool isRfcChannel(bool local, uint16_t cid) {
+    const auto& channel = local ? rfc_local_cid : rfc_remote_cid;
+    return cid == channel;
+  }
+
+  bool isWhitelistedDlci(uint8_t dlci) {
+    return rfc_channels.find(dlci) != rfc_channels.end();
+  }
+};
+
+std::mutex filter_list_mutex;
+std::unordered_map<uint16_t, FilterTracker> filter_list;
+std::unordered_map<uint16_t, uint16_t> local_cid_to_acl;
+
+// Cached value for whether full snoop logs are enabled. So the property isn't
+// checked for every packet.
+static bool is_btsnoop_enabled;
+static bool is_btsnoop_filtered;
+
 // TODO(zachoverflow): merge btsnoop and btsnoop_net together
 void btsnoop_net_open();
 void btsnoop_net_close();
 void btsnoop_net_write(const void* data, size_t length);
 
-static void delete_btsnoop_files();
-static bool is_btsnoop_enabled();
-static char* get_btsnoop_log_path(char* log_path);
-static char* get_btsnoop_last_log_path(char* last_log_path, char* log_path);
+static void delete_btsnoop_files(bool filtered);
+static std::string get_btsnoop_log_path(bool filtered);
+static std::string get_btsnoop_last_log_path(std::string log_path);
 static void open_next_snoop_file();
 static void btsnoop_write_packet(packet_type_t type, uint8_t* packet,
                                  bool is_received, uint64_t timestamp_us);
 
 // Module lifecycle functions
 
-static future_t* start_up(void) {
+static future_t* start_up() {
+  std::array<char, PROPERTY_VALUE_MAX> property = {};
   std::lock_guard<std::mutex> lock(btsnoop_mutex);
 
-  if (!is_btsnoop_enabled()) {
-    delete_btsnoop_files();
+  // Default mode is FILTERED on userdebug/eng build, DISABLED on user build.
+  // It can also be overwritten by modifying the global setting.
+  int is_debuggable = osi_property_get_int32(IS_DEBUGGABLE_PROPERTY, 0);
+  std::string default_mode = BTSNOOP_MODE_DISABLED;
+  if (is_debuggable) {
+    int len = osi_property_get(BTSNOOP_DEFAULT_MODE_PROPERTY, property.data(),
+                               BTSNOOP_MODE_FILTERED);
+    default_mode = std::string(property.data(), len);
+  }
+
+  // Get the actual mode
+  int len = osi_property_get(BTSNOOP_LOG_MODE_PROPERTY, property.data(),
+                             default_mode.c_str());
+  std::string btsnoop_mode(property.data(), len);
+
+  if (btsnoop_mode == BTSNOOP_MODE_FILTERED) {
+    LOG(INFO) << __func__ << ": Filtered Snoop Logs enabled";
+    is_btsnoop_enabled = true;
+    is_btsnoop_filtered = true;
+    delete_btsnoop_files(false);
+  } else if (btsnoop_mode == BTSNOOP_MODE_FULL) {
+    LOG(INFO) << __func__ << ": Snoop Logs fully enabled";
+    is_btsnoop_enabled = true;
+    is_btsnoop_filtered = false;
+    delete_btsnoop_files(true);
   } else {
+    LOG(INFO) << __func__ << ": Snoop Logs disabled";
+    is_btsnoop_enabled = false;
+    is_btsnoop_filtered = false;
+    delete_btsnoop_files(true);
+    delete_btsnoop_files(false);
+  }
+
+  if (is_btsnoop_enabled) {
     open_next_snoop_file();
     packets_per_file = osi_property_get_int32(BTSNOOP_MAX_PACKETS_PROPERTY,
                                               DEFAULT_BTSNOOP_SIZE);
@@ -104,14 +224,21 @@ static future_t* start_up(void) {
 static future_t* shut_down(void) {
   std::lock_guard<std::mutex> lock(btsnoop_mutex);
 
-  if (!is_btsnoop_enabled()) {
-    delete_btsnoop_files();
+  if (is_btsnoop_enabled) {
+    if (is_btsnoop_filtered) {
+      delete_btsnoop_files(false);
+    } else {
+      delete_btsnoop_files(true);
+    }
+  } else {
+    delete_btsnoop_files(true);
+    delete_btsnoop_files(false);
   }
 
   if (logfile_fd != INVALID_FD) close(logfile_fd);
   logfile_fd = INVALID_FD;
 
-  btsnoop_net_close();
+  if (is_btsnoop_enabled) btsnoop_net_close();
 
   return NULL;
 }
@@ -129,7 +256,12 @@ static void capture(const BT_HDR* buffer, bool is_received) {
   uint8_t* p = const_cast<uint8_t*>(buffer->data + buffer->offset);
 
   std::lock_guard<std::mutex> lock(btsnoop_mutex);
-  uint64_t timestamp_us = bluetooth::common::time_gettimeofday_us();
+
+  struct timespec ts_now = {};
+  clock_gettime(CLOCK_REALTIME, &ts_now);
+  uint64_t timestamp_us =
+      ((uint64_t)ts_now.tv_sec * 1000000L) + ((uint64_t)ts_now.tv_nsec / 1000);
+
   btsnoop_mem_capture(buffer, timestamp_us);
 
   if (logfile_fd == INVALID_FD) return;
@@ -152,39 +284,75 @@ static void capture(const BT_HDR* buffer, bool is_received) {
   }
 }
 
-static const btsnoop_t interface = {capture};
+static void whitelist_l2c_channel(uint16_t conn_handle, uint16_t local_cid,
+                                  uint16_t remote_cid) {
+  LOG(INFO) << __func__
+            << ": Whitelisting l2cap channel. conn_handle=" << conn_handle
+            << " cid=" << loghex(local_cid) << ":" << loghex(remote_cid);
+  std::lock_guard lock(filter_list_mutex);
 
-const btsnoop_t* btsnoop_get_interface() {
-  return &interface;
+  // This will create the entry if there is no associated filter with the
+  // connection.
+  filter_list[conn_handle].addL2cCid(local_cid, remote_cid);
 }
 
-// Internal functions
-static void delete_btsnoop_files() {
-  LOG_VERBOSE(LOG_TAG, "Deleting snoop log if it exists");
-  char log_path[PROPERTY_VALUE_MAX];
-  char last_log_path[PROPERTY_VALUE_MAX + sizeof(".last")];
-  get_btsnoop_log_path(log_path);
-  get_btsnoop_last_log_path(last_log_path, log_path);
-  remove(log_path);
-  remove(last_log_path);
+static void whitelist_rfc_dlci(uint16_t local_cid, uint8_t dlci) {
+  LOG(INFO) << __func__
+            << ": Whitelisting rfcomm channel. L2CAP CID=" << loghex(local_cid)
+            << " DLCI=" << loghex(dlci);
+  std::lock_guard lock(filter_list_mutex);
+
+  tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(nullptr, local_cid);
+  filter_list[p_ccb->p_lcb->handle].addRfcDlci(dlci);
 }
 
-static bool is_btsnoop_enabled() {
-  char btsnoop_enabled[PROPERTY_VALUE_MAX] = {0};
-  osi_property_get(BTSNOOP_ENABLE_PROPERTY, btsnoop_enabled, "false");
-  return strncmp(btsnoop_enabled, "true", 4) == 0;
+static void add_rfc_l2c_channel(uint16_t conn_handle, uint16_t local_cid,
+                                uint16_t remote_cid) {
+  LOG(INFO) << __func__
+            << ": rfcomm data going over l2cap channel. conn_handle="
+            << conn_handle << " cid=" << loghex(local_cid) << ":"
+            << loghex(remote_cid);
+  std::lock_guard lock(filter_list_mutex);
+
+  filter_list[conn_handle].setRfcCid(local_cid, remote_cid);
+  local_cid_to_acl.insert({local_cid, conn_handle});
 }
 
-static char* get_btsnoop_log_path(char* btsnoop_path) {
+static void clear_l2cap_whitelist(uint16_t conn_handle, uint16_t local_cid,
+                                  uint16_t remote_cid) {
+  LOG(INFO) << __func__
+            << ": Clearing whitelist from l2cap channel. conn_handle="
+            << conn_handle << " cid=" << local_cid << ":" << remote_cid;
+
+  std::lock_guard lock(filter_list_mutex);
+  filter_list[conn_handle].removeL2cCid(local_cid, remote_cid);
+}
+
+static const btsnoop_t interface = {capture, whitelist_l2c_channel,
+                                    whitelist_rfc_dlci, add_rfc_l2c_channel,
+                                    clear_l2cap_whitelist};
+
+const btsnoop_t* btsnoop_get_interface() { return &interface; }
+
+static void delete_btsnoop_files(bool filtered) {
+  LOG(INFO) << __func__
+            << ": Deleting snoop logs if they exist. filtered = " << filtered;
+  auto log_path = get_btsnoop_log_path(filtered);
+  remove(log_path.c_str());
+  remove(get_btsnoop_last_log_path(log_path).c_str());
+}
+
+std::string get_btsnoop_log_path(bool filtered) {
+  char btsnoop_path[PROPERTY_VALUE_MAX];
   osi_property_get(BTSNOOP_PATH_PROPERTY, btsnoop_path, DEFAULT_BTSNOOP_PATH);
-  return btsnoop_path;
+  std::string result(btsnoop_path);
+  if (filtered) result = result.append(".filtered");
+
+  return result;
 }
 
-static char* get_btsnoop_last_log_path(char* last_log_path,
-                                       char* btsnoop_path) {
-  snprintf(last_log_path, PROPERTY_VALUE_MAX + sizeof(".last"), "%s.last",
-           btsnoop_path);
-  return last_log_path;
+std::string get_btsnoop_last_log_path(std::string btsnoop_path) {
+  return btsnoop_path.append(".last");
 }
 
 static void open_next_snoop_file() {
@@ -195,22 +363,20 @@ static void open_next_snoop_file() {
     logfile_fd = INVALID_FD;
   }
 
-  char log_path[PROPERTY_VALUE_MAX];
-  char last_log_path[PROPERTY_VALUE_MAX + sizeof(".last")];
-  get_btsnoop_log_path(log_path);
-  get_btsnoop_last_log_path(last_log_path, log_path);
+  auto log_path = get_btsnoop_log_path(is_btsnoop_filtered);
+  auto last_log_path = get_btsnoop_last_log_path(log_path);
 
-  if (rename(log_path, last_log_path) != 0 && errno != ENOENT)
-    LOG_ERROR(LOG_TAG, "%s unable to rename '%s' to '%s': %s", __func__,
-              log_path, last_log_path, strerror(errno));
+  if (rename(log_path.c_str(), last_log_path.c_str()) != 0 && errno != ENOENT)
+    LOG(ERROR) << __func__ << ": unable to rename '" << log_path << "' to '"
+               << last_log_path << "' : " << strerror(errno);
 
   mode_t prevmask = umask(0);
-  logfile_fd = open(log_path, O_WRONLY | O_CREAT | O_TRUNC,
+  logfile_fd = open(log_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC,
                     S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
   umask(prevmask);
   if (logfile_fd == INVALID_FD) {
-    LOG_ERROR(LOG_TAG, "%s unable to open '%s': %s", __func__, log_path,
-              strerror(errno));
+    LOG(ERROR) << __func__ << ": unable to open '" << log_path
+               << "' : " << strerror(errno);
     return;
   }
 
@@ -235,6 +401,32 @@ static uint64_t htonll(uint64_t ll) {
   return ll;
 }
 
+static bool should_filter_log(bool is_received, uint8_t* packet) {
+  uint16_t acl_handle =
+      HCID_GET_HANDLE((((uint16_t)packet[ACL_CHANNEL_OFFSET + 1]) << 8) +
+                      packet[ACL_CHANNEL_OFFSET]);
+
+  std::lock_guard lock(filter_list_mutex);
+  auto& filters = filter_list[acl_handle];
+  uint16_t l2c_channel =
+      (packet[L2C_CHANNEL_OFFSET + 1] << 8) + packet[L2C_CHANNEL_OFFSET];
+  if (filters.isRfcChannel(is_received, l2c_channel)) {
+    uint8_t rfc_event = packet[RFC_EVENT_OFFSET] & 0b11101111;
+    if (rfc_event == RFCOMM_SABME || rfc_event == RFCOMM_UA) {
+      return false;
+    }
+
+    uint8_t rfc_dlci = packet[RFC_CHANNEL_OFFSET] >> 2;
+    if (!filters.isWhitelistedDlci(rfc_dlci)) {
+      return true;
+    }
+  } else if (!filters.isWhitelistedL2c(is_received, l2c_channel)) {
+    return true;
+  }
+
+  return false;
+}
+
 static void btsnoop_write_packet(packet_type_t type, uint8_t* packet,
                                  bool is_received, uint64_t timestamp_us) {
   uint32_t length_he = 0;
@@ -261,7 +453,15 @@ static void btsnoop_write_packet(packet_type_t type, uint8_t* packet,
 
   btsnoop_header_t header;
   header.length_original = htonl(length_he);
-  header.length_captured = header.length_original;
+
+  bool blacklisted = false;
+  if (is_btsnoop_filtered && type == kAclPacket) {
+    blacklisted = should_filter_log(is_received, packet);
+  }
+
+  header.length_captured =
+      blacklisted ? htonl(L2C_HEADER_SIZE) : header.length_original;
+  if (blacklisted) length_he = L2C_HEADER_SIZE;
   header.flags = htonl(flags);
   header.dropped_packets = 0;
   header.timestamp = htonll(timestamp_us + BTSNOOP_EPOCH_DELTA);
index 5ced71f..51e2daf 100644 (file)
@@ -56,7 +56,8 @@ void AVCT_Register(uint16_t mtu, UNUSED_ATTR uint16_t mtu_br,
   AVCT_TRACE_API("AVCT_Register");
 
   /* register PSM with L2CAP */
-  L2CA_Register(AVCT_PSM, (tL2CAP_APPL_INFO*)&avct_l2c_appl);
+  L2CA_Register(AVCT_PSM, (tL2CAP_APPL_INFO*)&avct_l2c_appl,
+                true /* enable_snoop */);
 
   /* set security level */
   BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVCTP, sec_mask, AVCT_PSM, 0,
@@ -68,7 +69,8 @@ void AVCT_Register(uint16_t mtu, UNUSED_ATTR uint16_t mtu_br,
   memset(&avct_cb, 0, sizeof(tAVCT_CB));
 
   /* Include the browsing channel which uses eFCR */
-  L2CA_Register(AVCT_BR_PSM, (tL2CAP_APPL_INFO*)&avct_l2c_br_appl);
+  L2CA_Register(AVCT_BR_PSM, (tL2CAP_APPL_INFO*)&avct_l2c_br_appl,
+                true /*enable_snoop*/);
 
   /* AVCTP browsing channel uses the same security service as AVCTP control
    * channel */
index 903862e..9350c31 100644 (file)
@@ -90,7 +90,8 @@ void avdt_scb_transport_channel_timer_timeout(void* data) {
  ******************************************************************************/
 void AVDT_Register(AvdtpRcb* p_reg, tAVDT_CTRL_CBACK* p_cback) {
   /* register PSM with L2CAP */
-  L2CA_Register(AVDT_PSM, (tL2CAP_APPL_INFO*)&avdt_l2c_appl);
+  L2CA_Register(AVDT_PSM, (tL2CAP_APPL_INFO*)&avdt_l2c_appl,
+                true /* enable_snoop */);
 
   /* set security level */
   BTM_SetSecurityLevel(true, "", BTM_SEC_SERVICE_AVDTP, p_reg->sec_mask,
index ae6c51b..265ec79 100644 (file)
@@ -94,7 +94,8 @@ tBNEP_RESULT bnep_register_with_l2cap(void) {
   bnep_cb.reg_info.pL2CA_CongestionStatus_Cb = bnep_congestion_ind;
 
   /* Now, register with L2CAP */
-  if (!L2CA_Register(BT_PSM_BNEP, &bnep_cb.reg_info)) {
+  if (!L2CA_Register(BT_PSM_BNEP, &bnep_cb.reg_info,
+                     false /* enable_snoop */)) {
     BNEP_TRACE_ERROR("BNEP - Registration failed");
     return BNEP_SECURITY_FAIL;
   }
index 72183bb..15d3ddb 100644 (file)
@@ -235,8 +235,7 @@ uint16_t GAP_ConnOpen(const char* p_serv_name, uint8_t service_id,
 
   /* Register the PSM with L2CAP */
   if (transport == BT_TRANSPORT_BR_EDR) {
-    p_ccb->psm = L2CA_REGISTER(
-        psm, &conn.reg_info, AMP_AUTOSWITCH_ALLOWED | AMP_USE_AMP_IF_POSSIBLE);
+    p_ccb->psm = L2CA_REGISTER(psm, &conn.reg_info, false /* enable_snoop */);
     if (p_ccb->psm == 0) {
       LOG(ERROR) << StringPrintf("%s: Failure registering PSM 0x%04x", __func__,
                                  psm);
index ba8e6fe..33cf845 100644 (file)
@@ -124,7 +124,8 @@ void gatt_init(void) {
   L2CA_RegisterFixedChannel(L2CAP_ATT_CID, &fixed_reg);
 
   /* Now, register with L2CAP for ATT PSM over BR/EDR */
-  if (!L2CA_Register(BT_PSM_ATT, (tL2CAP_APPL_INFO*)&dyn_info)) {
+  if (!L2CA_Register(BT_PSM_ATT, (tL2CAP_APPL_INFO*)&dyn_info,
+                     false /* enable_snoop */)) {
     LOG(ERROR) << "ATT Dynamic Registration failed";
   }
 
index e4525f9..8786f90 100644 (file)
@@ -756,12 +756,14 @@ tHID_STATUS hidd_conn_reg(void) {
   hd_cb.l2cap_intr_cfg.flush_to_present = TRUE;
   hd_cb.l2cap_intr_cfg.flush_to = HID_DEV_FLUSH_TO;
 
-  if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
+  if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&dev_reg_info,
+                     false /* enable_snoop */)) {
     HIDD_TRACE_ERROR("HID Control (device) registration failed");
     return (HID_ERR_L2CAP_FAILED);
   }
 
-  if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
+  if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&dev_reg_info,
+                     false /* enable_snoop */)) {
     L2CA_Deregister(HID_PSM_CONTROL);
     HIDD_TRACE_ERROR("HID Interrupt (device) registration failed");
     return (HID_ERR_L2CAP_FAILED);
index 6b729e5..3c694f0 100644 (file)
@@ -97,11 +97,13 @@ tHID_STATUS hidh_conn_reg(void) {
   hh_cb.l2cap_cfg.flush_to = HID_HOST_FLUSH_TO;
 
   /* Now, register with L2CAP */
-  if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&hst_reg_info)) {
+  if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&hst_reg_info,
+                     false /* enable_snoop */)) {
     HIDH_TRACE_ERROR("HID-Host Control Registration failed");
     return (HID_ERR_L2CAP_FAILED);
   }
-  if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&hst_reg_info)) {
+  if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&hst_reg_info,
+                     false /* enable_snoop */)) {
     L2CA_Deregister(HID_PSM_CONTROL);
     HIDH_TRACE_ERROR("HID-Host Interrupt Registration failed");
     return (HID_ERR_L2CAP_FAILED);
index 88121af..8f364e7 100644 (file)
@@ -328,7 +328,7 @@ typedef struct {
 
 } tL2CAP_ERTM_INFO;
 
-#define L2CA_REGISTER(a, b, c) L2CA_Register(a, (tL2CAP_APPL_INFO*)(b))
+#define L2CA_REGISTER(a, b, c) L2CA_Register(a, (tL2CAP_APPL_INFO*)(b), c)
 #define L2CA_DEREGISTER(a) L2CA_Deregister(a)
 #define L2CA_CONNECT_REQ(a, b, c) L2CA_ErtmConnectReq(a, b, c)
 #define L2CA_CONNECT_RSP(a, b, c, d, e, f) L2CA_ErtmConnectRsp(a, b, c, d, e, f)
@@ -362,7 +362,8 @@ typedef struct {
  *                  BTM_SetSecurityLevel().
  *
  ******************************************************************************/
-extern uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info);
+extern uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info,
+                              bool enable_snoop);
 
 /*******************************************************************************
  *
index 6dc41de..b5a9564 100644 (file)
@@ -58,7 +58,8 @@ using base::StringPrintf;
  *                  L2CA_ErtmConnectReq() and L2CA_Deregister()
  *
  ******************************************************************************/
-uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) {
+uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info,
+                       bool enable_snoop) {
   tL2C_RCB* p_rcb;
   uint16_t vpsm = psm;
 
@@ -104,6 +105,7 @@ uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) {
     }
   }
 
+  p_rcb->log_packets = enable_snoop;
   p_rcb->api = *p_cb_info;
   p_rcb->real_psm = psm;
 
index 0b71a19..53b6f32 100644 (file)
@@ -241,6 +241,7 @@ typedef struct {
 
 typedef struct {
   bool in_use;
+  bool log_packets;
   uint16_t psm;
   uint16_t real_psm; /* This may be a dummy RCB for an o/b connection but */
                      /* this is the real PSM that we need to connect to */
index c6477ce..031423c 100644 (file)
@@ -33,6 +33,7 @@
 #include "btm_int.h"
 #include "btu.h"
 #include "device/include/controller.h"
+#include "hci/include/btsnoop.h"
 #include "hcimsgs.h"
 #include "l2c_api.h"
 #include "l2c_int.h"
@@ -396,6 +397,14 @@ static void process_l2cap_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
         p_ccb->p_rcb = p_rcb;
         p_ccb->remote_cid = rcid;
 
+        if (p_rcb->psm == BT_PSM_RFCOMM) {
+          btsnoop_get_interface()->add_rfc_l2c_channel(
+              p_lcb->handle, p_ccb->local_cid, p_ccb->remote_cid);
+        } else if (p_rcb->log_packets) {
+          btsnoop_get_interface()->whitelist_l2c_channel(
+              p_lcb->handle, p_ccb->local_cid, p_ccb->remote_cid);
+        }
+
         l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_REQ, &con_info);
         break;
       }
@@ -427,6 +436,15 @@ static void process_l2cap_cmd(tL2C_LCB* p_lcb, uint8_t* p, uint16_t pkt_len) {
         else
           l2c_csm_execute(p_ccb, L2CEVT_L2CAP_CONNECT_RSP_NEG, &con_info);
 
+        tL2C_RCB* p_rcb = p_ccb->p_rcb;
+        if (p_rcb->psm == BT_PSM_RFCOMM) {
+          btsnoop_get_interface()->add_rfc_l2c_channel(
+              p_lcb->handle, p_ccb->local_cid, p_ccb->remote_cid);
+        } else if (p_rcb->log_packets) {
+          btsnoop_get_interface()->whitelist_l2c_channel(
+              p_lcb->handle, p_ccb->local_cid, p_ccb->remote_cid);
+        }
+
         break;
       }
 
index 4f4a48e..c908b2c 100644 (file)
@@ -33,6 +33,7 @@
 #include "btm_int.h"
 #include "btu.h"
 #include "device/include/controller.h"
+#include "hci/include/btsnoop.h"
 #include "hcidefs.h"
 #include "hcimsgs.h"
 #include "l2c_int.h"
@@ -1566,6 +1567,9 @@ void l2cu_release_ccb(tL2C_CCB* p_ccb) {
   /* If already released, could be race condition */
   if (!p_ccb->in_use) return;
 
+  btsnoop_get_interface()->clear_l2cap_whitelist(
+      p_lcb->handle, p_ccb->local_cid, p_ccb->remote_cid);
+
   if (p_rcb && (p_rcb->psm != p_rcb->real_psm)) {
     btm_sec_clr_service_by_psm(p_rcb->psm);
   }
index 3275d77..3dc4ec2 100644 (file)
@@ -30,6 +30,7 @@
 #include "osi/include/osi.h"
 
 #include "bt_utils.h"
+#include "hci/include/btsnoop.h"
 #include "l2c_api.h"
 #include "l2cdefs.h"
 #include "port_api.h"
@@ -73,7 +74,7 @@ void rfcomm_l2cap_if_init(void) {
   p_l2c->pL2CA_CongestionStatus_Cb = RFCOMM_CongestionStatusInd;
   p_l2c->pL2CA_TxComplete_Cb = NULL;
 
-  L2CA_Register(BT_PSM_RFCOMM, p_l2c);
+  L2CA_Register(BT_PSM_RFCOMM, p_l2c, true /* enable_snoop */);
 }
 
 /*******************************************************************************
index f486bdd..1b82ddf 100644 (file)
 #include "rfc_int.h"
 #include "rfcdefs.h"
 
+#include <set>
+#include "hci/include/btsnoop.h"
+
+static const std::set<uint16_t> uuid_logging_whitelist = {
+    UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY,
+    UUID_SERVCLASS_AG_HANDSFREE,
+};
+
 /******************************************************************************/
 /*            L O C A L    F U N C T I O N     P R O T O T Y P E S            */
 /******************************************************************************/
@@ -206,6 +214,13 @@ void rfc_port_sm_sabme_wait_ua(tPORT* p_port, uint16_t event, void* p_data) {
     case RFC_EVENT_UA:
       rfc_port_timer_stop(p_port);
       p_port->rfc.state = RFC_STATE_OPENED;
+
+      if (uuid_logging_whitelist.find(p_port->uuid) !=
+          uuid_logging_whitelist.end()) {
+        btsnoop_get_interface()->whitelist_rfc_dlci(p_port->rfc.p_mcb->lcid,
+                                                    p_port->dlci);
+      }
+
       PORT_DlcEstablishCnf(p_port->rfc.p_mcb, p_port->dlci,
                            p_port->rfc.p_mcb->peer_l2cap_mtu, RFCOMM_SUCCESS);
       return;
@@ -317,6 +332,12 @@ void rfc_port_sm_term_wait_sec_check(tPORT* p_port, uint16_t event,
       } else {
         rfc_send_ua(p_port->rfc.p_mcb, p_port->dlci);
         p_port->rfc.state = RFC_STATE_OPENED;
+
+        if (uuid_logging_whitelist.find(p_port->uuid) !=
+            uuid_logging_whitelist.end()) {
+          btsnoop_get_interface()->whitelist_rfc_dlci(p_port->rfc.p_mcb->lcid,
+                                                      p_port->dlci);
+        }
       }
       return;
   }
index 3df37c5..2211c39 100644 (file)
@@ -121,7 +121,7 @@ void sdp_init(void) {
   sdp_cb.reg_info.pL2CA_TxComplete_Cb = NULL;
 
   /* Now, register with L2CAP */
-  if (!L2CA_Register(SDP_PSM, &sdp_cb.reg_info)) {
+  if (!L2CA_Register(SDP_PSM, &sdp_cb.reg_info, true /* enable_snoop */)) {
     SDP_TRACE_ERROR("SDP Registration failed");
   }
 }
index 3d9da3f..0d27e5d 100644 (file)
@@ -27,6 +27,7 @@
 #include "port_api.h"
 
 #include "btm_int.h"
+#include "hci/include/btsnoop.h"
 #include "rfc_int.h"
 
 #include "mock_btm_layer.h"
 #include "stack_rfcomm_test_utils.h"
 #include "stack_test_packet_utils.h"
 
+static void capture(const BT_HDR*, bool) { /* do nothing */
+}
+static void whitelist_l2c_channel(uint16_t, uint16_t,
+                                  uint16_t) { /* do nothing */
+}
+static void whitelist_rfc_dlci(uint16_t, uint8_t) { /* do nothing */
+}
+static void add_rfc_l2c_channel(uint16_t, uint16_t, uint16_t) { /* do nothing */
+}
+static void clear_l2cap_whitelist(uint16_t, uint16_t,
+                                  uint16_t) { /* do nothing */
+}
+static const btsnoop_t fake_snoop = {capture, whitelist_l2c_channel,
+                                     whitelist_rfc_dlci, add_rfc_l2c_channel,
+                                     clear_l2cap_whitelist};
+const btsnoop_t* btsnoop_get_interface() { return &fake_snoop; }
+
 std::string DumpByteBufferToString(uint8_t* p_data, size_t len) {
   std::stringstream str;
   str.setf(std::ios_base::hex, std::ios::basefield);
@@ -46,6 +64,8 @@ std::string DumpByteBufferToString(uint8_t* p_data, size_t len) {
   return str.str();
 }
 
+uint16_t L2CA_Register(unsigned short, tL2CAP_APPL_INFO*, bool) { return 0; }
+
 std::string DumpBtHdrToString(BT_HDR* p_hdr) {
   uint8_t* p_hdr_data = p_hdr->data + p_hdr->offset;
   return DumpByteBufferToString(p_hdr_data, p_hdr->len);