diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2014-01-16 00:27:30 -0800 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-01-16 00:27:30 -0800 |
commit | 81294e5f5ade03ae490aceffce0955e506ea0b16 (patch) | |
tree | e5c670496b9c9ba3a2fdce9309bebef20d52425d | |
parent | 1d6fbfb1dad2ecc1218cd0011319aa216858f772 (diff) |
tools: Remove --smd option from proxy utility
-rw-r--r-- | tools/btproxy.c | 460 |
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; |