summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2014-01-16 00:27:30 -0800
committerMarcel Holtmann <marcel@holtmann.org>2014-01-16 00:27:30 -0800
commit81294e5f5ade03ae490aceffce0955e506ea0b16 (patch)
treee5c670496b9c9ba3a2fdce9309bebef20d52425d
parent1d6fbfb1dad2ecc1218cd0011319aa216858f772 (diff)
tools: Remove --smd option from proxy utility
-rw-r--r--tools/btproxy.c460
1 files changed, 240 insertions, 220 deletions
diff --git a/tools/btproxy.c b/tools/btproxy.c
index 4def50382..4429a16c6 100644
--- a/tools/btproxy.c
+++ b/tools/btproxy.c
@@ -56,277 +56,296 @@ struct sockaddr_hci {
#define HCI_CHANNEL_USER 1
static uint16_t hci_index = 0;
-static bool use_smd = false;
static bool client_active = false;
+static bool debug_enabled = false;
static void hexdump_print(const char *str, void *user_data)
{
- printf("%s\n", str);
+ printf("%s%s\n", (char *) user_data, str);
}
-struct stream {
- char dir;
- int src_fd;
- uint8_t src_type;
- int dst_fd;
- uint8_t dst_type;
- uint8_t buf[4096];
- uint16_t len;
+struct proxy {
+ /* Receive commands, ACL and SCO data */
+ int host_fd;
+ uint8_t host_buf[4096];
+ uint16_t host_len;
+ bool host_shutdown;
+
+ /* Receive events, ACL and SCO data */
+ int dev_fd;
+ uint8_t dev_buf[4096];
+ uint16_t dev_len;
+ bool dev_shutdown;
};
-static void stream_free(void *data)
+static bool write_packet(int fd, const void *data, size_t size,
+ void *user_data)
{
- struct stream *stream = data;
+ while (size > 0) {
+ ssize_t written;
- printf("Closing stream %c\n", stream->dir);
+ written = write(fd, data, size);
+ if (written < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ return false;
+ }
- client_active = false;
+ if (debug_enabled)
+ util_hexdump('<', data, written, hexdump_print,
+ user_data);
- close(stream->src_fd);
+ data += written;
+ size -= written;
+ }
- free(stream);
+ return true;
}
-static void stream_callback(int fd, uint32_t events, void *user_data)
+static void host_read_destroy(void *user_data)
{
- struct stream *stream = user_data;
- uint8_t *wbuf;
- ssize_t wlen, len;
+ struct proxy *proxy = user_data;
+
+ printf("Closing host descriptor\n");
+
+ if (proxy->host_shutdown)
+ shutdown(proxy->host_fd, SHUT_RDWR);
+
+ close(proxy->host_fd);
+ proxy->host_fd = -1;
+
+ if (proxy->dev_fd < 0) {
+ client_active = false;
+ free(proxy);
+ } else
+ mainloop_remove_fd(proxy->dev_fd);
+}
+
+static void host_read_callback(int fd, uint32_t events, void *user_data)
+{
+ struct proxy *proxy = user_data;
+ struct bt_hci_cmd_hdr *cmd_hdr;
+ struct bt_hci_acl_hdr *acl_hdr;
+ struct bt_hci_sco_hdr *sco_hdr;
+ ssize_t len;
uint16_t pktlen;
if (events & (EPOLLERR | EPOLLHUP)) {
- mainloop_remove_fd(stream->src_fd);
+ fprintf(stderr, "Error from host descriptor\n");
+ mainloop_remove_fd(proxy->host_fd);
+ return;
+ }
+
+ if (events & EPOLLRDHUP) {
+ fprintf(stderr, "Remote hangup of host descriptor\n");
+ mainloop_remove_fd(proxy->host_fd);
return;
}
- len = read(stream->src_fd, stream->buf + stream->len,
- sizeof(stream->buf) - stream->len);
+ len = read(proxy->host_fd, proxy->host_buf + proxy->host_len,
+ sizeof(proxy->host_buf) - proxy->host_len);
if (len < 0) {
if (errno == EAGAIN || errno == EINTR)
return;
- fprintf(stderr, "Failed to read stream packet\n");
- mainloop_remove_fd(stream->src_fd);
+
+ fprintf(stderr, "Read from host descriptor failed\n");
+ mainloop_remove_fd(proxy->host_fd);
return;
}
- util_hexdump(stream->dir, stream->buf + stream->len, len,
- hexdump_print, NULL);
+ if (debug_enabled)
+ util_hexdump('>', proxy->host_buf + proxy->host_len, len,
+ hexdump_print, "H: ");
- stream->len += len;
+ proxy->host_len += len;
process_packet:
- if (stream->len < 1)
+ if (proxy->host_len < 1)
return;
- switch (stream->buf[0]) {
+ switch (proxy->host_buf[0]) {
case BT_H4_CMD_PKT:
- {
- struct bt_hci_cmd_hdr *hdr;
-
- if (stream->len < 1 + sizeof(*hdr))
- return;
+ if (proxy->host_len < 1 + sizeof(*cmd_hdr))
+ return;
- hdr = (void *) (stream->buf + 1);
- pktlen = 1 + sizeof(*hdr) + hdr->plen;
- }
+ cmd_hdr = (void *) (proxy->host_buf + 1);
+ pktlen = 1 + sizeof(*cmd_hdr) + cmd_hdr->plen;
break;
case BT_H4_ACL_PKT:
- {
- struct bt_hci_acl_hdr *hdr;
-
- if (stream->len < 1 + sizeof(*hdr))
- return;
+ if (proxy->host_len < 1 + sizeof(*acl_hdr))
+ return;
- hdr = (void *) (stream->buf + 1);
- pktlen = 1 + sizeof(*hdr) + cpu_to_le16(hdr->dlen);
- }
+ acl_hdr = (void *) (proxy->host_buf + 1);
+ pktlen = 1 + sizeof(*acl_hdr) + cpu_to_le16(acl_hdr->dlen);
break;
case BT_H4_SCO_PKT:
- {
- struct bt_hci_sco_hdr *hdr;
-
- if (stream->len < 1 + sizeof(*hdr))
- return;
-
- hdr = (void *) (stream->buf + 1);
- pktlen = 1 + sizeof(*hdr) + hdr->dlen;
- }
- break;
- case BT_H4_EVT_PKT:
- {
- struct bt_hci_evt_hdr *hdr;
-
- if (stream->len < 1 + sizeof(*hdr))
- return;
+ if (proxy->host_len < 1 + sizeof(*sco_hdr))
+ return;
- hdr = (void *) (stream->buf + 1);
- pktlen = 1 + sizeof(*hdr) + hdr->plen;
- }
+ sco_hdr = (void *) (proxy->host_buf + 1);
+ pktlen = 1 + sizeof(*sco_hdr) + sco_hdr->dlen;
break;
case 0xff:
- if (stream->src_type > 0) {
- mainloop_remove_fd(stream->src_fd);
- return;
- }
/* Notification packet from /dev/vhci - ignore */
- stream->len = 0;
+ proxy->host_len = 0;
return;
default:
- fprintf(stderr, "Received unknown packet type 0x%02x\n",
- stream->buf[0]);
- mainloop_remove_fd(stream->src_fd);
+ fprintf(stderr, "Received unknown host packet type 0x%02x\n",
+ proxy->host_buf[0]);
+ mainloop_remove_fd(proxy->host_fd);
return;
}
- if (stream->len < pktlen)
+ if (proxy->host_len < pktlen)
return;
- if (stream->dst_type > 0) {
- if (stream->buf[0] != stream->dst_type)
- goto next_packet;
- wbuf = stream->buf + 1;
- wlen = pktlen - 1;
- } else {
- wbuf = stream->buf;
- wlen = pktlen;
+ if (!write_packet(proxy->dev_fd, proxy->host_buf, pktlen, "D: ")) {
+ fprintf(stderr, "Write to device descriptor failed\n");
+ mainloop_remove_fd(proxy->dev_fd);
+ return;
}
- printf("* wlen = %zd\n", wlen);
- util_hexdump('*', wbuf, wlen, hexdump_print, NULL);
+ if (proxy->host_len > pktlen) {
+ memmove(proxy->host_buf, proxy->host_buf + pktlen,
+ proxy->host_len - pktlen);
+ proxy->host_len -= pktlen;
+ goto process_packet;
+ }
- while (wlen > 0) {
- ssize_t written;
+ proxy->host_len = 0;
+}
- written = write(stream->dst_fd, wbuf, wlen);
- if (written < 0) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- fprintf(stderr, "Failed to write stream packet\n");
- mainloop_remove_fd(stream->src_fd);
- return;
- }
+static void dev_read_destroy(void *user_data)
+{
+ struct proxy *proxy = user_data;
- wbuf += written;
- wlen -= written;
- }
+ printf("Closing device descriptor\n");
-next_packet:
- if (stream->len > pktlen) {
- if (stream->src_type > 0) {
- memmove(stream->buf + 1, stream->buf + pktlen,
- stream->len - pktlen);
- stream->len -= pktlen;
+ if (proxy->dev_shutdown)
+ shutdown(proxy->dev_fd, SHUT_RDWR);
- stream->buf[0] = stream->src_type;
- stream->len++;
- } else {
- memmove(stream->buf, stream->buf + pktlen,
- stream->len - pktlen);
- stream->len -= pktlen;
- }
+ close(proxy->dev_fd);
+ proxy->dev_fd = -1;
- goto process_packet;
- } else {
- if (stream->src_type > 0) {
- stream->buf[0] = stream->src_type;
- stream->len = 1;
- } else
- stream->len = 0;
- }
+ if (proxy->host_fd < 0) {
+ client_active = false;
+ free(proxy);
+ } else
+ mainloop_remove_fd(proxy->host_fd);
}
-static struct stream *stream_create(char dir, int src_fd, uint8_t src_type,
- int dst_fd, uint8_t dst_type)
+static void dev_read_callback(int fd, uint32_t events, void *user_data)
{
- struct stream *stream;
-
- stream = new0(struct stream, 1);
- if (!stream)
- return NULL;
-
- stream->dir = dir;
-
- stream->src_fd = src_fd;
- stream->src_type = src_type;
+ struct proxy *proxy = user_data;
+ struct bt_hci_evt_hdr *evt_hdr;
+ struct bt_hci_acl_hdr *acl_hdr;
+ struct bt_hci_sco_hdr *sco_hdr;
+ ssize_t len;
+ uint16_t pktlen;
- stream->dst_fd = dst_fd;
- stream->dst_type = dst_type;
+ if (events & (EPOLLERR | EPOLLHUP)) {
+ fprintf(stderr, "Error from device descriptor\n");
+ mainloop_remove_fd(proxy->dev_fd);
+ return;
+ }
- if (stream->src_type > 0) {
- stream->buf[0] = stream->src_type;
- stream->len = 1;
+ if (events & EPOLLRDHUP) {
+ fprintf(stderr, "Remote hangup of device descriptor\n");
+ mainloop_remove_fd(proxy->host_fd);
+ return;
}
- mainloop_add_fd(stream->src_fd, EPOLLIN, stream_callback,
- stream, stream_free);
+ len = read(proxy->dev_fd, proxy->dev_buf + proxy->dev_len,
+ sizeof(proxy->dev_buf) - proxy->dev_len);
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return;
- return stream;
-}
+ fprintf(stderr, "Read from device descriptor failed\n");
+ mainloop_remove_fd(proxy->dev_fd);
+ return;
+ }
-static bool setup_streams(int src_fd, uint8_t src_type_rx,
- uint8_t src_type_tx, int dst_fd)
-{
- struct stream *stream;
+ if (debug_enabled)
+ util_hexdump('>', proxy->dev_buf + proxy->dev_len, len,
+ hexdump_print, "D: ");
- stream = stream_create('>', src_fd, src_type_rx, dst_fd, 0x00);
- if (!stream) {
- fprintf(stderr, "Failed to create source stream\n");
- close(src_fd);
- close(dst_fd);
- return false;
- }
+ proxy->dev_len += len;
- stream = stream_create('<', dst_fd, 0x00, src_fd, src_type_tx);
- if (!stream) {
- fprintf(stderr, "Failed to create destination stream\n");
- close(src_fd);
- close(dst_fd);
- return false;
- }
+process_packet:
+ if (proxy->dev_len < 1)
+ return;
- return true;
-}
+ switch (proxy->dev_buf[0]) {
+ case BT_H4_EVT_PKT:
+ if (proxy->dev_len < 1 + sizeof(*evt_hdr))
+ return;
-static int open_smd(void)
-{
- struct termios ti;
- int fd;
+ evt_hdr = (void *) (proxy->dev_buf + 1);
+ pktlen = 1 + sizeof(*evt_hdr) + evt_hdr->plen;
+ break;
+ case BT_H4_ACL_PKT:
+ if (proxy->dev_len < 1 + sizeof(*acl_hdr))
+ return;
- printf("Opening /dev/smd3 device\n");
+ acl_hdr = (void *) (proxy->dev_buf + 1);
+ pktlen = 1 + sizeof(*acl_hdr) + cpu_to_le16(acl_hdr->dlen);
+ break;
+ case BT_H4_SCO_PKT:
+ if (proxy->dev_len < 1 + sizeof(*sco_hdr))
+ return;
- fd = open("/dev/smd3", O_RDWR | O_NOCTTY | O_CLOEXEC);
- if (fd < 0) {
- perror("Failed to open /dev/smd3 device");
- return -1;
+ sco_hdr = (void *) (proxy->dev_buf + 1);
+ pktlen = 1 + sizeof(*sco_hdr) + sco_hdr->dlen;
+ break;
+ default:
+ fprintf(stderr, "Received unknown device packet type 0x%02x\n",
+ proxy->dev_buf[0]);
+ mainloop_remove_fd(proxy->dev_fd);
+ return;
}
- /* Sleep 0.5 sec to give smd port time to fully initialize */
- usleep(500000);
+ if (proxy->dev_len < pktlen)
+ return;
- if (tcflush(fd, TCIOFLUSH) < 0) {
- perror("Failed to flush /dev/smd3 device");
- close(fd);
- return -1;
+ if (!write_packet(proxy->host_fd, proxy->dev_buf, pktlen, "H: ")) {
+ fprintf(stderr, "Write to host descriptor failed\n");
+ mainloop_remove_fd(proxy->host_fd);
+ return;
}
- if (tcgetattr(fd, &ti) < 0) {
- perror("Failed to get /dev/smd3 attributes");
- close(fd);
- return -1;
+ if (proxy->dev_len > pktlen) {
+ memmove(proxy->dev_buf, proxy->dev_buf + pktlen,
+ proxy->dev_len - pktlen);
+ proxy->dev_len -= pktlen;
+ goto process_packet;
}
- /* Switch to raw mode */
- cfmakeraw(&ti);
+ proxy->dev_len = 0;
+}
- ti.c_cflag |= CRTSCTS | CLOCAL;
+static bool setup_proxy(int host_fd, bool host_shutdown,
+ int dev_fd, bool dev_shutdown)
+{
+ struct proxy *proxy;
- if (tcsetattr(fd, TCSANOW, &ti) < 0) {
- perror("Failed to set /dev/smd3 attributes");
- close(fd);
- return -1;
- }
+ proxy = new0(struct proxy, 1);
+ if (!proxy)
+ return NULL;
- return fd;
+ proxy->host_fd = host_fd;
+ proxy->host_shutdown = host_shutdown;
+
+ proxy->dev_fd = dev_fd;
+ proxy->dev_shutdown = dev_shutdown;
+
+ mainloop_add_fd(proxy->host_fd, EPOLLIN | EPOLLRDHUP,
+ host_read_callback, proxy, host_read_destroy);
+
+ mainloop_add_fd(proxy->dev_fd, EPOLLIN | EPOLLRDHUP,
+ dev_read_callback, proxy, dev_read_destroy);
+
+ return true;
}
static int open_channel(uint16_t index)
@@ -359,12 +378,12 @@ static int open_channel(uint16_t index)
static void server_callback(int fd, uint32_t events, void *user_data)
{
union {
+ struct sockaddr common;
struct sockaddr_un sun;
struct sockaddr_in sin;
} addr;
socklen_t len;
- int src_fd, dst_fd;
- uint8_t src_type_rx, src_type_tx;
+ int host_fd, dev_fd;
if (events & (EPOLLERR | EPOLLHUP)) {
mainloop_quit();
@@ -374,41 +393,32 @@ static void server_callback(int fd, uint32_t events, void *user_data)
memset(&addr, 0, sizeof(addr));
len = sizeof(addr);
- if (getsockname(fd, (struct sockaddr *) &addr, &len) < 0) {
+ if (getsockname(fd, &addr.common, &len) < 0) {
perror("Failed to get socket name");
return;
}
- dst_fd = accept(fd, (struct sockaddr *) &addr, &len);
- if (dst_fd < 0) {
+ host_fd = accept(fd, &addr.common, &len);
+ if (host_fd < 0) {
perror("Failed to accept client socket");
return;
}
if (client_active) {
fprintf(stderr, "Active client already present\n");
- close(dst_fd);
+ close(host_fd);
return;
}
- if (use_smd) {
- src_fd = open_smd();
- src_type_rx = BT_H4_EVT_PKT;
- src_type_tx = BT_H4_CMD_PKT;
- } else {
- src_fd = open_channel(hci_index);
- src_type_rx = 0x00;
- src_type_tx = 0x00;
- }
-
- if (src_fd < 0) {
- close(dst_fd);
+ dev_fd = open_channel(hci_index);
+ if (dev_fd < 0) {
+ close(host_fd);
return;
}
printf("New client connected\n");
- if (!setup_streams(src_fd, src_type_rx, src_type_tx, dst_fd))
+ if (!setup_proxy(host_fd, true, dev_fd, false))
return;
client_active = true;
@@ -544,13 +554,13 @@ static void usage(void)
printf("btproxy - Bluetooth controller proxy\n"
"Usage:\n");
printf("\tbtproxy [options]\n");
- printf("options:\n"
+ printf("Options:\n"
"\t-c, --connect <address> Connect to server\n"
"\t-l, --listen [address] Use TCP server\n"
"\t-u, --unix [path] Use Unix server\n"
"\t-p, --port <port> Use specified TCP port\n"
"\t-i, --index <num> Use specified controller\n"
- "\t-s, --smd Use SMD channel devices\n"
+ "\t-d, --debug Enable debugging output\n"
"\t-h, --help Show help options\n");
}
@@ -560,7 +570,7 @@ static const struct option main_options[] = {
{ "unix", optional_argument, NULL, 'u' },
{ "port", required_argument, NULL, 'p' },
{ "index", required_argument, NULL, 'i' },
- { "smd", no_argument, NULL, 's' },
+ { "debug", no_argument, NULL, 'd' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ }
@@ -571,14 +581,14 @@ int main(int argc, char *argv[])
const char *connect_address = NULL;
const char *server_address = NULL;
const char *unix_path = NULL;
- unsigned short tcp_port = 0xb1ee;
+ unsigned short tcp_port = 0xb1ee; /* 45550 */
const char *str;
sigset_t mask;
for (;;) {
int opt;
- opt = getopt_long(argc, argv, "c:l::u::p:i:svh",
+ opt = getopt_long(argc, argv, "c:l::u::p:i:dvh",
main_options, NULL);
if (opt < 0)
break;
@@ -613,8 +623,8 @@ int main(int argc, char *argv[])
}
hci_index = atoi(str);
break;
- case 's':
- use_smd = true;
+ case 'd':
+ debug_enabled = true;
break;
case 'v':
printf("%s\n", VERSION);
@@ -632,6 +642,16 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
+ if (unix_path && server_address) {
+ fprintf(stderr, "Invalid to specify TCP and Unix servers\n");
+ return EXIT_FAILURE;
+ }
+
+ if (connect_address && (unix_path || server_address)) {
+ fprintf(stderr, "Invalid to specify client and server mode\n");
+ return EXIT_FAILURE;
+ }
+
mainloop_init();
sigemptyset(&mask);
@@ -641,23 +661,23 @@ int main(int argc, char *argv[])
mainloop_set_signal(&mask, signal_callback, NULL, NULL);
if (connect_address) {
- int src_fd, dst_fd;
+ int host_fd, dev_fd;
printf("Connecting to %s:%u\n", connect_address, tcp_port);
- src_fd = connect_tcp(connect_address, tcp_port);
- if (src_fd < 0)
+ dev_fd = connect_tcp(connect_address, tcp_port);
+ if (dev_fd < 0)
return EXIT_FAILURE;
printf("Opening virtual device\n");
- dst_fd = open_vhci(0x00);
- if (dst_fd < 0) {
- close(src_fd);
+ host_fd = open_vhci(0x00);
+ if (host_fd < 0) {
+ close(dev_fd);
return EXIT_FAILURE;
}
- if (!setup_streams(src_fd, 0x00, 0x00, dst_fd))
+ if (!setup_proxy(host_fd, false, dev_fd, true))
return EXIT_FAILURE;
} else {
int server_fd;