1107120Sjulian/* 2107120Sjulian * link_policy.c 3107120Sjulian * 4107120Sjulian * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5107120Sjulian * All rights reserved. 6107120Sjulian * 7107120Sjulian * Redistribution and use in source and binary forms, with or without 8107120Sjulian * modification, are permitted provided that the following conditions 9107120Sjulian * are met: 10107120Sjulian * 1. Redistributions of source code must retain the above copyright 11107120Sjulian * notice, this list of conditions and the following disclaimer. 12107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright 13107120Sjulian * notice, this list of conditions and the following disclaimer in the 14107120Sjulian * documentation and/or other materials provided with the distribution. 15107120Sjulian * 16107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26107120Sjulian * SUCH DAMAGE. 27107120Sjulian * 28121054Semax * $Id: link_policy.c,v 1.3 2003/08/18 19:19:54 max Exp $ 29107120Sjulian * $FreeBSD$ 30107120Sjulian */ 31107120Sjulian 32121054Semax#include <bluetooth.h> 33107120Sjulian#include <errno.h> 34107120Sjulian#include <stdio.h> 35121054Semax#include <string.h> 36107120Sjulian#include "hccontrol.h" 37107120Sjulian 38107120Sjulian/* Send Role Discovery to the unit */ 39107120Sjulianstatic int 40107120Sjulianhci_role_discovery(int s, int argc, char **argv) 41107120Sjulian{ 42107120Sjulian ng_hci_role_discovery_cp cp; 43107120Sjulian ng_hci_role_discovery_rp rp; 44107120Sjulian int n; 45107120Sjulian 46107120Sjulian /* parse command parameters */ 47107120Sjulian switch (argc) { 48107120Sjulian case 1: 49107120Sjulian /* connection handle */ 50107120Sjulian if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) 51107120Sjulian return (USAGE); 52107120Sjulian 53128079Semax cp.con_handle = (uint16_t) (n & 0x0fff); 54107120Sjulian cp.con_handle = htole16(cp.con_handle); 55107120Sjulian break; 56107120Sjulian 57107120Sjulian default: 58107120Sjulian return (USAGE); 59107120Sjulian } 60107120Sjulian 61107120Sjulian /* send request */ 62107120Sjulian n = sizeof(rp); 63107120Sjulian if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 64107120Sjulian NG_HCI_OCF_ROLE_DISCOVERY), 65107120Sjulian (char const *) &cp, sizeof(cp), 66107120Sjulian (char *) &rp, &n) == ERROR) 67107120Sjulian return (ERROR); 68107120Sjulian 69107120Sjulian if (rp.status != 0x00) { 70107120Sjulian fprintf(stdout, "Status: %s [%#02x]\n", 71107120Sjulian hci_status2str(rp.status), rp.status); 72107120Sjulian return (FAILED); 73107120Sjulian } 74107120Sjulian 75107120Sjulian fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle)); 76107120Sjulian fprintf(stdout, "Role: %s [%#x]\n", 77107120Sjulian (rp.role == NG_HCI_ROLE_MASTER)? "Master" : "Slave", rp.role); 78107120Sjulian 79107120Sjulian return (OK); 80107120Sjulian} /* hci_role_discovery */ 81107120Sjulian 82107120Sjulian/* Send Swith Role to the unit */ 83107120Sjulianstatic int 84107120Sjulianhci_switch_role(int s, int argc, char **argv) 85107120Sjulian{ 86121054Semax int n0; 87107120Sjulian char b[512]; 88107120Sjulian ng_hci_switch_role_cp cp; 89107120Sjulian ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 90107120Sjulian 91107120Sjulian /* parse command parameters */ 92107120Sjulian switch (argc) { 93107120Sjulian case 2: 94107120Sjulian /* bdaddr */ 95121054Semax if (!bt_aton(argv[0], &cp.bdaddr)) { 96121054Semax struct hostent *he = NULL; 97107120Sjulian 98121054Semax if ((he = bt_gethostbyname(argv[0])) == NULL) 99121054Semax return (USAGE); 100107120Sjulian 101121054Semax memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr)); 102121054Semax } 103121054Semax 104107120Sjulian /* role */ 105107120Sjulian if (sscanf(argv[1], "%d", &n0) != 1) 106107120Sjulian return (USAGE); 107107120Sjulian 108107120Sjulian cp.role = n0? NG_HCI_ROLE_SLAVE : NG_HCI_ROLE_MASTER; 109107120Sjulian break; 110107120Sjulian 111107120Sjulian default: 112107120Sjulian return (USAGE); 113107120Sjulian } 114107120Sjulian 115107120Sjulian /* send request and expect status response */ 116107120Sjulian n0 = sizeof(b); 117107120Sjulian if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 118107120Sjulian NG_HCI_OCF_SWITCH_ROLE), 119107120Sjulian (char const *) &cp, sizeof(cp), b, &n0) == ERROR) 120107120Sjulian return (ERROR); 121107120Sjulian 122107120Sjulian if (*b != 0x00) 123107120Sjulian return (FAILED); 124107120Sjulian 125107120Sjulian /* wait for event */ 126107120Sjulianagain: 127107120Sjulian n0 = sizeof(b); 128107120Sjulian if (hci_recv(s, b, &n0) == ERROR) 129107120Sjulian return (ERROR); 130107120Sjulian if (n0 < sizeof(*e)) { 131107120Sjulian errno = EIO; 132107120Sjulian return (ERROR); 133107120Sjulian } 134107120Sjulian 135107120Sjulian if (e->event == NG_HCI_EVENT_ROLE_CHANGE) { 136107120Sjulian ng_hci_role_change_ep *ep = (ng_hci_role_change_ep *)(e + 1); 137107120Sjulian 138107120Sjulian if (ep->status != 0x00) { 139107120Sjulian fprintf(stdout, "Status: %s [%#02x]\n", 140107120Sjulian hci_status2str(ep->status), ep->status); 141107120Sjulian return (FAILED); 142107120Sjulian } 143107120Sjulian 144121054Semax fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr)); 145107120Sjulian fprintf(stdout, "Role: %s [%#x]\n", 146107120Sjulian (ep->role == NG_HCI_ROLE_MASTER)? "Master" : "Slave", 147107120Sjulian ep->role); 148107120Sjulian } else 149107120Sjulian goto again; 150107120Sjulian 151107120Sjulian return (OK); 152107120Sjulian} /* hci_switch_role */ 153107120Sjulian 154107120Sjulian/* Send Read_Link_Policy_Settings command to the unit */ 155107120Sjulianstatic int 156107120Sjulianhci_read_link_policy_settings(int s, int argc, char **argv) 157107120Sjulian{ 158107120Sjulian ng_hci_read_link_policy_settings_cp cp; 159107120Sjulian ng_hci_read_link_policy_settings_rp rp; 160107120Sjulian int n; 161107120Sjulian 162107120Sjulian /* parse command parameters */ 163107120Sjulian switch (argc) { 164107120Sjulian case 1: 165107120Sjulian /* connection handle */ 166107120Sjulian if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) 167107120Sjulian return (USAGE); 168107120Sjulian 169128079Semax cp.con_handle = (uint16_t) (n & 0x0fff); 170107120Sjulian cp.con_handle = htole16(cp.con_handle); 171107120Sjulian break; 172107120Sjulian 173107120Sjulian default: 174107120Sjulian return (USAGE); 175107120Sjulian } 176107120Sjulian 177107120Sjulian /* send request */ 178107120Sjulian n = sizeof(rp); 179107120Sjulian if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 180107120Sjulian NG_HCI_OCF_READ_LINK_POLICY_SETTINGS), 181107120Sjulian (char const *) &cp, sizeof(cp), 182107120Sjulian (char *) &rp, &n) == ERROR) 183107120Sjulian return (ERROR); 184107120Sjulian 185107120Sjulian if (rp.status != 0x00) { 186107120Sjulian fprintf(stdout, "Status: %s [%#02x]\n", 187107120Sjulian hci_status2str(rp.status), rp.status); 188107120Sjulian return (FAILED); 189107120Sjulian } 190107120Sjulian 191107120Sjulian fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle)); 192107120Sjulian fprintf(stdout, "Link policy settings: %#x\n", le16toh(rp.settings)); 193107120Sjulian 194107120Sjulian return (OK); 195107120Sjulian} /* hci_read_link_policy_settings */ 196107120Sjulian 197107120Sjulian/* Send Write_Link_Policy_Settings command to the unit */ 198107120Sjulianstatic int 199107120Sjulianhci_write_link_policy_settings(int s, int argc, char **argv) 200107120Sjulian{ 201107120Sjulian ng_hci_write_link_policy_settings_cp cp; 202107120Sjulian ng_hci_write_link_policy_settings_rp rp; 203107120Sjulian int n; 204107120Sjulian 205107120Sjulian /* parse command parameters */ 206107120Sjulian switch (argc) { 207107120Sjulian case 2: 208107120Sjulian /* connection handle */ 209107120Sjulian if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) 210107120Sjulian return (USAGE); 211107120Sjulian 212128079Semax cp.con_handle = (uint16_t) (n & 0x0fff); 213107120Sjulian cp.con_handle = htole16(cp.con_handle); 214107120Sjulian 215107120Sjulian /* link policy settings */ 216107120Sjulian if (sscanf(argv[1], "%x", &n) != 1) 217107120Sjulian return (USAGE); 218107120Sjulian 219128079Semax cp.settings = (uint16_t) (n & 0x0ffff); 220107120Sjulian cp.settings = htole16(cp.settings); 221107120Sjulian break; 222107120Sjulian 223107120Sjulian default: 224107120Sjulian return (USAGE); 225107120Sjulian } 226107120Sjulian 227107120Sjulian /* send request */ 228107120Sjulian n = sizeof(rp); 229107120Sjulian if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 230107120Sjulian NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS), 231107120Sjulian (char const *) &cp, sizeof(cp), 232107120Sjulian (char *) &rp, &n) == ERROR) 233107120Sjulian return (ERROR); 234107120Sjulian 235107120Sjulian if (rp.status != 0x00) { 236107120Sjulian fprintf(stdout, "Status: %s [%#02x]\n", 237107120Sjulian hci_status2str(rp.status), rp.status); 238107120Sjulian return (FAILED); 239107120Sjulian } 240107120Sjulian 241107120Sjulian return (OK); 242107120Sjulian} /* hci_write_link_policy_settings */ 243107120Sjulian 244107120Sjulianstruct hci_command link_policy_commands[] = { 245107120Sjulian{ 246122451Semax"role_discovery <connection_handle>", 247107120Sjulian"\nThe Role_Discovery command is used for a Bluetooth device to determine\n" \ 248107120Sjulian"which role the device is performing for a particular Connection Handle.\n" \ 249107120Sjulian"The connection handle must be a connection handle for an ACL connection.\n\n" \ 250107120Sjulian"\t<connection_handle> - dddd; connection handle", 251107120Sjulian&hci_role_discovery 252107120Sjulian}, 253107120Sjulian{ 254133178Semax"switch_role <BD_ADDR> <role>", 255107120Sjulian"\nThe Switch_Role command is used for a Bluetooth device to switch the\n" \ 256107120Sjulian"current role the device is performing for a particular connection with\n" \ 257107120Sjulian"another specified Bluetooth device. The BD_ADDR command parameter indicates\n"\ 258107120Sjulian"for which connection the role switch is to be performed. The Role indicates\n"\ 259107120Sjulian"the requested new role that the local device performs. Note: the BD_ADDR\n" \ 260107120Sjulian"command parameter must specify a Bluetooth device for which a connection\n" 261107120Sjulian"already exists.\n\n" \ 262133178Semax"\t<BD_ADDR> - xx:xx:xx:xx:xx:xx BD_ADDR or name\n" \ 263133178Semax"\t<role> - dd; role; 0 - Master, 1 - Slave", 264107120Sjulian&hci_switch_role 265107120Sjulian}, 266107120Sjulian{ 267107120Sjulian"read_link_policy_settings <connection_handle>", 268107120Sjulian"\nThis command will read the Link Policy setting for the specified connection\n"\ 269107120Sjulian"handle. The link policy settings parameter determines the behavior of the\n" \ 270107120Sjulian"local Link Manager when it receives a request from a remote device or it\n" \ 271107120Sjulian"determines itself to change the master-slave role or to enter the hold,\n" \ 272107120Sjulian"sniff, or park mode. The local Link Manager will automatically accept or\n" \ 273107120Sjulian"reject such a request from the remote device, and may even autonomously\n" \ 274107120Sjulian"request itself, depending on the value of the link policy settings parameter\n"\ 275107120Sjulian"for the corresponding connection handle. The connection handle must be a\n" \ 276107120Sjulian"connection handle for an ACL connection.\n\n" \ 277107120Sjulian"\t<connection_handle> - dddd; connection handle", 278107120Sjulian&hci_read_link_policy_settings 279107120Sjulian}, 280107120Sjulian{ 281107120Sjulian"write_link_policy_settings <connection_handle> <settings>", 282107120Sjulian"\nThis command will write the Link Policy setting for the specified connection\n"\ 283107120Sjulian"handle. The link policy settings parameter determines the behavior of the\n" \ 284107120Sjulian"local Link Manager when it receives a request from a remote device or it\n" \ 285107120Sjulian"determines itself to change the master-slave role or to enter the hold,\n" \ 286107120Sjulian"sniff, or park mode. The local Link Manager will automatically accept or\n" \ 287107120Sjulian"reject such a request from the remote device, and may even autonomously\n" \ 288107120Sjulian"request itself, depending on the value of the link policy settings parameter\n"\ 289107120Sjulian"for the corresponding connection handle. The connection handle must be a\n" \ 290107120Sjulian"connection handle for an ACL connection. Multiple Link Manager policies may\n"\ 291107120Sjulian"be specified for the link policy settings parameter by performing a bitwise\n"\ 292107120Sjulian"OR operation of the different activity types.\n\n" \ 293107120Sjulian"\t<connection_handle> - dddd; connection handle\n" \ 294107120Sjulian"\t<settings> - xxxx; settings\n" \ 295107120Sjulian"\t\t0x0000 - Disable All LM Modes (Default)\n" \ 296107120Sjulian"\t\t0x0001 - Enable Master Slave Switch\n" \ 297107120Sjulian"\t\t0x0002 - Enable Hold Mode\n" \ 298107120Sjulian"\t\t0x0004 - Enable Sniff Mode\n" \ 299107120Sjulian"\t\t0x0008 - Enable Park Mode\n", 300107120Sjulian&hci_write_link_policy_settings 301107120Sjulian}, 302107120Sjulian{ 303107120SjulianNULL, 304107120Sjulian}}; 305107120Sjulian 306