11f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <hardware/bluetooth.h> 21f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <netinet/in.h> 31f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <stdio.h> 41f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <string.h> 51f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <sys/socket.h> 61f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <sys/types.h> 71f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <unistd.h> 81f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 90f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/osi.h" 101f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 111f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatitypedef int (*handler_t)(int argc, char **argv); 121f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 131f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatitypedef enum { 141f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati HCI_PACKET_COMMAND = 1, 151f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati HCI_PACKET_ACL_DATA = 2, 161f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati HCI_PACKET_SCO_DATA = 3, 171f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati HCI_PACKET_EVENT = 4, 181f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} hci_packet_t; 191f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 201f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatitypedef struct { 211f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati const char *name; 221f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati const char *help; 231f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati handler_t handler; 241f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} command_t; 251f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 261f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic int help(int argc, char **argv); 2752743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavatistatic int set_discoverable(int argc, char **argv); 281f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic int set_name(int argc, char **argv); 291f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic int set_pcm_loopback(int argc, char **argv); 301f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 311f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic bool write_hci_command(hci_packet_t type, const void *packet, size_t length); 321f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic const command_t *find_command(const char *name); 331f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic void usage(const char *name); 341f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 351f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic const command_t commands[] = { 361f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati { "help", "<command> - shows help text for <command>.", help }, 3752743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati { "setDiscoverable", "(true|false) - whether the controller should be discoverable.", set_discoverable }, 381f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati { "setName", "<name> - sets the device's Bluetooth name to <name>.", set_name }, 391f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati { "setPcmLoopback", "(true|false) - enables or disables PCM loopback on the controller.", set_pcm_loopback }, 401f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati}; 411f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 421f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic int help(int argc, char **argv) { 431f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (!argc) { 441f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("No help command specified.\n"); 451f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 1; 461f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 471f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 481f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati const command_t *command = find_command(argv[0]); 491f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (!command) { 501f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("No command named '%s'.\n", argv[0]); 511f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 2; 521f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 531f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 541f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("%s %s\n", argv[0], command->help); 551f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 0; 561f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 571f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 5852743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavatistatic int set_discoverable(int argc, char **argv) { 5952743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati if (argc != 1) { 6052743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati printf("Discoverable mode not specified.\n"); 6152743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati return 1; 6252743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati } 6352743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati 6452743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati if (strcmp(argv[0], "true") && strcmp(argv[0], "false")) { 6552743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati printf("Invalid discoverable mode '%s'.\n", argv[0]); 6652743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati return 2; 6752743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati } 6852743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati 6952743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati uint8_t packet[] = { 0x1A, 0x0C, 0x01, 0x00 }; 7052743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati if (argv[0][0] == 't') 7152743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati packet[ARRAY_SIZE(packet) - 1] = 0x03; 7252743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati 7352743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet)); 7452743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati} 7552743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati 761f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic int set_name(int argc, char **argv) { 771f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (argc != 1) { 781f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Device name not specified.\n"); 791f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 1; 801f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 811f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 821f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati size_t len = strlen(argv[0]); 831f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (len > 247) { 841f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Device name cannot exceed 247 bytes.\n"); 851f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 2; 861f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 871f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 881f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati uint8_t packet[251] = { 0x13, 0x0C, 248 }; 891f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati memcpy(&packet[3], argv[0], len + 1); 901f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 911f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (!write_hci_command(HCI_PACKET_COMMAND, packet, sizeof(packet))) 921f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 1; 931f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 941f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati memset(&packet[0], sizeof(packet), 0); 951f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[0] = 0x52; 961f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[1] = 0x0C; 971f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[2] = 0xF1; // HCI command packet length. 981f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[3] = 0x01; // FEC required. 991f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[4] = len + 1; 1001f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[5] = 0x09; // Device name field tag. 1011f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati memcpy(&packet[6], argv[0], len); 1021f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return !write_hci_command(HCI_PACKET_COMMAND, packet, 0xF4); 1031f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 1041f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1051f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic int set_pcm_loopback(int argc, char **argv) { 1061f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (argc != 1) { 1071f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("PCM loopback mode not specified.\n"); 1081f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 1; 1091f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 1101f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1111f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (strcmp(argv[0], "true") && strcmp(argv[0], "false")) { 1121f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Invalid PCM mode '%s'.\n", argv[0]); 1131f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 2; 1141f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 1151f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1161f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati uint8_t packet[] = { 0x24, 0xFC, 0x01, 0x00 }; 1171f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (argv[0][0] == 't') 1181f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[ARRAY_SIZE(packet) - 1] = 0x01; 1191f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1201f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet)); 1211f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 1221f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1231f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatiint main(int argc, char **argv) { 1241f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (argc < 2) { 1251f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati usage(argv[0]); 1261f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return -1; 1271f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 1281f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1291f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati const command_t *command = find_command(argv[1]); 1301f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (!command) { 1311f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Unrecognized command '%s'.\n", argv[1]); 1321f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return -2; 1331f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 1341f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1351f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (!command->handler) { 1361f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Unhandled command '%s'.\n", argv[1]); 1371f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return -3; 1381f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 1391f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1401f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return command->handler(argc - 2, &argv[2]); 1411f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 1421f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1431f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic bool write_hci_command(hci_packet_t type, const void *packet, size_t length) { 1441f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 1451f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (sock == INVALID_FD) 1461f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati goto error; 1471f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1481f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati struct sockaddr_in addr; 1491f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati addr.sin_family = AF_INET; 1501f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati addr.sin_addr.s_addr = htonl(0x7F000001); 1511f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati addr.sin_port = htons(8873); 1521f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (connect(sock, (const struct sockaddr *)&addr, sizeof(addr)) == -1) 1531f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati goto error; 1541f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1551f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (send(sock, &type, 1, 0) != 1) 1561f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati goto error; 1571f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1581f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (send(sock, &length, 2, 0) != 2) 1591f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati goto error; 1601f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1611f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (send(sock, packet, length, 0) != (ssize_t)length) 1621f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati goto error; 1631f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1641f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati close(sock); 1651f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return true; 1661f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1671f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatierror:; 1681f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati close(sock); 1691f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return false; 1701f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 1711f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1721f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic const command_t *find_command(const char *name) { 1731f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati for (size_t i = 0; i < ARRAY_SIZE(commands); ++i) 1741f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (!strcmp(commands[i].name, name)) 1751f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return &commands[i]; 1761f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return NULL; 1771f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 1781f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1791f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic void usage(const char *name) { 1801f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Usage: %s <command> [options]\n", name); 1811f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Commands:\n"); 1821f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati for (size_t i = 0; i < ARRAY_SIZE(commands); ++i) 1831f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf(" %s\n", commands[i].name); 1841f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("For detailed help on a command, run '%s help <command>'.\n", name); 1851f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 186