/****************************************************************************** * * Copyright (C) 2020-2021 SeekWave Technology * * Licensed under the Apache License, Version 2.0 (the "License"); * ******************************************************************************/ #define LOG_TAG "skw_btsnoop" #include "skw_btsnoop.h" #include #include #include "skw_log.h" #include "skw_common.h" char skw_btsnoop_path[1024] = {'\0'}; static pthread_mutex_t btsnoop_log_lock; char btsnoop_save_log = FALSE; static int hci_btsnoop_fd = -1; static const uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL; unsigned int btsnoop_cnts = 0; unsigned int btsnoop_rev_length = 0; extern char skwlog_slice; extern char btsnoop_log_en; static uint64_t skw_btsnoop_timestamp(void) { struct timeval tv; gettimeofday(&tv, NULL); uint64_t timestamp = (tv.tv_sec * 1000LL * 1000LL) + tv.tv_usec + BTSNOOP_EPOCH_DELTA; return timestamp; } void skw_btsnoop_open() { char last_log_path[PATH_MAX]; uint64_t timestamp; uint32_t usec; char new_file = TRUE; btsnoop_rev_length = 0; if((hci_btsnoop_fd != -1) || (!btsnoop_log_en) || (strlen(skw_btsnoop_path) <= 0)) { ALOGE("%s btsnoop log file is already open. log_en:%d", __func__, btsnoop_log_en); return; } if(btsnoop_save_log) { struct stat buf; int fd = -1; if(stat(skw_btsnoop_path, &buf) == 0) { fd = open(skw_btsnoop_path, O_RDONLY); } if(fd >= 0) { fstat(fd, &buf); int file_zie = (int)buf.st_size; close(fd); ALOGD("%s btsnoop log file size:%d", __func__, file_zie); if(skwlog_slice) { if(file_zie > SKW_LOG_DEFAULT_SIZE) { snprintf(last_log_path, PATH_MAX, "%s.last", skw_btsnoop_path); remove(last_log_path); if (!rename(skw_btsnoop_path, last_log_path) && (errno != ENOENT)) { ALOGE("%s unable to rename '%s' to btsnoop_hci: %s", __func__, skw_btsnoop_path, strerror(errno)); return ; } skwlog_reopen(TRUE); } else { btsnoop_rev_length = file_zie; if(file_zie < 16) { new_file = TRUE; } else { new_file = FALSE; } skwlog_reopen(new_file); } } else { if(file_zie > 16) { time_t current_time = time(NULL); struct tm *time_created = localtime(¤t_time); char config_time_created[sizeof("YYYY-MM-DD-HHMMSS") + 1]; strftime(config_time_created, sizeof("YYYY-MM-DD-HHMMSS"), "%Y-%m-%d-%H%M%S", time_created); timestamp = skw_btsnoop_timestamp() - BTSNOOP_EPOCH_DELTA; usec = (uint32_t)(timestamp % 1000000LL); snprintf(last_log_path, PATH_MAX, "%s.%s_%d-%02d", skw_btsnoop_path, config_time_created, (int)usec, (int)btsnoop_cnts); btsnoop_cnts ++; if (!rename(skw_btsnoop_path, last_log_path) && (errno != ENOENT)) { ALOGE("%s unable to rename '%s' to '%s': %s", __func__, skw_btsnoop_path, last_log_path, strerror(errno)); } } } } else if(skwlog_slice) { ALOGD("%s btsnoop log file not exist", __func__); skwlog_reopen(TRUE); } } else { snprintf(last_log_path, PATH_MAX, "%s.last", skw_btsnoop_path); if (!rename(skw_btsnoop_path, last_log_path) && errno != ENOENT) { ALOGE("%s unable to rename '%s' to '%s': %s", __func__, skw_btsnoop_path, last_log_path, strerror(errno)); } } hci_btsnoop_fd = open(skw_btsnoop_path, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); if (hci_btsnoop_fd < 0) { ALOGE("%s unable to open '%s': %s", __func__, skw_btsnoop_path, strerror(errno)); return; } ALOGD("%s open '%s', fd:%d, is new:%d", __func__, skw_btsnoop_path, hci_btsnoop_fd, new_file); //lseek(hci_btsnoop_fd, 0, SEEK_END); if(new_file) { write(hci_btsnoop_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16); ALOGD("%s write header", __func__); } } void skw_btsnoop_init() { pthread_mutex_init(&btsnoop_log_lock, NULL); btsnoop_cnts = 0; //ALOGD("%s btsnoop log file path:%s", __func__,skw_btsnoop_path); skw_btsnoop_open(); } void skw_btsnoop_close(void) { pthread_mutex_destroy(&btsnoop_log_lock); if (hci_btsnoop_fd != -1) { close(hci_btsnoop_fd); } hci_btsnoop_fd = -1; } static void skw_btsnoop_write(const void *data, size_t length) { if (hci_btsnoop_fd != -1) { write(hci_btsnoop_fd, data, length); } } void skw_btsnoop_capture(const uint8_t *packet, char is_received) { int length_he = 0; int length = 0; int flags = 0; int drops = 0; if((!btsnoop_log_en) || (hci_btsnoop_fd == -1)) { return ; } pthread_mutex_lock(&btsnoop_log_lock); uint8_t type = packet[0]; switch (type) { case HCI_COMMAND_PKT: length_he = packet[3] + 4; flags = 2; break; case HCI_ACLDATA_PKT: case HCI_ISO_PKT: length_he = (packet[4] << 8) + packet[3] + 5; flags = is_received; break; case HCI_SCODATA_PKT: length_he = packet[3] + 4; flags = is_received; break; case HCI_EVENT_PKT: case HCI_EVENT_SKWLOG: length_he = packet[2] + 3; flags = 3; break; default: pthread_mutex_unlock(&btsnoop_log_lock); return; //break; } btsnoop_rev_length += length_he; //SKWBT_LOG("btsnoop_capture type:%d, len:%d", type, length_he); uint64_t timestamp = skw_btsnoop_timestamp(); uint32_t time_hi = timestamp >> 32ul; uint32_t time_lo = timestamp & 0xFFFFFFFF; length = htonl(length_he); flags = htonl(flags); drops = htonl(drops); time_hi = htonl(time_hi); time_lo = htonl(time_lo); skw_btsnoop_write(&length, 4); skw_btsnoop_write(&length, 4); skw_btsnoop_write(&flags, 4); skw_btsnoop_write(&drops, 4); skw_btsnoop_write(&time_hi, 4); skw_btsnoop_write(&time_lo, 4); skw_btsnoop_write(packet, length_he); if(btsnoop_rev_length >= SKW_LOG_DEFAULT_SIZE) { close(hci_btsnoop_fd); hci_btsnoop_fd = -1; skw_btsnoop_open(); //skwlog_reopen(TRUE); } pthread_mutex_unlock(&btsnoop_log_lock); }