diff options
author | Mallikarjuna GB <gbmalli@codeaurora.org> | 2014-11-14 19:46:19 +0530 |
---|---|---|
committer | Linux Build Service Account <lnxbuild@localhost> | 2015-10-06 03:22:06 -0600 |
commit | 57989bb15937beff071393f83f418c57b443dbe5 (patch) | |
tree | aff7a19cee45d1c52bf3b97c2da058e0aca380cf | |
parent | a4afb57a9bf3694155dc6daff754525b0a72deae (diff) | |
download | android_system_bt-57989bb15937beff071393f83f418c57b443dbe5.tar.gz android_system_bt-57989bb15937beff071393f83f418c57b443dbe5.tar.bz2 android_system_bt-57989bb15937beff071393f83f418c57b443dbe5.zip |
btsnoop: btsnoop write from external process
- write btsnoop from external process
- adjust the gmt offset to match with logcat logs
- avoid btsnoop file write if btsnoop client is connected
- limit the block of snoop write to 10 ms and drop the packet
- memcpy and issue single write to eliminate multiple I/O
- enable snoop by default on userdebug build
- option to override snoop config for userdebug build
Change-Id: I13749dc348baf88af57e3ebec1ec7acd5e999c04
-rw-r--r-- | conf/bt_stack.conf | 6 | ||||
-rw-r--r-- | hci/Android.mk | 4 | ||||
-rw-r--r-- | hci/src/btsnoop.c | 127 | ||||
-rw-r--r-- | hci/src/btsnoop_net.c | 122 | ||||
-rw-r--r-- | include/stack_config.h | 1 | ||||
-rw-r--r-- | main/stack_config.c | 8 | ||||
-rw-r--r-- | tools/btsnoop_dump/Android.mk | 16 | ||||
-rw-r--r-- | tools/btsnoop_dump/btsnoop_dump.c | 363 |
8 files changed, 622 insertions, 25 deletions
diff --git a/conf/bt_stack.conf b/conf/bt_stack.conf index 575e02bbb..1b84cb2a2 100644 --- a/conf/bt_stack.conf +++ b/conf/bt_stack.conf @@ -1,6 +1,12 @@ +# 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 diff --git a/hci/Android.mk b/hci/Android.mk index af87285d1..bbaf11781 100644 --- a/hci/Android.mk +++ b/hci/Android.mk @@ -23,6 +23,10 @@ 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 += -std=c99 $(bdroid_CFLAGS) LOCAL_C_INCLUDES += \ diff --git a/hci/src/btsnoop.c b/hci/src/btsnoop.c index d859e6842..089cc5104 100644 --- a/hci/src/btsnoop.c +++ b/hci/src/btsnoop.c @@ -20,6 +20,7 @@ #include <arpa/inet.h> #include <assert.h> +#include <cutils/properties.h> #include <errno.h> #include <fcntl.h> #include <limits.h> @@ -28,8 +29,10 @@ #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 "hci/include/btsnoop.h" @@ -50,6 +53,15 @@ typedef enum { 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 +bool hci_ext_dump_enabled = false; /* External BT snoop */ +/* 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; @@ -67,7 +79,20 @@ static void update_logging(); // Module lifecycle functions static future_t *start_up(void) { + time_t t = time(NULL); + struct tm tm_cur = {0}; + + localtime_r (&t, &tm_cur); + LOG_INFO("Time GMT offset %ld\n", 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; @@ -75,6 +100,9 @@ static future_t *start_up(void) { static future_t *shut_down(void) { module_started = false; + if (hci_ext_dump_enabled == true) { + property_set("bluetooth.startbtsnoop", "false"); + } update_logging(); return NULL; @@ -140,6 +168,7 @@ const btsnoop_t *btsnoop_get_interface() { 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; @@ -150,7 +179,7 @@ static uint64_t btsnoop_timestamp(void) { 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; @@ -158,7 +187,9 @@ static void update_logging() { is_logging = should_log; 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 @@ -187,10 +218,20 @@ static void update_logging() { } 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); +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); } static void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool is_received) { @@ -198,6 +239,14 @@ static void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool 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[1200] = {0}; + uint32_t offset = 0; + switch (type) { case kCommandPacket: length_he = packet[2] + 4; @@ -227,12 +276,68 @@ static void btsnoop_write_packet(packet_type_t type, const uint8_t *packet, bool 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; + 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("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("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("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("btsnoop write : Write took more time %08lld us", ts_diff); + } +#endif } diff --git a/hci/src/btsnoop_net.c b/hci/src/btsnoop_net.c index c601da811..8c69b6732 100644 --- a/hci/src/btsnoop_net.c +++ b/hci/src/btsnoop_net.c @@ -19,6 +19,9 @@ #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> @@ -42,7 +45,36 @@ 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) { + int conn_sk, length; + + 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("Failed to create Local Socket (%s)", strerror(errno)); + return -1; + } + + if (listen(listen_socket_local_, 1) < 0) { + LOG_ERROR("Local socket listen failed (%s)", strerror(errno)); + close(listen_socket_local_); + return -1; + } + return listen_socket_local_; +} void btsnoop_net_open() { listen_thread_valid_ = (pthread_create(&listen_thread_, NULL, listen_fn_, NULL) == 0); @@ -56,31 +88,49 @@ void btsnoop_net_open() { void btsnoop_net_close() { if (listen_thread_valid_) { shutdown(listen_socket_, SHUT_RDWR); + 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) { + ssize_t ret; + pthread_mutex_lock(&client_socket_lock_); - if (client_socket_ != -1) { - if (send(client_socket_, data, length, 0) == -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("%s conn closed", __func__); + } + if (ret < length) { + LOG_ERROR("%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) { + ssize_t ret; + fd_set sock_fds; + int fd_max, retval; prctl(PR_SET_NAME, (unsigned long)LISTEN_THREAD_NAME_, 0, 0, 0); + FD_ZERO(&sock_fds); + listen_socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listen_socket_ == -1) { LOG_ERROR("%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) { @@ -102,27 +152,71 @@ static void *listen_fn_(UNUSED_ATTR void *context) { goto cleanup; } + if (local_socket_create() != -1) { + if (listen_socket_local_ > fd_max) { + fd_max = listen_socket_local_; + } + FD_SET(listen_socket_local_, &sock_fds); + } + for (;;) { - int client_socket = accept(listen_socket_, NULL, NULL); - if (client_socket == -1) { - if (errno == EINVAL || errno == EBADF) { + int client_socket = -1; + + LOG_DEBUG("waiting for client connection"); + + if ((retval = select(fd_max + 1, &sock_fds, NULL, NULL, NULL)) == -1) { + LOG_ERROR("%s select failed %s", __func__, strerror(errno)); + goto cleanup; + } + + if(retval == 2) { + LOG_INFO("%s sockets shutdown :", __func__); break; + } + + if (FD_ISSET(listen_socket_, &sock_fds)) { + client_socket = accept(listen_socket_, NULL, NULL); + if (client_socket == -1) { + if (errno == EINVAL || errno == EBADF) { + LOG_WARN("%s error accepting TCP socket: %s", __func__, strerror(errno)); + break; + } + LOG_WARN("%s error accepting TCP socket: %s", __func__, strerror(errno)); + continue; + } + } else if (FD_ISSET(listen_socket_local_, &sock_fds)){ + struct sockaddr_un cliaddr; + int length; + + client_socket = accept(listen_socket_local_, (struct sockaddr *)&cliaddr, &length); + if (client_socket == -1) { + if (errno == EINVAL || errno == EBADF) { + LOG_WARN("%s error accepting LOCAL socket: %s", __func__, strerror(errno)); + break; + } + LOG_WARN("%s error accepting LOCAL socket: %s", __func__, strerror(errno)); + continue; } - LOG_WARN("%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; - 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; + ret = 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); + 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; } diff --git a/include/stack_config.h b/include/stack_config.h index a4262c5f5..28cb57837 100644 --- a/include/stack_config.h +++ b/include/stack_config.h @@ -28,6 +28,7 @@ static const char STACK_CONFIG_MODULE[] = "stack_config_module"; 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); config_t *(*get_all)(void); diff --git a/main/stack_config.c b/main/stack_config.c index 6e1431ee4..0618fb107 100644 --- a/main/stack_config.c +++ b/main/stack_config.c @@ -26,6 +26,8 @@ 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"; @@ -82,6 +84,11 @@ static bool get_trace_config_enabled(void) { return config_get_bool(config, CONFIG_DEFAULT_SECTION, TRACE_CONFIG_ENABLED_KEY, false); } +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; } @@ -89,6 +96,7 @@ static config_t *get_all(void) { 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_all diff --git a/tools/btsnoop_dump/Android.mk b/tools/btsnoop_dump/Android.mk new file mode 100644 index 000000000..f114c3ffc --- /dev/null +++ b/tools/btsnoop_dump/Android.mk @@ -0,0 +1,16 @@ +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) diff --git a/tools/btsnoop_dump/btsnoop_dump.c b/tools/btsnoop_dump/btsnoop_dump.c new file mode 100644 index 000000000..073946207 --- /dev/null +++ b/tools/btsnoop_dump/btsnoop_dump.c @@ -0,0 +1,363 @@ +/****************************************************************************** +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; +} + |