+# Enable BtSnoop configuration from this config file
+# Snoop is enabled by default on userdebug builds, below configuration
+# enables to override it and take effect from the configurations here.
+BtSnoopConfigFromFile=false
+
# Enable BtSnoop logging function
# valid value : true, false
BtSnoopLogOutput=false
+BtSnoopExtDump=false
# BtSnoop log output file
BtSnoopFileName=/sdcard/btsnoop_hci.log
ifeq ($(BLUETOOTH_HCI_USE_MCT),true)
LOCAL_CFLAGS += -DHCI_USE_MCT
endif
+
+ifeq ($(TARGET_BUILD_VARIANT),userdebug)
+ LOCAL_CFLAGS += -DBTSNOOP_DEFAULT=TRUE
+endif
+
LOCAL_CFLAGS += $(bluetooth_CFLAGS)
LOCAL_CONLYFLAGS += $(bluetooth_CONLYFLAGS)
LOCAL_CPPFLAGS += $(bluetooth_CPPFLAGS)
#include <arpa/inet.h>
#include <assert.h>
+#include <cutils/properties.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <sys/stat.h>
#include <sys/time.h>
+#include <sys/poll.h>
#include <unistd.h>
#include "bt_types.h"
static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
static const stack_config_t *stack_config;
+extern int client_socket_btsnoop;
+static long int gmt_offset;
+#define USEC_PER_SEC 1000000L
+#define MAX_SNOOP_BUF_SIZE 1200
+
+// External BT snoop
+bool hci_ext_dump_enabled = false;
+
+/* snoop config from the config file, required for userdebug
+ build where snoop is enabled by default.
+ power/perf measurements need the snoop to be disabled.
+*/
+bool btsnoop_conf_from_file = false;
static int logfile_fd = INVALID_FD;
static bool module_started;
// Module lifecycle functions
static future_t *start_up(void) {
+ time_t t = time(NULL);
+ struct tm tm_cur;
+
+ localtime_r (&t, &tm_cur);
+ LOG_INFO(LOG_TAG, "%s Time GMT offset %ld\n", __func__, tm_cur.tm_gmtoff);
+ gmt_offset = tm_cur.tm_gmtoff;
+
module_started = true;
+ stack_config->get_btsnoop_ext_options(&hci_ext_dump_enabled, &btsnoop_conf_from_file);
+#if (BTSNOOP_DEFAULT == TRUE)
+ if (btsnoop_conf_from_file == false) {
+ hci_ext_dump_enabled = true;
+ }
+#endif
update_logging();
return NULL;
static future_t *shut_down(void) {
module_started = false;
+ if (hci_ext_dump_enabled == true) {
+ property_set("bluetooth.startbtsnoop", "false");
+ }
update_logging();
return NULL;
static uint64_t btsnoop_timestamp(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
+ tv.tv_sec += gmt_offset;
// Timestamp is in microseconds.
uint64_t timestamp = tv.tv_sec * 1000 * 1000LL;
static void update_logging() {
bool should_log = module_started &&
- (logging_enabled_via_api || stack_config->get_btsnoop_turned_on());
+ (logging_enabled_via_api || stack_config->get_btsnoop_turned_on() || hci_ext_dump_enabled);
if (should_log == is_logging)
return;
if (should_log) {
btsnoop_net_open();
+ if (hci_ext_dump_enabled == true) {
+ property_set("bluetooth.startbtsnoop", "true");
+ }
const char *log_path = stack_config->get_btsnoop_log_path();
// Save the old log if configured to do so
}
static void btsnoop_write(const void *data, size_t length) {
+ if (client_socket_btsnoop != -1) {
+ btsnoop_net_write(data, length);
+ /* skip writing to file if external client is connected*/
+ return;
+ }
+
if (logfile_fd != INVALID_FD)
write(logfile_fd, data, length);
+}
- btsnoop_net_write(data, length);
+#ifdef DEBUG_SNOOP
+static uint64_t time_now_us() {
+ struct timespec ts_now;
+ clock_gettime(CLOCK_BOOTTIME, &ts_now);
+ return ((uint64_t)ts_now.tv_sec * USEC_PER_SEC) + ((uint64_t)ts_now.tv_nsec / 1000);
}
+#endif
static void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool is_received) {
int length_he = 0;
int length;
int flags;
int drops = 0;
+ struct pollfd pfd;
+#ifdef DEBUG_SNOOP
+ uint64_t ts_begin;
+ uint64_t ts_end, ts_diff;
+#endif
+ uint8_t snoop_buf[MAX_SNOOP_BUF_SIZE] = {0};
+ uint32_t offset = 0;
+
switch (type) {
case kCommandPacket:
length_he = packet[2] + 4;
time_hi = htonl(time_hi);
time_lo = htonl(time_lo);
- btsnoop_write(&length, 4);
- btsnoop_write(&length, 4);
- btsnoop_write(&flags, 4);
- btsnoop_write(&drops, 4);
- btsnoop_write(&time_hi, 4);
- btsnoop_write(&time_lo, 4);
- btsnoop_write(&type, 1);
- btsnoop_write(packet, length_he - 1);
+ /* store the length in both original and included fields */
+ memcpy(snoop_buf + offset, &length, 4);
+ offset += 4;
+ memcpy(snoop_buf + offset, &length, 4);
+ offset += 4;
+
+ /* flags: */
+ memcpy(snoop_buf + offset, &flags, 4);
+ offset += 4;
+
+ /* drops: none */
+ memcpy(snoop_buf + offset, &drops, 4);
+ offset += 4;
+
+ /* time */
+ memcpy(snoop_buf + offset, &time_hi, 4);
+ offset += 4;
+ memcpy(snoop_buf + offset, &time_lo, 4);
+ offset = offset + 4;
+
+ snoop_buf[offset] = type;
+ offset += 1;
+ if (offset + length_he + 1 > MAX_SNOOP_BUF_SIZE) {
+ LOG_ERROR(LOG_TAG, "Bad packet length, downgrading the length to %d from %d",
+ MAX_SNOOP_BUF_SIZE - offset - 1, length_he);
+ length_he = MAX_SNOOP_BUF_SIZE - offset - 1;
+ }
+ memcpy(snoop_buf + offset, packet, length_he - 1);
+
+ if (client_socket_btsnoop != -1) {
+ pfd.fd = client_socket_btsnoop;
+ pfd.events = POLLOUT;
+#ifdef DEBUG_SNOOP
+ ts_begin = time_now_us();
+#endif
+
+ if (poll(&pfd, 1, 10) == 0) {
+ LOG_ERROR(LOG_TAG, "btsnoop poll : Taking more than 10 ms : skip dump");
+#ifdef DEBUG_SNOOP
+ ts_end = time_now_us();
+ ts_diff = ts_end - ts_begin;
+ if (ts_diff > 10000) {
+ LOG_ERROR(LOG_TAG, "btsnoop poll T/O : took more time %08lld us", ts_diff);
+ }
+#endif
+ return;
+ }
+
+#ifdef DEBUG_SNOOP
+ ts_end = time_now_us();
+ ts_diff = ts_end - ts_begin;
+ if (ts_diff > 10000) {
+ LOG_ERROR(LOG_TAG, "btsnoop poll : took more time %08lld us", ts_diff);
+ }
+#endif
+ }
+#ifdef DEBUG_SNOOP
+ ts_begin = time_now_us();
+#endif
+
+ btsnoop_write(snoop_buf, offset + length_he - 1);
+
+#ifdef DEBUG_SNOOP
+ ts_end = time_now_us();
+ ts_diff = ts_end - ts_begin;
+ if (ts_diff > 10000) {
+ LOG_ERROR(LOG_TAG, "btsnoop write : Write took more time %08lld us", ts_diff);
+ }
+#endif
}
#define LOG_TAG "bt_snoop_net"
#include <assert.h>
+#include <cutils/sockets.h>
+#include <sys/un.h>
+#include <sys/poll.h>
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
static void *listen_fn_(void *context);
static const char *LISTEN_THREAD_NAME_ = "btsnoop_net_listen";
+#if (defined(BT_NET_DEBUG) && (NET_DEBUG == TRUE))
static const int LOCALHOST_ = 0x7F000001;
static const int LISTEN_PORT_ = 8872;
+#endif
static pthread_t listen_thread_;
static bool listen_thread_valid_ = false;
static pthread_mutex_t client_socket_lock_ = PTHREAD_MUTEX_INITIALIZER;
static int listen_socket_ = -1;
-static int client_socket_ = -1;
+int client_socket_btsnoop = -1;
+
+/*
+ local socket for writing from different process
+ to limit blocking of HCI threads.
+*/
+#define LOCAL_SOCKET_NAME "bthcitraffic"
+static int listen_socket_local_ = -1;
+
+static int local_socket_create(void) {
+
+ listen_socket_local_ = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if(listen_socket_local_ < 0) {
+ return -1;
+ }
+
+ if(socket_local_server_bind(listen_socket_local_, LOCAL_SOCKET_NAME,
+ ANDROID_SOCKET_NAMESPACE_ABSTRACT) < 0) {
+ LOG_ERROR(LOG_TAG, "Failed to create Local Socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ if (listen(listen_socket_local_, 1) < 0) {
+ LOG_ERROR(LOG_TAG, "Local socket listen failed (%s)", strerror(errno));
+ close(listen_socket_local_);
+ return -1;
+ }
+ return listen_socket_local_;
+}
void btsnoop_net_open() {
-#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
- return; // Disable using network sockets for security reasons
-#endif
listen_thread_valid_ = (pthread_create(&listen_thread_, NULL, listen_fn_, NULL) == 0);
if (!listen_thread_valid_) {
}
void btsnoop_net_close() {
-#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
- return; // Disable using network sockets for security reasons
-#endif
if (listen_thread_valid_) {
+#if (defined(BT_NET_DEBUG) && (NET_DEBUG == TRUE))
+ // Disable using network sockets for security reasons
shutdown(listen_socket_, SHUT_RDWR);
+#endif
+ shutdown(listen_socket_local_, SHUT_RDWR);
pthread_join(listen_thread_, NULL);
- safe_close_(&client_socket_);
+ safe_close_(&client_socket_btsnoop);
listen_thread_valid_ = false;
}
}
void btsnoop_net_write(const void *data, size_t length) {
-#if (!defined(BT_NET_DEBUG) || (BT_NET_DEBUG != TRUE))
- return; // Disable using network sockets for security reasons
-#endif
+ ssize_t ret;
pthread_mutex_lock(&client_socket_lock_);
- if (client_socket_ != -1) {
- ssize_t ret;
- OSI_NO_INTR(ret = send(client_socket_, data, length, 0));
-
- if (ret == -1 && errno == ECONNRESET) {
- safe_close_(&client_socket_);
- }
+ if (client_socket_btsnoop != -1) {
+ do {
+ if ((ret = send(client_socket_btsnoop, data, length, 0)) == -1 && errno == ECONNRESET) {
+ safe_close_(&client_socket_btsnoop);
+ LOG_INFO(LOG_TAG, "%s conn closed", __func__);
+ }
+ if ((size_t) ret < length) {
+ LOG_ERROR(LOG_TAG, "%s: send : not able to write complete packet", __func__);
+ }
+ length -= ret;
+ } while ((length > 0) && (ret != -1));
}
+
pthread_mutex_unlock(&client_socket_lock_);
}
static void *listen_fn_(UNUSED_ATTR void *context) {
+ fd_set sock_fds;
+ int fd_max = -1, retval;
prctl(PR_SET_NAME, (unsigned long)LISTEN_THREAD_NAME_, 0, 0, 0);
+ FD_ZERO(&sock_fds);
+
+#if (defined(BT_NET_DEBUG) && (NET_DEBUG == TRUE))
+ // Disable using network sockets for security reasons
listen_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_socket_ == -1) {
LOG_ERROR(LOG_TAG, "%s socket creation failed: %s", __func__, strerror(errno));
goto cleanup;
}
+ FD_SET(listen_socket_, &sock_fds);
+ fd_max = listen_socket_;
int enable = 1;
if (setsockopt(listen_socket_, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) == -1) {
LOG_ERROR(LOG_TAG, "%s unable to listen: %s", __func__, strerror(errno));
goto cleanup;
}
+#endif
+
+ if (local_socket_create() != -1) {
+ if (listen_socket_local_ > fd_max) {
+ fd_max = listen_socket_local_;
+ }
+ FD_SET(listen_socket_local_, &sock_fds);
+ }
+
+ if (fd_max == -1) {
+ LOG_ERROR(LOG_TAG, "%s No sockets to wait for conn..", __func__);
+ return NULL;
+ }
for (;;) {
- int client_socket;
- OSI_NO_INTR(client_socket = accept(listen_socket_, NULL, NULL));
- if (client_socket == -1) {
- if (errno == EINVAL || errno == EBADF) {
- break;
+ int client_socket = -1;
+
+ LOG_DEBUG(LOG_TAG, "waiting for client connection");
+
+ if ((retval = select(fd_max + 1, &sock_fds, NULL, NULL, NULL)) == -1) {
+ LOG_ERROR(LOG_TAG, "%s select failed %s", __func__, strerror(errno));
+ goto cleanup;
+ }
+
+ if ((listen_socket_ != -1) && FD_ISSET(listen_socket_, &sock_fds)) {
+ client_socket = accept(listen_socket_, NULL, NULL);
+ if (client_socket == -1) {
+ if (errno == EINVAL || errno == EBADF) {
+ LOG_WARN(LOG_TAG, "%s error accepting TCP socket: %s", __func__, strerror(errno));
+ break;
+ }
+ LOG_WARN(LOG_TAG, "%s error accepting TCP socket: %s", __func__, strerror(errno));
+ continue;
+ }
+ } else if ((listen_socket_local_ != -1) && FD_ISSET(listen_socket_local_, &sock_fds)){
+ struct sockaddr_un cliaddr;
+ int length;
+
+ client_socket = accept(listen_socket_local_, (struct sockaddr *)&cliaddr, (socklen_t *)&length);
+ if (client_socket == -1) {
+ if (errno == EINVAL || errno == EBADF) {
+ LOG_WARN(LOG_TAG, "%s error accepting LOCAL socket: %s", __func__, strerror(errno));
+ break;
+ }
+ LOG_WARN(LOG_TAG, "%s error accepting LOCAL socket: %s", __func__, strerror(errno));
+ continue;
}
- LOG_WARN(LOG_TAG, "%s error accepting socket: %s", __func__, strerror(errno));
- continue;
}
/* When a new client connects, we have to send the btsnoop file header. This allows
a decoder to treat the session as a new, valid btsnoop file. */
pthread_mutex_lock(&client_socket_lock_);
- safe_close_(&client_socket_);
- client_socket_ = client_socket;
-
- OSI_NO_INTR(send(client_socket_, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16, 0));
+ safe_close_(&client_socket_btsnoop);
+ client_socket_btsnoop = client_socket;
+ send(client_socket_btsnoop, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16, 0);
pthread_mutex_unlock(&client_socket_lock_);
+
+ FD_ZERO(&sock_fds);
+ if(listen_socket_ != -1) {
+ FD_SET(listen_socket_, &sock_fds);
+ }
+ if(listen_socket_local_ != -1) {
+ FD_SET(listen_socket_local_, &sock_fds);
+ }
}
cleanup:
safe_close_(&listen_socket_);
+ safe_close_(&listen_socket_local_);
return NULL;
}
typedef struct {
const char *(*get_btsnoop_log_path)(void);
bool (*get_btsnoop_turned_on)(void);
+ void (*get_btsnoop_ext_options)(bool *hci_ext_dump_enabled, bool *btsnoop_conf_from_file);
bool (*get_btsnoop_should_save_last)(void);
bool (*get_trace_config_enabled)(void);
bool (*get_pts_secure_only_mode)(void);
const char *BTSNOOP_LOG_PATH_KEY = "BtSnoopFileName";
const char *BTSNOOP_TURNED_ON_KEY = "BtSnoopLogOutput";
+const char *BTSNOOP_EXT_DUMP_KEY = "BtSnoopExtDump";
+const char *BTSNOOP_CONFIG_FROM_FILE_KEY = "BtSnoopConfigFromFile";
const char *BTSNOOP_SHOULD_SAVE_LAST_KEY = "BtSnoopSaveLog";
const char *TRACE_CONFIG_ENABLED_KEY = "TraceConf";
const char *PTS_SECURE_ONLY_MODE = "PTS_SecurePairOnly";
return config_get_int(config, CONFIG_DEFAULT_SECTION, PTS_SMP_FAILURE_CASE_KEY, 0);
}
+static void get_btsnoop_ext_options(bool *hci_ext_dump_enabled, bool *btsnoop_conf_from_file) {
+ *hci_ext_dump_enabled = config_get_bool(config, CONFIG_DEFAULT_SECTION, BTSNOOP_EXT_DUMP_KEY, false);
+ *btsnoop_conf_from_file = config_get_bool(config, CONFIG_DEFAULT_SECTION, BTSNOOP_CONFIG_FROM_FILE_KEY, false);
+}
+
static config_t *get_all(void) {
return config;
}
const stack_config_t interface = {
get_btsnoop_log_path,
get_btsnoop_turned_on,
+ get_btsnoop_ext_options,
get_btsnoop_should_save_last,
get_trace_config_enabled,
get_pts_secure_only_mode,
--- /dev/null
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ btsnoop_dump.c
+
+LOCAL_C_INCLUDES :=
+
+LOCAL_MODULE_TAGS := debug optional
+
+LOCAL_MODULE:= btsnoop
+
+LOCAL_SHARED_LIBRARIES += libcutils
+
+include $(BUILD_EXECUTABLE)
--- /dev/null
+/******************************************************************************
+Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <private/android_filesystem_config.h>
+#include <android/log.h>
+
+#include <cutils/log.h>
+
+#define MAX_FILE_SIZE 1024*1024*20
+
+#define LOGD0(t,s) __android_log_write(ANDROID_LOG_DEBUG, t, s)
+
+static int file_descriptor = -1;
+uint32_t file_size = 0;
+
+#define LOCAL_SOCKET_NAME "bthcitraffic"
+#define BTSNOOP_PATH "/data/media/0"
+#define BTSOOP_PORT 8872
+
+//#define __SNOOP_DUMP_DBG__
+
+static void snoop_log(const char *fmt_str, ...)
+{
+ static char buffer[1024];
+ va_list ap;
+
+ va_start(ap, fmt_str);
+ vsnprintf(buffer, 1024, fmt_str, ap);
+ va_end(ap);
+
+ LOGD0("btsnoop_dump: ", buffer);
+}
+
+int btsnoop_file_name (char file_name[256])
+{
+ struct tm *tmp;
+ time_t t;
+ char time_string[64];
+
+ t = time(NULL);
+ tmp = localtime(&t);
+ if (tmp == NULL)
+ {
+ snoop_log("Error : get localtime");
+ return -1;
+ }
+
+ if (strftime(time_string, 64, "%Y%m%d%H%M%S", tmp) == 0)
+ {
+ snoop_log("Error : strftime :");
+ return -1;
+ }
+ snprintf(file_name, 256, BTSNOOP_PATH"/hci_snoop%s.cfa", time_string);
+ return 0;
+}
+
+int snoop_open_file (void)
+{
+ char file_name[2][256];
+ int snoop_files_found = 0;
+ struct DIR* p_dir;
+ struct dirent* p_dirent;
+
+ p_dir = opendir(BTSNOOP_PATH);
+ if(p_dir == NULL)
+ {
+ snoop_log("snoop_log_open: Unable to open the Dir entry\n");
+ file_descriptor = -1;
+ return -1;
+ }
+ while ((p_dirent = readdir(p_dir)) != NULL)
+ {
+ int ret;
+
+ if ((ret = strncmp(p_dirent->d_name, "hci_snoop", strlen("hci_snoop"))) == 0)
+ {
+ snoop_files_found++;
+ }
+ if (snoop_files_found > 2)
+ {
+ snoop_log("snoop_log_open: Error : More than two snoop files : Abort");
+ file_descriptor = -1;
+ return -1;
+ }
+ else if (ret == 0)
+ {
+ strlcpy(file_name[snoop_files_found - 1], p_dirent->d_name, 256);
+#ifdef __SNOOP_DUMP_DBG__
+ snoop_log("snoop_log_open: snoop file found : %s", file_name[snoop_files_found - 1]);
+#endif //__SNOOP_DUMP_DBG__
+ }
+ }
+ closedir(p_dir);
+ if (snoop_files_found == 2)
+ {
+ char del_file[256];
+
+ /* Delete the oldest File */
+ if (strncmp(file_name[0], file_name[1], 256) < 0)
+ {
+ snprintf(del_file, 256, BTSNOOP_PATH"/%s", file_name[0]);
+#ifdef __SNOOP_DUMP_DBG__
+ snoop_log("snoop_log_open: old file to delete : %s", del_file);
+#endif //__SNOOP_DUMP_DBG__
+ unlink(del_file);
+ }
+ else
+ {
+ snprintf(del_file, 256, BTSNOOP_PATH"/%s", file_name[1]);
+#ifdef __SNOOP_DUMP_DBG__
+ snoop_log("snoop_log_open: old file to delete : %s", del_file);
+#endif //__SNOOP_DUMP_DBG__
+ unlink(del_file);
+ }
+ }
+
+ if (btsnoop_file_name(file_name[0]) != 0)
+ {
+ snoop_log("snoop_log_open: error : could not get snoop file name !!");
+ return -1;
+ }
+
+ snoop_log("snoop_log_open: new file : %s", file_name[0]);
+ file_descriptor = open(file_name[0], \
+ O_WRONLY|O_CREAT|O_TRUNC, \
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
+ if (file_descriptor == -1)
+ {
+ snoop_log("snoop_log_open: Unable to open snoop log file\n");
+ file_descriptor = -1;
+ return -1;
+ }
+
+ file_size = 0;
+ write(file_descriptor, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16);
+ return 0;
+}
+
+int snoop_connect_to_source (void)
+{
+ struct sockaddr_un serv_addr;
+
+ int sk, ret, retry_count = 0, addr_len;
+
+ snoop_log("snoop_connect_to_source :");
+ /* Create Socket to connect to BT Traffic source*/
+ sk = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if (sk < 0)
+ {
+ snoop_log("Can't create client socket : %s\n", strerror(errno));
+ return -1;
+ }
+ else
+ {
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sun_family = AF_LOCAL;
+ memcpy(&serv_addr.sun_path[1], LOCAL_SOCKET_NAME, strlen(LOCAL_SOCKET_NAME));
+ addr_len = strlen(LOCAL_SOCKET_NAME) + 1;
+ addr_len += sizeof(serv_addr.sun_family);
+ do
+ {
+ ret = connect(sk, &serv_addr, addr_len);
+ if (ret < 0)
+ {
+ snoop_log("Can't connect to BT traffic source : %s\n",strerror(errno));
+ retry_count++;
+ sleep (1);
+ }
+ } while((ret < 0) && (retry_count < 10));
+
+ if (ret < 0)
+ {
+ close(sk);
+ return -1;
+ }
+
+ snoop_log("Connected to bthcitraffic : sock fd : %d", sk);
+ return sk;
+ }
+}
+
+int read_block (int sock, unsigned char *pBuf, int len)
+{
+ int bytes_recv = 0, ret;
+ do
+ {
+#ifdef __SNOOP_DUMP_DBG__
+ snoop_log("read_block : waiting to read");
+#endif //__SNOOP_DUMP_DBG__
+
+ ret = recv(sock, &pBuf[bytes_recv], len - bytes_recv, 0);
+#ifdef __SNOOP_DUMP_DBG__
+ snoop_log("read_block : read returned %d", ret);
+#endif //__SNOOP_DUMP_DBG__
+ if ( (ret == -1) && (errno != EAGAIN) )
+ {
+ bytes_recv = ret;
+ snoop_log("Error Packet header : Connection Closed : %s\n", strerror(errno));
+ break;
+ }
+ else if (ret == 0)
+ {
+ snoop_log("Disconnected from bthcitraffic : Exiting...");
+ close (sock);
+ break;
+ }
+ bytes_recv += ret;
+ } while(bytes_recv < len);
+
+#ifdef __SNOOP_DUMP_DBG__
+ snoop_log("bytes read = %d", bytes_recv);
+#endif //__SNOOP_DUMP_DBG__
+ return bytes_recv;
+}
+
+static unsigned char read_buf[1200];
+
+int snoop_process (int sk)
+{
+ int bytes_recv = 0;
+ struct stat st;
+ uint32_t sizeoffile = 0, length;
+
+ if (file_descriptor == -1)
+ {
+ if (snoop_open_file() != 0)
+ {
+ return -1;
+ }
+ }
+
+/*
+ 24 Bytes snoop Header
+ Initial 4 bytes have the length of the HCI packet
+ Read 8 bytes which have orignal length and included length
+*/
+ bytes_recv = read_block (sk, &read_buf[0], 8);
+ if ((bytes_recv == 0) || (bytes_recv == -1))
+ {
+ snoop_log("Error in reading the Header : ");
+ return -1;
+ }
+
+ length = read_buf[0] << 24 | read_buf[1] << 16 | read_buf[2] << 8 | read_buf[3];
+
+#if 1
+#ifdef __SNOOP_DUMP_DBG__
+ snoop_log("Length of Frame %ld : byte %0x %0x %0x %0x", length,
+ read_buf[0], read_buf[1], read_buf[2], read_buf[3]);
+
+ snoop_log("File Size = %d", file_size);
+#endif //__SNOOP_DUMP_DBG__
+
+ if (file_size > MAX_FILE_SIZE)
+ {
+ if (file_descriptor != -1)
+ {
+ close(file_descriptor);
+ file_descriptor = -1;
+ if (snoop_open_file() != 0)
+ {
+ return -1;
+ }
+ }
+ }
+#endif
+
+/*
+ Read rest of snoop header(16 Bytes) and HCI Packet
+*/
+ bytes_recv = read_block (sk, &read_buf[8], length + 16);
+ if ((bytes_recv == 0) || (bytes_recv == -1))
+ {
+ snoop_log("Error reading snoop packet : ");
+ return -1;
+ }
+
+ file_size += (bytes_recv + 8);
+
+ write(file_descriptor, read_buf, bytes_recv + 8);
+
+ return 0;
+}
+
+int main (int argc, char * argv[])
+{
+ int sk, ret, bytes_recv;
+
+ snoop_log ("btsnoop dump starting");
+
+ /* set the file creation mask to allow read/write */
+ umask(0111);
+
+ sk = snoop_connect_to_source();
+
+/*
+ 16 Bytes : Read and discard snoop file header
+*/
+ bytes_recv = read_block (sk, &read_buf[0], 16);
+ if ((bytes_recv == 0) || (bytes_recv == -1))
+ {
+ snoop_log("Error in reading the snoop file Header : ");
+ return -1;
+ }
+
+ if (snoop_open_file() != 0)
+ {
+ return -1;
+ }
+
+ if (sk != -1)
+ {
+ do
+ {
+ ret = snoop_process(sk);
+ } while(ret != -1);
+ }
+
+ snoop_log("btsnoop dump terminated");
+ return 0;
+}
+