Index: stable/6/usr.sbin/bluetooth/hccontrol/hccontrol.c =================================================================== --- stable/6/usr.sbin/bluetooth/hccontrol/hccontrol.c (revision 159387) +++ stable/6/usr.sbin/bluetooth/hccontrol/hccontrol.c (revision 159388) @@ -1,274 +1,322 @@ /* * hccontrol.c * * Copyright (c) 2001-2002 Maksim Yevmenkin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: hccontrol.c,v 1.5 2003/09/05 00:38:24 max Exp $ * $FreeBSD$ */ #include +#include #include #include #include #include +#include #include #include #include #include #include "hccontrol.h" /* Prototypes */ static int do_hci_command (char const *, int, char **); static struct hci_command * find_hci_command (char const *, struct hci_command *); +static int find_hci_nodes (struct nodeinfo **); static void print_hci_command (struct hci_command *); static void usage (void); /* Globals */ int verbose = 0; int timeout; int numeric_bdaddr = 0; /* Main */ int main(int argc, char *argv[]) { char *node = NULL; int n; /* Process command line arguments */ while ((n = getopt(argc, argv, "n:Nvh")) != -1) { switch (n) { case 'n': node = optarg; break; case 'N': numeric_bdaddr = 1; break; case 'v': verbose = 1; break; case 'h': default: usage(); } } argc -= optind; argv += optind; if (*argv == NULL) usage(); n = do_hci_command(node, argc, argv); return (n); } /* main */ /* Create socket and bind it */ static int socket_open(char const *node) { - struct sockaddr_hci addr; - struct ng_btsocket_hci_raw_filter filter; - int s, mib[4]; - size_t size; + struct sockaddr_hci addr; + struct ng_btsocket_hci_raw_filter filter; + int s, mib[4], num; + size_t size; + struct nodeinfo *nodes; - if (node == NULL) - usage(); + num = find_hci_nodes(&nodes); + if (num == 0) + errx(7, "Could not find HCI nodes"); + if (node == NULL) { + node = strdup(nodes[0].name); + if (num > 1) + fprintf(stdout, "Using HCI node: %s\n", node); + } + + free(nodes); + s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI); if (s < 0) err(1, "Could not create socket"); memset(&addr, 0, sizeof(addr)); addr.hci_len = sizeof(addr); addr.hci_family = AF_BLUETOOTH; strncpy(addr.hci_node, node, sizeof(addr.hci_node)); if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) err(2, "Could not bind socket, node=%s", node); if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) err(3, "Could not connect socket, node=%s", node); memset(&filter, 0, sizeof(filter)); bit_set(filter.event_mask, NG_HCI_EVENT_COMMAND_COMPL - 1); bit_set(filter.event_mask, NG_HCI_EVENT_COMMAND_STATUS - 1); bit_set(filter.event_mask, NG_HCI_EVENT_INQUIRY_COMPL - 1); bit_set(filter.event_mask, NG_HCI_EVENT_INQUIRY_RESULT - 1); bit_set(filter.event_mask, NG_HCI_EVENT_CON_COMPL - 1); bit_set(filter.event_mask, NG_HCI_EVENT_DISCON_COMPL - 1); bit_set(filter.event_mask, NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL - 1); bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL - 1); bit_set(filter.event_mask, NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL - 1); bit_set(filter.event_mask, NG_HCI_EVENT_RETURN_LINK_KEYS - 1); bit_set(filter.event_mask, NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL - 1); bit_set(filter.event_mask, NG_HCI_EVENT_CON_PKT_TYPE_CHANGED - 1); bit_set(filter.event_mask, NG_HCI_EVENT_ROLE_CHANGE - 1); if (setsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER, (void * const) &filter, sizeof(filter)) < 0) err(4, "Could not setsockopt()"); size = (sizeof(mib)/sizeof(mib[0])); if (sysctlnametomib("net.bluetooth.hci.command_timeout",mib,&size) < 0) err(5, "Could not sysctlnametomib()"); if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), (void *) &timeout, &size, NULL, 0) < 0) err(6, "Could not sysctl()"); timeout ++; return (s); } /* socket_open */ /* Execute commands */ static int do_hci_command(char const *node, int argc, char **argv) { char *cmd = argv[0]; struct hci_command *c = NULL; int s, e, help; help = 0; if (strcasecmp(cmd, "help") == 0) { argc --; argv ++; if (argc <= 0) { fprintf(stdout, "Supported commands:\n"); print_hci_command(link_control_commands); print_hci_command(link_policy_commands); print_hci_command(host_controller_baseband_commands); print_hci_command(info_commands); print_hci_command(status_commands); print_hci_command(node_commands); fprintf(stdout, "\nFor more information use " \ "'help command'\n"); return (OK); } help = 1; cmd = argv[0]; } c = find_hci_command(cmd, link_control_commands); if (c != NULL) goto execute; c = find_hci_command(cmd, link_policy_commands); if (c != NULL) goto execute; c = find_hci_command(cmd, host_controller_baseband_commands); if (c != NULL) goto execute; c = find_hci_command(cmd, info_commands); if (c != NULL) goto execute; c = find_hci_command(cmd, status_commands); if (c != NULL) goto execute; c = find_hci_command(cmd, node_commands); if (c == NULL) { fprintf(stdout, "Unknown command: \"%s\"\n", cmd); return (ERROR); } execute: if (!help) { s = socket_open(node); e = (c->handler)(s, -- argc, ++ argv); close(s); } else e = USAGE; switch (e) { case OK: case FAILED: break; case ERROR: fprintf(stdout, "Could not execute command \"%s\". %s\n", cmd, strerror(errno)); break; case USAGE: fprintf(stdout, "Usage: %s\n%s\n", c->command, c->description); break; default: assert(0); break; } return (e); } /* do_hci_command */ /* Try to find command in specified category */ static struct hci_command * find_hci_command(char const *command, struct hci_command *category) { struct hci_command *c = NULL; for (c = category; c->command != NULL; c++) { char *c_end = strchr(c->command, ' '); if (c_end != NULL) { int len = c_end - c->command; if (strncasecmp(command, c->command, len) == 0) return (c); } else if (strcasecmp(command, c->command) == 0) return (c); } return (NULL); } /* find_hci_command */ +/* Find all HCI nodes */ +static int +find_hci_nodes(struct nodeinfo** nodes) +{ + struct ng_btsocket_hci_raw_node_list_names r; + struct sockaddr_hci addr; + int s; + const char * node = "ubt0hci"; + + r.num_names = MAX_NODE_NUM; + r.names = (struct nodeinfo*)calloc(MAX_NODE_NUM, sizeof(struct nodeinfo)); + if (r.names == NULL) + err(8, "Could not allocate memory"); + + s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI); + if (s < 0) + err(9, "Could not create socket"); + + memset(&addr, 0, sizeof(addr)); + addr.hci_len = sizeof(addr); + addr.hci_family = AF_BLUETOOTH; + strncpy(addr.hci_node, node, sizeof(addr.hci_node)); + if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) + err(10, "Could not bind socket"); + + if (ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &r, sizeof(r)) < 0) + err(11, "Could not get list of HCI nodes"); + + close(s); + + *nodes = r.names; + + return (r.num_names); +} /* find_hci_nodes */ + /* Print commands in specified category */ static void print_hci_command(struct hci_command *category) { struct hci_command *c = NULL; for (c = category; c->command != NULL; c++) fprintf(stdout, "\t%s\n", c->command); } /* print_hci_command */ /* Usage */ static void usage(void) { - fprintf(stdout, "Usage: hccontrol -n HCI_node_name [-h] cmd [p1] [..]]\n"); + fprintf(stdout, "Usage: hccontrol [-hN] [-n HCI_node_name] cmd [p1] [..]\n"); exit(255); } /* usage */ Index: stable/6/usr.sbin/bluetooth/hccontrol/hccontrol.h =================================================================== --- stable/6/usr.sbin/bluetooth/hccontrol/hccontrol.h (revision 159387) +++ stable/6/usr.sbin/bluetooth/hccontrol/hccontrol.h (revision 159388) @@ -1,77 +1,79 @@ /* * hccontrol.h * * Copyright (c) 2001-2002 Maksim Yevmenkin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: hccontrol.h,v 1.2 2003/05/19 17:29:29 max Exp $ * $FreeBSD$ */ #ifndef _HCCONTROL_H_ #define _HCCONTROL_H_ #define OK 0 /* everything was OK */ #define ERROR 1 /* could not execute command */ #define FAILED 2 /* error was reported */ #define USAGE 3 /* invalid parameters */ +#define MAX_NODE_NUM 16 /* max number of nodes */ + struct hci_command { char const *command; char const *description; int (*handler)(int, int, char **); }; extern int timeout; extern int verbose; extern struct hci_command link_control_commands[]; extern struct hci_command link_policy_commands[]; extern struct hci_command host_controller_baseband_commands[]; extern struct hci_command info_commands[]; extern struct hci_command status_commands[]; extern struct hci_command node_commands[]; int hci_request (int, int, char const *, int, char *, int *); int hci_simple_request (int, int, char *, int *); int hci_send (int, char const *, int); int hci_recv (int, char *, int *); char const * const hci_link2str (int); char const * const hci_pin2str (int); char const * const hci_scan2str (int); char const * const hci_encrypt2str (int, int); char const * const hci_coding2str (int); char const * const hci_vdata2str (int); char const * const hci_hmode2str (int, char *, int); char const * const hci_ver2str (int); char const * const hci_lmpver2str (int); char const * const hci_manufacturer2str(int); char const * const hci_features2str (uint8_t *, char *, int); char const * const hci_cc2str (int); char const * const hci_con_state2str (int); char const * const hci_status2str (int); char const * const hci_bdaddr2str (bdaddr_t const *); #endif /* _HCCONTROL_H_ */ Index: stable/6/usr.sbin/bluetooth/hccontrol/node.c =================================================================== --- stable/6/usr.sbin/bluetooth/hccontrol/node.c (revision 159387) +++ stable/6/usr.sbin/bluetooth/hccontrol/node.c (revision 159388) @@ -1,573 +1,607 @@ /* * node.c * * Copyright (c) 2001-2002 Maksim Yevmenkin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: node.c,v 1.6 2003/07/22 21:14:02 max Exp $ * $FreeBSD$ */ #include #include #include +#include #include #include #include +#include #include "hccontrol.h" /* Send Read_Node_State command to the node */ static int hci_read_node_state(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_state r; memset(&r, 0, sizeof(r)); if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &r, sizeof(r)) < 0) return (ERROR); fprintf(stdout, "State: %#x\n", r.state); return (OK); } /* hci_read_node_state */ /* Send Intitialize command to the node */ static int hci_node_initialize(int s, int argc, char **argv) { if (ioctl(s, SIOC_HCI_RAW_NODE_INIT) < 0) return (ERROR); return (OK); } /* hci_node_initialize */ /* Send Read_Debug_Level command to the node */ static int hci_read_debug_level(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_debug r; memset(&r, 0, sizeof(r)); if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &r, sizeof(r)) < 0) return (ERROR); fprintf(stdout, "Debug level: %d\n", r.debug); return (OK); } /* hci_read_debug_level */ /* Send Write_Debug_Level command to the node */ static int hci_write_debug_level(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_debug r; memset(&r, 0, sizeof(r)); switch (argc) { case 1: r.debug = atoi(argv[0]); break; default: return (USAGE); } if (ioctl(s, SIOC_HCI_RAW_NODE_SET_DEBUG, &r, sizeof(r)) < 0) return (ERROR); return (OK); } /* hci_write_debug_level */ /* Send Read_Node_Buffer_Size command to the node */ static int hci_read_node_buffer_size(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_buffer r; memset(&r, 0, sizeof(r)); if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &r, sizeof(r)) < 0) return (ERROR); fprintf(stdout, "Number of free command buffers: %d\n", r.buffer.cmd_free); fprintf(stdout, "Max. ACL packet size: %d\n", r.buffer.acl_size); fprintf(stdout, "Numbef of free ACL buffers: %d\n", r.buffer.acl_free); fprintf(stdout, "Total number of ACL buffers: %d\n", r.buffer.acl_pkts); fprintf(stdout, "Max. SCO packet size: %d\n", r.buffer.sco_size); fprintf(stdout, "Numbef of free SCO buffers: %d\n", r.buffer.sco_free); fprintf(stdout, "Total number of SCO buffers: %d\n", r.buffer.sco_pkts); return (OK); } /* hci_read_node_buffer_size */ /* Send Read_Node_BD_ADDR command to the node */ static int hci_read_node_bd_addr(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_bdaddr r; memset(&r, 0, sizeof(r)); if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &r, sizeof(r)) < 0) return (ERROR); fprintf(stdout, "BD_ADDR: %s\n", bt_ntoa(&r.bdaddr, NULL)); return (OK); } /* hci_read_node_bd_addr */ /* Send Read_Node_Features command to the node */ static int hci_read_node_features(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_features r; int n; char buffer[1024]; memset(&r, 0, sizeof(r)); if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &r, sizeof(r)) < 0) return (ERROR); fprintf(stdout, "Features: "); for (n = 0; n < sizeof(r.features)/sizeof(r.features[0]); n++) fprintf(stdout, "%#02x ", r.features[n]); fprintf(stdout, "\n%s\n", hci_features2str(r.features, buffer, sizeof(buffer))); return (OK); } /* hci_read_node_features */ /* Send Read_Node_Stat command to the node */ static int hci_read_node_stat(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_stat r; memset(&r, 0, sizeof(r)); if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &r, sizeof(r)) < 0) return (ERROR); fprintf(stdout, "Commands sent: %d\n", r.stat.cmd_sent); fprintf(stdout, "Events received: %d\n", r.stat.evnt_recv); fprintf(stdout, "ACL packets received: %d\n", r.stat.acl_recv); fprintf(stdout, "ACL packets sent: %d\n", r.stat.acl_sent); fprintf(stdout, "SCO packets received: %d\n", r.stat.sco_recv); fprintf(stdout, "SCO packets sent: %d\n", r.stat.sco_sent); fprintf(stdout, "Bytes received: %d\n", r.stat.bytes_recv); fprintf(stdout, "Bytes sent: %d\n", r.stat.bytes_sent); return (OK); } /* hci_read_node_stat */ /* Send Reset_Node_Stat command to the node */ static int hci_reset_node_stat(int s, int argc, char **argv) { if (ioctl(s, SIOC_HCI_RAW_NODE_RESET_STAT) < 0) return (ERROR); return (OK); } /* hci_reset_node_stat */ /* Send Flush_Neighbor_Cache command to the node */ static int hci_flush_neighbor_cache(int s, int argc, char **argv) { if (ioctl(s, SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE) < 0) return (ERROR); return (OK); } /* hci_flush_neighbor_cache */ /* Send Read_Neighbor_Cache command to the node */ static int hci_read_neighbor_cache(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_neighbor_cache r; int n, error = OK; memset(&r, 0, sizeof(r)); r.num_entries = NG_HCI_MAX_NEIGHBOR_NUM; r.entries = calloc(NG_HCI_MAX_NEIGHBOR_NUM, sizeof(ng_hci_node_neighbor_cache_entry_ep)); if (r.entries == NULL) { errno = ENOMEM; return (ERROR); } if (ioctl(s, SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE, &r, sizeof(r)) < 0) { error = ERROR; goto out; } fprintf(stdout, "BD_ADDR " \ "Features " \ "Clock offset " \ "Page scan " \ "Rep. scan\n"); for (n = 0; n < r.num_entries; n++) { fprintf(stdout, "%-17.17s " \ "%02x %02x %02x %02x %02x %02x %02x %02x " \ "%#12x " \ "%#9x " \ "%#9x\n", hci_bdaddr2str(&r.entries[n].bdaddr), r.entries[n].features[0], r.entries[n].features[1], r.entries[n].features[2], r.entries[n].features[3], r.entries[n].features[4], r.entries[n].features[5], r.entries[n].features[6], r.entries[n].features[7], r.entries[n].clock_offset, r.entries[n].page_scan_mode, r.entries[n].page_scan_rep_mode); } out: free(r.entries); return (error); } /* hci_read_neightbor_cache */ /* Send Read_Connection_List command to the node */ static int hci_read_connection_list(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_con_list r; int n, error = OK; memset(&r, 0, sizeof(r)); r.num_connections = NG_HCI_MAX_CON_NUM; r.connections = calloc(NG_HCI_MAX_CON_NUM, sizeof(ng_hci_node_con_ep)); if (r.connections == NULL) { errno = ENOMEM; return (ERROR); } if (ioctl(s, SIOC_HCI_RAW_NODE_GET_CON_LIST, &r, sizeof(r)) < 0) { error = ERROR; goto out; } fprintf(stdout, "Remote BD_ADDR " \ "Handle " \ "Type " \ "Mode " \ "Role " \ "Encrypt " \ "Pending " \ "Queue " \ "State\n"); for (n = 0; n < r.num_connections; n++) { fprintf(stdout, "%-17.17s " \ "%6d " \ "%4.4s " \ "%4d " \ "%4.4s " \ "%7.7s " \ "%7d " \ "%5d " \ "%s\n", hci_bdaddr2str(&r.connections[n].bdaddr), r.connections[n].con_handle, (r.connections[n].link_type == NG_HCI_LINK_ACL)? "ACL" : "SCO", r.connections[n].mode, (r.connections[n].role == NG_HCI_ROLE_MASTER)? "MAST" : "SLAV", hci_encrypt2str(r.connections[n].encryption_mode, 1), r.connections[n].pending, r.connections[n].queue_len, hci_con_state2str(r.connections[n].state)); } out: free(r.connections); return (error); } /* hci_read_connection_list */ /* Send Read_Node_Link_Policy_Settings_Mask command to the node */ int hci_read_node_link_policy_settings_mask(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_link_policy_mask r; memset(&r, 0, sizeof(r)); if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK, &r, sizeof(r)) < 0) return (ERROR); fprintf(stdout, "Link Policy Settings mask: %#04x\n", r.policy_mask); return (OK); } /* hci_read_node_link_policy_settings_mask */ /* Send Write_Node_Link_Policy_Settings_Mask command to the node */ int hci_write_node_link_policy_settings_mask(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_link_policy_mask r; int m; memset(&r, 0, sizeof(r)); switch (argc) { case 1: if (sscanf(argv[0], "%x", &m) != 1) return (USAGE); r.policy_mask = (m & 0xffff); break; default: return (USAGE); } if (ioctl(s, SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK, &r, sizeof(r)) < 0) return (ERROR); return (OK); } /* hci_write_node_link_policy_settings_mask */ /* Send Read_Node_Packet_Mask command to the node */ int hci_read_node_packet_mask(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_packet_mask r; memset(&r, 0, sizeof(r)); if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK, &r, sizeof(r)) < 0) return (ERROR); fprintf(stdout, "Packet mask: %#04x\n", r.packet_mask); return (OK); } /* hci_read_node_packet_mask */ /* Send Write_Node_Packet_Mask command to the node */ int hci_write_node_packet_mask(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_packet_mask r; int m; memset(&r, 0, sizeof(r)); switch (argc) { case 1: if (sscanf(argv[0], "%x", &m) != 1) return (USAGE); r.packet_mask = (m & 0xffff); break; default: return (USAGE); } if (ioctl(s, SIOC_HCI_RAW_NODE_SET_PACKET_MASK, &r, sizeof(r)) < 0) return (ERROR); return (OK); } /* hci_write_node_packet_mask */ /* Send Read_Node_Role_Switch command to the node */ int hci_read_node_role_switch(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_role_switch r; memset(&r, 0, sizeof(r)); if (ioctl(s, SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH, &r, sizeof(r)) < 0) return (ERROR); fprintf(stdout, "Role switch: %d\n", r.role_switch); return (OK); } /* hci_read_node_role_switch */ /* Send Write_Node_Role_Switch command to the node */ int hci_write_node_role_switch(int s, int argc, char **argv) { struct ng_btsocket_hci_raw_node_role_switch r; int m; memset(&r, 0, sizeof(r)); switch (argc) { case 1: if (sscanf(argv[0], "%d", &m) != 1) return (USAGE); r.role_switch = m? 1 : 0; break; default: return (USAGE); } if (ioctl(s, SIOC_HCI_RAW_NODE_SET_ROLE_SWITCH, &r, sizeof(r)) < 0) return (ERROR); return (OK); } /* hci_write_node_role_switch */ +/* Send Read_Node_List command to the node */ +int +hci_read_node_list(int s, int argc, char **argv) +{ + struct ng_btsocket_hci_raw_node_list_names r; + int i; + + r.num_names = MAX_NODE_NUM; + r.names = (struct nodeinfo*)calloc(MAX_NODE_NUM, sizeof(struct nodeinfo)); + if (r.names == NULL) + return (ERROR); + + if (ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &r, sizeof(r)) < 0) { + free(r.names); + return (ERROR); + } + + fprintf(stdout, "Name ID Num hooks\n"); + for (i = 0; i < r.num_names; ++i) + fprintf(stdout, "%-15s %08x %9d\n", + r.names[i].name, r.names[i].id, r.names[i].hooks); + + free(r.names); + + return (OK); +} /* hci_read_node_list */ + struct hci_command node_commands[] = { { "read_node_state", "Get the HCI node state", &hci_read_node_state }, { "initialize", "Initialize the HCI node", &hci_node_initialize }, { "read_debug_level", "Read the HCI node debug level", &hci_read_debug_level }, { "write_debug_level ", "Write the HCI node debug level", &hci_write_debug_level }, { "read_node_buffer_size", "Read the HCI node buffer information. This will return current state of the\n"\ "HCI buffer for the HCI node", &hci_read_node_buffer_size }, { "read_node_bd_addr", "Read the HCI node BD_ADDR. Returns device BD_ADDR as cached by the HCI node", &hci_read_node_bd_addr }, { "read_node_features", "Read the HCI node features. This will return list of supported features as\n" \ "cached by the HCI node", &hci_read_node_features }, { "read_node_stat", "Read packets and bytes counters for the HCI node", &hci_read_node_stat }, { "reset_node_stat", "Reset packets and bytes counters for the HCI node", &hci_reset_node_stat }, { "flush_neighbor_cache", "Flush content of the HCI node neighbor cache", &hci_flush_neighbor_cache }, { "read_neighbor_cache", "Read content of the HCI node neighbor cache", &hci_read_neighbor_cache }, { "read_connection_list", "Read the baseband connection descriptors list for the HCI node", &hci_read_connection_list }, { "read_node_link_policy_settings_mask", "Read the value of the Link Policy Settinngs mask for the HCI node", &hci_read_node_link_policy_settings_mask }, { "write_node_link_policy_settings_mask ", "Write the value of the Link Policy Settings mask for the HCI node. By default\n" \ "all supported Link Policy modes (as reported by the local device features) are\n"\ "enabled. The particular Link Policy mode is enabled if local device supports\n"\ "it and correspinding bit in the mask was set\n\n" \ "\t - xxxx; Link Policy mask\n" \ "\t\t0x0000 - Disable All LM Modes\n" \ "\t\t0x0001 - Enable Master Slave Switch\n" \ "\t\t0x0002 - Enable Hold Mode\n" \ "\t\t0x0004 - Enable Sniff Mode\n" \ "\t\t0x0008 - Enable Park Mode\n", &hci_write_node_link_policy_settings_mask }, { "read_node_packet_mask", "Read the value of the Packet mask for the HCI node", &hci_read_node_packet_mask }, { "write_node_packet_mask ", "Write the value of the Packet mask for the HCI node. By default all supported\n" \ "packet types (as reported by the local device features) are enabled. The\n" \ "particular packet type is enabled if local device supports it and corresponding\n" \ "bit in the mask was set\n\n" \ "\t - xxxx; packet type mask\n" \ "" \ "\t\tACL packets\n" \ "\t\t-----------\n" \ "\t\t0x0008 DM1\n" \ "\t\t0x0010 DH1\n" \ "\t\t0x0400 DM3\n" \ "\t\t0x0800 DH3\n" \ "\t\t0x4000 DM5\n" \ "\t\t0x8000 DH5\n" \ "\n" \ "\t\tSCO packets\n" \ "\t\t-----------\n" \ "\t\t0x0020 HV1\n" \ "\t\t0x0040 HV2\n" \ "\t\t0x0080 HV3\n", &hci_write_node_packet_mask }, { "read_node_role_switch", "Read the value of the Role Switch parameter for the HCI node", &hci_read_node_role_switch }, { "write_node_role_switch {0|1}", "Write the value of the Role Switch parameter for the HCI node. By default,\n" \ "if Role Switch is supported, local device will try to perform Role Switch\n" \ "and become Master on incoming connection. Some devices do not support Role\n" \ "Switch and thus incomming connections from such devices will fail. Setting\n" \ "this parameter to zero will prevent Role Switch and thus accepting device\n" \ "will remain Slave", &hci_write_node_role_switch +}, +{ +"read_node_list", +"Get a list of HCI nodes, their Netgraph IDs and connected hooks.", +&hci_read_node_list }, { NULL, }};