diff options
author | Sharvil Nanavati <sharvil@google.com> | 2014-08-13 01:14:49 -0700 |
---|---|---|
committer | Andre Eisenbach <eisenbach@google.com> | 2015-03-16 16:51:28 -0700 |
commit | 1f8c2356a1d9beeb40a9e107df415f46d50ee8ba (patch) | |
tree | b0bc60921a20bd702f748d3c38154641461f952f /tools | |
parent | 8d546df22536ce78e19d15e5e70e0dc8109796c3 (diff) | |
download | android_system_bt-1f8c2356a1d9beeb40a9e107df415f46d50ee8ba.tar.gz android_system_bt-1f8c2356a1d9beeb40a9e107df415f46d50ee8ba.tar.bz2 android_system_bt-1f8c2356a1d9beeb40a9e107df415f46d50ee8ba.zip |
Add a tool to inject HCI commands into bluedroid.
This tool is very primitive in a number of ways. First, each new
HCI command needs to be carefully crafted. Second, it is entirely
stateless and operates in "fire-and-forget" mode. In other words,
there's no "read-modify-write" capability yet. That being said,
this tool will grow along with the infrastructure in bluedroid.
Diffstat (limited to 'tools')
-rw-r--r-- | tools/hci/Android.mk | 29 | ||||
-rw-r--r-- | tools/hci/main.c | 165 |
2 files changed, 194 insertions, 0 deletions
diff --git a/tools/hci/Android.mk b/tools/hci/Android.mk new file mode 100644 index 000000000..e52704ed0 --- /dev/null +++ b/tools/hci/Android.mk @@ -0,0 +1,29 @@ +# +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := hci + +LOCAL_SRC_FILES := main.c +LOCAL_STATIC_LIBRARIES := libosi +LOCAL_CFLAGS := -std=c99 $(bdroid_CFLAGS) +LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../osi/include + +include $(BUILD_EXECUTABLE) diff --git a/tools/hci/main.c b/tools/hci/main.c new file mode 100644 index 000000000..5c4e148f8 --- /dev/null +++ b/tools/hci/main.c @@ -0,0 +1,165 @@ +#include <hardware/bluetooth.h> +#include <netinet/in.h> +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +#include "osi.h" + +typedef int (*handler_t)(int argc, char **argv); + +typedef enum { + HCI_PACKET_COMMAND = 1, + HCI_PACKET_ACL_DATA = 2, + HCI_PACKET_SCO_DATA = 3, + HCI_PACKET_EVENT = 4, +} hci_packet_t; + +typedef struct { + const char *name; + const char *help; + handler_t handler; +} command_t; + +static int help(int argc, char **argv); +static int set_name(int argc, char **argv); +static int set_pcm_loopback(int argc, char **argv); + +static bool write_hci_command(hci_packet_t type, const void *packet, size_t length); +static const command_t *find_command(const char *name); +static void usage(const char *name); + +static const command_t commands[] = { + { "help", "<command> - shows help text for <command>.", help }, + { "setName", "<name> - sets the device's Bluetooth name to <name>.", set_name }, + { "setPcmLoopback", "(true|false) - enables or disables PCM loopback on the controller.", set_pcm_loopback }, +}; + +static int help(int argc, char **argv) { + if (!argc) { + printf("No help command specified.\n"); + return 1; + } + + const command_t *command = find_command(argv[0]); + if (!command) { + printf("No command named '%s'.\n", argv[0]); + return 2; + } + + printf("%s %s\n", argv[0], command->help); + return 0; +} + +static int set_name(int argc, char **argv) { + if (argc != 1) { + printf("Device name not specified.\n"); + return 1; + } + + size_t len = strlen(argv[0]); + if (len > 247) { + printf("Device name cannot exceed 247 bytes.\n"); + return 2; + } + + uint8_t packet[251] = { 0x13, 0x0C, 248 }; + memcpy(&packet[3], argv[0], len + 1); + + if (!write_hci_command(HCI_PACKET_COMMAND, packet, sizeof(packet))) + return 1; + + memset(&packet[0], sizeof(packet), 0); + packet[0] = 0x52; + packet[1] = 0x0C; + packet[2] = 0xF1; // HCI command packet length. + packet[3] = 0x01; // FEC required. + packet[4] = len + 1; + packet[5] = 0x09; // Device name field tag. + memcpy(&packet[6], argv[0], len); + return !write_hci_command(HCI_PACKET_COMMAND, packet, 0xF4); +} + +static int set_pcm_loopback(int argc, char **argv) { + if (argc != 1) { + printf("PCM loopback mode not specified.\n"); + return 1; + } + + if (strcmp(argv[0], "true") && strcmp(argv[0], "false")) { + printf("Invalid PCM mode '%s'.\n", argv[0]); + return 2; + } + + uint8_t packet[] = { 0x24, 0xFC, 0x01, 0x00 }; + if (argv[0][0] == 't') + packet[ARRAY_SIZE(packet) - 1] = 0x01; + + return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet)); +} + +int main(int argc, char **argv) { + if (argc < 2) { + usage(argv[0]); + return -1; + } + + const command_t *command = find_command(argv[1]); + if (!command) { + printf("Unrecognized command '%s'.\n", argv[1]); + return -2; + } + + if (!command->handler) { + printf("Unhandled command '%s'.\n", argv[1]); + return -3; + } + + return command->handler(argc - 2, &argv[2]); +} + +static bool write_hci_command(hci_packet_t type, const void *packet, size_t length) { + int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock == INVALID_FD) + goto error; + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(0x7F000001); + addr.sin_port = htons(8873); + if (connect(sock, (const struct sockaddr *)&addr, sizeof(addr)) == -1) + goto error; + + if (send(sock, &type, 1, 0) != 1) + goto error; + + if (send(sock, &length, 2, 0) != 2) + goto error; + + if (send(sock, packet, length, 0) != (ssize_t)length) + goto error; + + close(sock); + return true; + +error:; + close(sock); + return false; +} + +static const command_t *find_command(const char *name) { + for (size_t i = 0; i < ARRAY_SIZE(commands); ++i) + if (!strcmp(commands[i].name, name)) + return &commands[i]; + return NULL; +} + +static void usage(const char *name) { + printf("Usage: %s <command> [options]\n", name); + printf("Commands:\n"); + for (size_t i = 0; i < ARRAY_SIZE(commands); ++i) + printf(" %s\n", commands[i].name); + printf("For detailed help on a command, run '%s help <command>'.\n", name); +} |