Path: blob/main/usr.sbin/bluetooth/hccontrol/hccontrol.c
107110 views
/*-1* hccontrol.c2*3* SPDX-License-Identifier: BSD-2-Clause4*5* Copyright (c) 2001-2002 Maksim Yevmenkin <[email protected]>6* All rights reserved.7*8* Redistribution and use in source and binary forms, with or without9* modification, are permitted provided that the following conditions10* are met:11* 1. Redistributions of source code must retain the above copyright12* notice, this list of conditions and the following disclaimer.13* 2. Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in the15* documentation and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND18* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE19* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE20* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE21* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL22* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS23* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)24* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT25* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY26* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF27* SUCH DAMAGE.28*29* $Id: hccontrol.c,v 1.5 2003/09/05 00:38:24 max Exp $30*/3132#define L2CAP_SOCKET_CHECKED33#include <bluetooth.h>34#include <sys/ioctl.h>35#include <sys/param.h>36#include <sys/sysctl.h>37#include <assert.h>38#include <err.h>39#include <errno.h>40#include <netgraph/ng_message.h>41#include <stdio.h>42#include <stdlib.h>43#include <string.h>44#include <unistd.h>45#include "hccontrol.h"4647/* Prototypes */48static int do_hci_command (char const *, int, char **);49static struct hci_command * find_hci_command (char const *, struct hci_command *);50static int find_hci_nodes (struct nodeinfo **);51static void print_hci_command (struct hci_command *);52static void usage (void);5354/* Globals */55int verbose = 0;56int timeout;57int numeric_bdaddr = 0;5859/* Main */60int61main(int argc, char *argv[])62{63char *node = NULL;64int n;6566/* Process command line arguments */67while ((n = getopt(argc, argv, "n:Nvh")) != -1) {68switch (n) {69case 'n':70node = optarg;71break;7273case 'N':74numeric_bdaddr = 1;75break;7677case 'v':78verbose = 1;79break;8081case 'h':82default:83usage();84}85}8687argc -= optind;88argv += optind;8990if (*argv == NULL)91usage();9293n = do_hci_command(node, argc, argv);9495return (n);96} /* main */9798/* Create socket and bind it */99static int100socket_open(char const *node)101{102struct sockaddr_hci addr;103struct ng_btsocket_hci_raw_filter filter;104int s, mib[4], num;105size_t size;106struct nodeinfo *nodes;107char *lnode = NULL;108109num = find_hci_nodes(&nodes);110if (num == 0)111errx(7, "Could not find HCI nodes");112113if (node == NULL) {114node = lnode = strdup(nodes[0].name);115if (num > 1)116fprintf(stdout, "Using HCI node: %s\n", node);117}118119free(nodes);120121s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);122if (s < 0)123err(1, "Could not create socket");124125memset(&addr, 0, sizeof(addr));126addr.hci_len = sizeof(addr);127addr.hci_family = AF_BLUETOOTH;128strncpy(addr.hci_node, node, sizeof(addr.hci_node));129if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)130err(2, "Could not bind socket, node=%s", node);131132if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)133err(3, "Could not connect socket, node=%s", node);134135free(lnode);136memset(&filter, 0, sizeof(filter));137bit_set(filter.event_mask, NG_HCI_EVENT_COMMAND_COMPL - 1);138bit_set(filter.event_mask, NG_HCI_EVENT_COMMAND_STATUS - 1);139bit_set(filter.event_mask, NG_HCI_EVENT_INQUIRY_COMPL - 1);140bit_set(filter.event_mask, NG_HCI_EVENT_INQUIRY_RESULT - 1);141bit_set(filter.event_mask, NG_HCI_EVENT_CON_COMPL - 1);142bit_set(filter.event_mask, NG_HCI_EVENT_DISCON_COMPL - 1);143bit_set(filter.event_mask, NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL - 1);144bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL - 1);145bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL - 1);146bit_set(filter.event_mask, NG_HCI_EVENT_RETURN_LINK_KEYS - 1);147bit_set(filter.event_mask, NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL - 1);148bit_set(filter.event_mask, NG_HCI_EVENT_CON_PKT_TYPE_CHANGED - 1);149bit_set(filter.event_mask, NG_HCI_EVENT_ROLE_CHANGE - 1);150bit_set(filter.event_mask, NG_HCI_EVENT_LE -1);151152if (setsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER,153(void * const) &filter, sizeof(filter)) < 0)154err(4, "Could not setsockopt()");155156size = nitems(mib);157if (sysctlnametomib("net.bluetooth.hci.command_timeout",mib,&size) < 0)158err(5, "Could not sysctlnametomib()");159160if (sysctl(mib, nitems(mib),161(void *) &timeout, &size, NULL, 0) < 0)162err(6, "Could not sysctl()");163164timeout ++;165166return (s);167} /* socket_open */168169/* Execute commands */170static int171do_hci_command(char const *node, int argc, char **argv)172{173char *cmd = argv[0];174struct hci_command *c = NULL;175int s, e, help;176177help = 0;178if (strcasecmp(cmd, "help") == 0) {179argc --;180argv ++;181182if (argc <= 0) {183fprintf(stdout, "Supported commands:\n");184print_hci_command(link_control_commands);185print_hci_command(link_policy_commands);186print_hci_command(host_controller_baseband_commands);187print_hci_command(info_commands);188print_hci_command(status_commands);189print_hci_command(le_commands);190print_hci_command(node_commands);191fprintf(stdout, "\nFor more information use " \192"'help command'\n");193194return (OK);195}196197help = 1;198cmd = argv[0];199}200201c = find_hci_command(cmd, link_control_commands);202if (c != NULL)203goto execute;204205c = find_hci_command(cmd, link_policy_commands);206if (c != NULL)207goto execute;208209c = find_hci_command(cmd, host_controller_baseband_commands);210if (c != NULL)211goto execute;212213c = find_hci_command(cmd, info_commands);214if (c != NULL)215goto execute;216217c = find_hci_command(cmd, status_commands);218if (c != NULL)219goto execute;220221c = find_hci_command(cmd, le_commands);222if (c != NULL)223goto execute;224225226c = find_hci_command(cmd, node_commands);227if (c == NULL) {228fprintf(stdout, "Unknown command: \"%s\"\n", cmd);229return (ERROR);230}231execute:232if (!help) {233s = socket_open(node);234e = (c->handler)(s, -- argc, ++ argv);235close(s);236} else237e = USAGE;238239switch (e) {240case OK:241case FAILED:242break;243244case ERROR:245fprintf(stdout, "Could not execute command \"%s\". %s\n",246cmd, strerror(errno));247break;248249case USAGE:250fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description);251break;252253default: assert(0); break;254}255256257return (e);258} /* do_hci_command */259260/* Try to find command in specified category */261static struct hci_command *262find_hci_command(char const *command, struct hci_command *category)263{264struct hci_command *c = NULL;265266for (c = category; c->command != NULL; c++) {267char *c_end = strchr(c->command, ' ');268269if (c_end != NULL) {270int len = c_end - c->command;271272if (strncasecmp(command, c->command, len) == 0)273return (c);274} else if (strcasecmp(command, c->command) == 0)275return (c);276}277278return (NULL);279} /* find_hci_command */280281/* Find all HCI nodes */282static int283find_hci_nodes(struct nodeinfo** nodes)284{285struct ng_btsocket_hci_raw_node_list_names r;286struct sockaddr_hci addr;287int s;288const char * node = "ubt0hci";289290r.num_names = MAX_NODE_NUM;291r.names = (struct nodeinfo*)calloc(MAX_NODE_NUM, sizeof(struct nodeinfo));292if (r.names == NULL)293err(8, "Could not allocate memory");294295s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);296if (s < 0)297err(9, "Could not create socket");298299memset(&addr, 0, sizeof(addr));300addr.hci_len = sizeof(addr);301addr.hci_family = AF_BLUETOOTH;302strncpy(addr.hci_node, node, sizeof(addr.hci_node));303if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)304err(10, "Could not bind socket");305306if (ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &r, sizeof(r)) < 0)307err(11, "Could not get list of HCI nodes");308309close(s);310311*nodes = r.names;312313return (r.num_names);314} /* find_hci_nodes */315316/* Print commands in specified category */317static void318print_hci_command(struct hci_command *category)319{320struct hci_command *c = NULL;321322for (c = category; c->command != NULL; c++)323fprintf(stdout, "\t%s\n", c->command);324} /* print_hci_command */325326/* Usage */327static void328usage(void)329{330fprintf(stdout, "Usage: hccontrol [-hN] [-n HCI_node_name] cmd [p1] [..]\n");331exit(255);332} /* usage */333334335336