This patch adds btsnoop_create_fd function which allows to create
btsnoop on existing file descriptor instead of creating new file like
btsnoop_create does.
---
src/shared/btsnoop.c | 47 ++++++++++++++++++++++++++++++++++++-----------
src/shared/btsnoop.h | 1 +
2 files changed, 37 insertions(+), 11 deletions(-)
diff --git a/src/shared/btsnoop.c b/src/shared/btsnoop.c
index 17a872c..da993c5 100644
--- a/src/shared/btsnoop.c
+++ b/src/shared/btsnoop.c
@@ -128,12 +128,45 @@ failed:
return NULL;
}
-struct btsnoop *btsnoop_create(const char *path, uint32_t type)
+static bool btsnoop_init(struct btsnoop *btsnoop, uint32_t type)
{
- struct btsnoop *btsnoop;
struct btsnoop_hdr hdr;
ssize_t written;
+ btsnoop->type = type;
+ btsnoop->index = 0xffff;
+
+ memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
+ hdr.version = htobe32(btsnoop_version);
+ hdr.type = htobe32(btsnoop->type);
+
+ written = write(btsnoop->fd, &hdr, BTSNOOP_HDR_SIZE);
+
+ return written == BTSNOOP_HDR_SIZE;
+}
+
+struct btsnoop *btsnoop_create_fd(int fd, uint32_t type)
+{
+ struct btsnoop *btsnoop;
+
+ btsnoop = calloc(1, sizeof(*btsnoop));
+ if (!btsnoop)
+ return NULL;
+
+ btsnoop->fd = fd;
+
+ if (!btsnoop_init(btsnoop, type)) {
+ free(btsnoop);
+ return NULL;
+ }
+
+ return btsnoop_ref(btsnoop);
+}
+
+struct btsnoop *btsnoop_create(const char *path, uint32_t type)
+{
+ struct btsnoop *btsnoop;
+
btsnoop = calloc(1, sizeof(*btsnoop));
if (!btsnoop)
return NULL;
@@ -145,15 +178,7 @@ struct btsnoop *btsnoop_create(const char *path, uint32_t type)
return NULL;
}
- btsnoop->type = type;
- btsnoop->index = 0xffff;
-
- memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
- hdr.version = htobe32(btsnoop_version);
- hdr.type = htobe32(btsnoop->type);
-
- written = write(btsnoop->fd, &hdr, BTSNOOP_HDR_SIZE);
- if (written < 0) {
+ if (!btsnoop_init(btsnoop, type)) {
close(btsnoop->fd);
free(btsnoop);
return NULL;
diff --git a/src/shared/btsnoop.h b/src/shared/btsnoop.h
index 2c55d02..9e6b854 100644
--- a/src/shared/btsnoop.h
+++ b/src/shared/btsnoop.h
@@ -55,6 +55,7 @@ struct btsnoop;
struct btsnoop *btsnoop_open(const char *path, unsigned long flags);
struct btsnoop *btsnoop_create(const char *path, uint32_t type);
+struct btsnoop *btsnoop_create_fd(int fd, uint32_t type);
struct btsnoop *btsnoop_ref(struct btsnoop *btsnoop);
void btsnoop_unref(struct btsnoop *btsnoop);
--
1.9.3
Reading from ADB requires bluetoothd-snoop service to be running on
target device (i.e. HCI logging needs to be turned on in case of KitKat
devices).
Without optional argument, "-d" or "--read-adb" will connect to default
device and use default port (4330). Optional argument can be in form:
<serialno>:<port>
Any of <serialno> and <port> can be omitted and default value will be
used, i.e. --read-adb=ABCD will read from device with serial ABCD and
port 4330 while --read-adb=:1234 will read from default device and port
1234.
---
tools/hcidump.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 165 insertions(+), 2 deletions(-)
diff --git a/tools/hcidump.c b/tools/hcidump.c
index 37a9f00..3dff7d6 100644
--- a/tools/hcidump.c
+++ b/tools/hcidump.c
@@ -38,6 +38,7 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
+#include <arpa/inet.h>
#include "parser/parser.h"
#include "parser/sdp.h"
@@ -53,7 +54,8 @@ enum {
READ,
WRITE,
PPPDUMP,
- AUDIO
+ AUDIO,
+ ADB,
};
/* Default options */
@@ -522,6 +524,153 @@ static int open_file(char *file, int mode, unsigned long flags)
return fd;
}
+static int send_adb(int fd, const char *cmd)
+{
+ char buf[128];
+ unsigned int len;
+ struct iovec iov[2];
+
+ len = strlen(cmd);
+ sprintf(buf, "%04X", len);
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = 4;
+ iov[1].iov_base = (void *) cmd;
+ iov[1].iov_len = len;
+
+ if (writev(fd, iov, 2) < 0)
+ return -1;
+
+ if (recv(fd, buf, sizeof(buf), 0) < 0)
+ return -1;
+
+ /* OKAY means we're fine */
+ if (!memcmp("OKAY", buf, 4))
+ return 0;
+
+ /*
+ * failure comes in format FAIL<4hex><msg> where <4hex> is length of
+ * <msg> written as hexadecimal string (4 chars)
+ */
+ if (sscanf(buf, "FAIL%04X", &len) > 0) {
+ buf[8 + len] = '\0';
+ fprintf(stderr, "ADB: %s\n", &buf[8]);
+ } else {
+ fprintf(stderr, "ADB: unknown failure");
+ }
+
+ return -1;
+}
+
+static int connect_adb(const char *serial, int port)
+{
+ struct sockaddr_in addr;
+ char cmd[128];
+ int fd;
+
+ fd = socket(PF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (fd < 0) {
+ perror("Failed to open TCP client socket");
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ addr.sin_port = htons(5037); /* default ADB port */
+
+ if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("Failed to connect TCP client socket");
+ close(fd);
+ return -1;
+ }
+
+ /* first need to switch socket to adb daemon on device */
+ if (serial)
+ sprintf(cmd, "host:transport:%s", serial);
+ else
+ strcpy(cmd, "host:transport-any");
+ if (send_adb(fd, cmd) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ /* next need to switch socket to tcp socket */
+ sprintf(cmd, "tcp:%d", port ? port : 4330);
+ if (send_adb(fd, cmd) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+static void parse_adb(const char *device, char **serial, int *port)
+{
+ const char *p;
+
+ *serial = NULL;
+ *port = 0;
+
+ if (!device)
+ return;
+
+ p = strrchr(device, ':');
+ if (!p) {
+ *serial = strdup(device);
+ return;
+ }
+
+ if (p - device)
+ *serial = strndup(device, p - device);
+ *port = atoi(&p[1]);
+}
+
+static int open_adb(const char *device)
+{
+ unsigned char buf[BTSNOOP_HDR_SIZE];
+ struct btsnoop_hdr *hdr = (struct btsnoop_hdr *) buf;
+ int fd, len;
+ char *serial;
+ int port;
+
+ parse_adb(device, &serial, &port);
+
+ fd = connect_adb(serial, port);
+ if (fd < 0)
+ return -1;
+
+ free(serial);
+
+ len = read(fd, buf, BTSNOOP_HDR_SIZE);
+ if (len != BTSNOOP_HDR_SIZE)
+ return -1;
+
+ if (memcmp(hdr->id, btsnoop_id, sizeof(btsnoop_id)))
+ return -1;
+
+ parser.flags |= DUMP_BTSNOOP;
+
+ btsnoop_version = be32toh(hdr->version);
+ btsnoop_type = be32toh(hdr->type);
+
+ printf("btsnoop version: %d datalink type: %d\n",
+ btsnoop_version, btsnoop_type);
+
+ if (btsnoop_version != 1) {
+ fprintf(stderr, "Unsupported BTSnoop version\n");
+ exit(1);
+ }
+
+ if (btsnoop_type != 1001 && btsnoop_type != 1002 &&
+ btsnoop_type != 2001) {
+ fprintf(stderr, "Unsupported BTSnoop datalink type\n");
+ exit(1);
+ }
+
+ return fd;
+}
+
static int open_socket(int dev, unsigned long flags)
{
struct sockaddr_hci addr;
@@ -624,6 +773,7 @@ static void usage(void)
" -m, --manufacturer=compid Default manufacturer\n"
" -w, --save-dump=file Save dump to a file\n"
" -r, --read-dump=file Read dump from a file\n"
+ " -d, --read-adb=dev Read dump via ADB\n"
" -t, --ts Display time stamps\n"
" -a, --ascii Dump data in ascii\n"
" -x, --hex Dump data in hex\n"
@@ -650,6 +800,7 @@ static struct option main_options[] = {
{ "manufacturer", 1, 0, 'm' },
{ "save-dump", 1, 0, 'w' },
{ "read-dump", 1, 0, 'r' },
+ { "read-adb", 2, 0, 'd' },
{ "timestamp", 0, 0, 't' },
{ "ascii", 0, 0, 'a' },
{ "hex", 0, 0, 'x' },
@@ -679,7 +830,7 @@ int main(int argc, char *argv[])
uint16_t obex_port;
while ((opt = getopt_long(argc, argv,
- "i:l:p:m:w:r:taxXRC:H:O:P:S:D:A:Yhv",
+ "i:l:p:m:w:r:d::taxXRC:H:O:P:S:D:A:Yhv",
main_options, NULL)) != -1) {
switch(opt) {
case 'i':
@@ -711,6 +862,11 @@ int main(int argc, char *argv[])
dump_file = strdup(optarg);
break;
+ case 'd':
+ mode = ADB;
+ dump_file = optarg ? strdup(optarg) : NULL;
+ break;
+
case 't':
flags |= DUMP_TSTAMP;
break;
@@ -817,6 +973,13 @@ int main(int argc, char *argv[])
process_frames(device, open_socket(device, flags),
open_file(dump_file, mode, flags), flags);
break;
+
+ case ADB:
+ flags |= DUMP_VERBOSE;
+ init_parser(flags, filter, defpsm, defcompid,
+ pppdump_fd, audio_fd);
+ read_dump(open_adb(dump_file));
+ break;
}
return 0;
--
1.9.3
This patch adds support to write snoop file to client connected via
TCP. Default listen port is 4330 which is used by Bluedroid for similar
purpose.
---
android/bluetoothd-snoop.c | 123 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 122 insertions(+), 1 deletion(-)
diff --git a/android/bluetoothd-snoop.c b/android/bluetoothd-snoop.c
index 57f97f4..25b9c97 100644
--- a/android/bluetoothd-snoop.c
+++ b/android/bluetoothd-snoop.c
@@ -32,6 +32,9 @@
#if defined(ANDROID)
#include <sys/capability.h>
#endif
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
#include "lib/bluetooth.h"
#include "lib/hci.h"
@@ -41,12 +44,15 @@
#include "src/shared/btsnoop.h"
#define DEFAULT_SNOOP_FILE "/sdcard/btsnoop_hci.log"
+#define DEFAULT_TCP_PORT 4330
#define MAX_PACKET_SIZE (1486 + 4)
static struct btsnoop *snoop = NULL;
+static struct btsnoop *tcp_snoop = NULL;
static uint8_t monitor_buf[MAX_PACKET_SIZE];
static int monitor_fd = -1;
+static int server_fd = -1;
static void signal_callback(int signum, void *user_data)
{
@@ -137,8 +143,10 @@ static void data_callback(int fd, uint32_t events, void *user_data)
continue;
flags = get_flags_from_opcode(opcode);
- if (flags != 0xff)
+ if (flags != 0xff) {
btsnoop_write(snoop, tv, flags, monitor_buf, pktlen);
+ btsnoop_write(tcp_snoop, tv, flags, monitor_buf, pktlen);
+ }
}
}
@@ -215,6 +223,115 @@ static void set_capabilities(void)
#endif
}
+static void tcp_callback(int fd, uint32_t events, void *user_data)
+{
+ if (events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) {
+ mainloop_remove_fd(fd);
+
+ free(tcp_snoop);
+ tcp_snoop = NULL;
+
+ printf("TCP client disconnected\n");
+ }
+}
+
+static void accept_tcp(int fd, uint32_t events, void *user_data)
+{
+ struct sockaddr_un addr;
+ socklen_t len;
+ int nfd;
+
+ memset(&addr, 0, sizeof(addr));
+ len = sizeof(addr);
+
+ if (events & (EPOLLERR | EPOLLHUP)) {
+ mainloop_remove_fd(server_fd);
+ return;
+ }
+
+ nfd = accept(server_fd, (struct sockaddr *) &addr, &len);
+ if (nfd < 0) {
+ perror("Failed to accept incoming connection\n");
+ return;
+ }
+
+ /* We only support one client connected */
+ if (tcp_snoop) {
+ fprintf(stderr, "TCP client already connected\n");
+ close(nfd);
+ return;
+ }
+
+ if (mainloop_add_fd(nfd, EPOLLIN | EPOLLRDHUP, tcp_callback,
+ NULL, NULL) < 0) {
+ fprintf(stderr, "Failed to setup watch on client\n");
+ close(nfd);
+ return;
+ }
+
+ tcp_snoop = btsnoop_create_fd(nfd, BTSNOOP_TYPE_HCI);
+ if (!tcp_snoop) {
+ fprintf(stderr, "Failed to create snoop\n");
+ close(nfd);
+ return;
+ }
+
+ printf("TCP client connected\n");
+}
+
+static int open_tcp(void)
+{
+ struct sockaddr_in addr;
+ int fd, opt = 1;
+
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+ if (fd < 0) {
+ perror("Failed to open server socket\n");
+ return -1;
+ }
+
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+ addr.sin_port = htons(DEFAULT_TCP_PORT);
+
+ if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("Failed to bind server socket\n");
+ close(fd);
+ return -1;
+ }
+
+ if (listen(fd, 5) < 0) {
+ perror("Failed to listen server socket\n");
+ close(fd);
+ return -1;
+ }
+
+ if (mainloop_add_fd(fd, EPOLLIN, accept_tcp, NULL, NULL) < 0) {
+ fprintf(stderr, "Failed to setup watch on server socket\n");
+ close(fd);
+ return -1;
+ }
+
+ server_fd = fd;
+
+ printf("TCP server ready\n");
+
+ return 0;
+}
+
+static void close_tcp(void)
+{
+ close(server_fd);
+
+ mainloop_remove_fd(server_fd);
+
+ server_fd = -1;
+}
+
int main(int argc, char *argv[])
{
const char *path;
@@ -243,8 +360,12 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
+ open_tcp();
+
mainloop_run();
+ close_tcp();
+
close_monitor();
return EXIT_SUCCESS;
--
1.9.3
This patch makes btsnoop_write to use writev so there's single write
instead of two. It's useful when file descriptor is e.g. TCP socket
rather than regular file.
---
src/shared/btsnoop.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/src/shared/btsnoop.c b/src/shared/btsnoop.c
index da993c5..59f8c65 100644
--- a/src/shared/btsnoop.c
+++ b/src/shared/btsnoop.c
@@ -32,6 +32,7 @@
#include <string.h>
#include <arpa/inet.h>
#include <sys/stat.h>
+#include <sys/uio.h>
#include "src/shared/btsnoop.h"
@@ -225,6 +226,7 @@ bool btsnoop_write(struct btsnoop *btsnoop, struct timeval *tv,
struct btsnoop_pkt pkt;
uint64_t ts;
ssize_t written;
+ struct iovec iov[2];
if (!btsnoop || !tv)
return false;
@@ -237,17 +239,14 @@ bool btsnoop_write(struct btsnoop *btsnoop, struct timeval *tv,
pkt.drops = htobe32(0);
pkt.ts = htobe64(ts + 0x00E03AB44A676000ll);
- written = write(btsnoop->fd, &pkt, BTSNOOP_PKT_SIZE);
- if (written < 0)
- return false;
+ iov[0].iov_base = &pkt;
+ iov[0].iov_len = BTSNOOP_PKT_SIZE;
+ iov[1].iov_base = (void *) data;
+ iov[1].iov_len = size;
- if (data && size > 0) {
- written = write(btsnoop->fd, data, size);
- if (written < 0)
- return false;
- }
+ written = writev(btsnoop->fd, iov, 2);
- return true;
+ return written >= 0;
}
static uint32_t get_flags_from_opcode(uint16_t opcode)
--
1.9.3