1878ed226SJulian Elischer /* 2878ed226SJulian Elischer * link_policy.c 3878ed226SJulian Elischer * 4878ed226SJulian Elischer * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5878ed226SJulian Elischer * All rights reserved. 6878ed226SJulian Elischer * 7878ed226SJulian Elischer * Redistribution and use in source and binary forms, with or without 8878ed226SJulian Elischer * modification, are permitted provided that the following conditions 9878ed226SJulian Elischer * are met: 10878ed226SJulian Elischer * 1. Redistributions of source code must retain the above copyright 11878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer. 12878ed226SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 13878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer in the 14878ed226SJulian Elischer * documentation and/or other materials provided with the distribution. 15878ed226SJulian Elischer * 16878ed226SJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17878ed226SJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18878ed226SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19878ed226SJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20878ed226SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21878ed226SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22878ed226SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23878ed226SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24878ed226SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25878ed226SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26878ed226SJulian Elischer * SUCH DAMAGE. 27878ed226SJulian Elischer * 280986ab12SMaksim Yevmenkin * $Id: link_policy.c,v 1.3 2003/08/18 19:19:54 max Exp $ 29878ed226SJulian Elischer * $FreeBSD$ 30878ed226SJulian Elischer */ 31878ed226SJulian Elischer 320986ab12SMaksim Yevmenkin #include <bluetooth.h> 33878ed226SJulian Elischer #include <errno.h> 34878ed226SJulian Elischer #include <stdio.h> 350986ab12SMaksim Yevmenkin #include <string.h> 36878ed226SJulian Elischer #include "hccontrol.h" 37878ed226SJulian Elischer 38878ed226SJulian Elischer /* Send Role Discovery to the unit */ 39878ed226SJulian Elischer static int 40878ed226SJulian Elischer hci_role_discovery(int s, int argc, char **argv) 41878ed226SJulian Elischer { 42878ed226SJulian Elischer ng_hci_role_discovery_cp cp; 43878ed226SJulian Elischer ng_hci_role_discovery_rp rp; 44878ed226SJulian Elischer int n; 45878ed226SJulian Elischer 46878ed226SJulian Elischer /* parse command parameters */ 47878ed226SJulian Elischer switch (argc) { 48878ed226SJulian Elischer case 1: 49878ed226SJulian Elischer /* connection handle */ 50878ed226SJulian Elischer if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) 51878ed226SJulian Elischer return (USAGE); 52878ed226SJulian Elischer 53079a8a3eSMaksim Yevmenkin cp.con_handle = (uint16_t) (n & 0x0fff); 54878ed226SJulian Elischer cp.con_handle = htole16(cp.con_handle); 55878ed226SJulian Elischer break; 56878ed226SJulian Elischer 57878ed226SJulian Elischer default: 58878ed226SJulian Elischer return (USAGE); 59878ed226SJulian Elischer } 60878ed226SJulian Elischer 61878ed226SJulian Elischer /* send request */ 62878ed226SJulian Elischer n = sizeof(rp); 63878ed226SJulian Elischer if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 64878ed226SJulian Elischer NG_HCI_OCF_ROLE_DISCOVERY), 65878ed226SJulian Elischer (char const *) &cp, sizeof(cp), 66878ed226SJulian Elischer (char *) &rp, &n) == ERROR) 67878ed226SJulian Elischer return (ERROR); 68878ed226SJulian Elischer 69878ed226SJulian Elischer if (rp.status != 0x00) { 70878ed226SJulian Elischer fprintf(stdout, "Status: %s [%#02x]\n", 71878ed226SJulian Elischer hci_status2str(rp.status), rp.status); 72878ed226SJulian Elischer return (FAILED); 73878ed226SJulian Elischer } 74878ed226SJulian Elischer 75878ed226SJulian Elischer fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle)); 76878ed226SJulian Elischer fprintf(stdout, "Role: %s [%#x]\n", 77878ed226SJulian Elischer (rp.role == NG_HCI_ROLE_MASTER)? "Master" : "Slave", rp.role); 78878ed226SJulian Elischer 79878ed226SJulian Elischer return (OK); 80878ed226SJulian Elischer } /* hci_role_discovery */ 81878ed226SJulian Elischer 82878ed226SJulian Elischer /* Send Swith Role to the unit */ 83878ed226SJulian Elischer static int 84878ed226SJulian Elischer hci_switch_role(int s, int argc, char **argv) 85878ed226SJulian Elischer { 860986ab12SMaksim Yevmenkin int n0; 87878ed226SJulian Elischer char b[512]; 88878ed226SJulian Elischer ng_hci_switch_role_cp cp; 89878ed226SJulian Elischer ng_hci_event_pkt_t *e = (ng_hci_event_pkt_t *) b; 90878ed226SJulian Elischer 91878ed226SJulian Elischer /* parse command parameters */ 92878ed226SJulian Elischer switch (argc) { 93878ed226SJulian Elischer case 2: 94878ed226SJulian Elischer /* bdaddr */ 950986ab12SMaksim Yevmenkin if (!bt_aton(argv[0], &cp.bdaddr)) { 960986ab12SMaksim Yevmenkin struct hostent *he = NULL; 970986ab12SMaksim Yevmenkin 980986ab12SMaksim Yevmenkin if ((he = bt_gethostbyname(argv[0])) == NULL) 99878ed226SJulian Elischer return (USAGE); 100878ed226SJulian Elischer 1010986ab12SMaksim Yevmenkin memcpy(&cp.bdaddr, he->h_addr, sizeof(cp.bdaddr)); 1020986ab12SMaksim Yevmenkin } 103878ed226SJulian Elischer 104878ed226SJulian Elischer /* role */ 105878ed226SJulian Elischer if (sscanf(argv[1], "%d", &n0) != 1) 106878ed226SJulian Elischer return (USAGE); 107878ed226SJulian Elischer 108878ed226SJulian Elischer cp.role = n0? NG_HCI_ROLE_SLAVE : NG_HCI_ROLE_MASTER; 109878ed226SJulian Elischer break; 110878ed226SJulian Elischer 111878ed226SJulian Elischer default: 112878ed226SJulian Elischer return (USAGE); 113878ed226SJulian Elischer } 114878ed226SJulian Elischer 115878ed226SJulian Elischer /* send request and expect status response */ 116878ed226SJulian Elischer n0 = sizeof(b); 117878ed226SJulian Elischer if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 118878ed226SJulian Elischer NG_HCI_OCF_SWITCH_ROLE), 119878ed226SJulian Elischer (char const *) &cp, sizeof(cp), b, &n0) == ERROR) 120878ed226SJulian Elischer return (ERROR); 121878ed226SJulian Elischer 122878ed226SJulian Elischer if (*b != 0x00) 123878ed226SJulian Elischer return (FAILED); 124878ed226SJulian Elischer 125878ed226SJulian Elischer /* wait for event */ 126878ed226SJulian Elischer again: 127878ed226SJulian Elischer n0 = sizeof(b); 128878ed226SJulian Elischer if (hci_recv(s, b, &n0) == ERROR) 129878ed226SJulian Elischer return (ERROR); 130878ed226SJulian Elischer if (n0 < sizeof(*e)) { 131878ed226SJulian Elischer errno = EIO; 132878ed226SJulian Elischer return (ERROR); 133878ed226SJulian Elischer } 134878ed226SJulian Elischer 135878ed226SJulian Elischer if (e->event == NG_HCI_EVENT_ROLE_CHANGE) { 136878ed226SJulian Elischer ng_hci_role_change_ep *ep = (ng_hci_role_change_ep *)(e + 1); 137878ed226SJulian Elischer 138878ed226SJulian Elischer if (ep->status != 0x00) { 139878ed226SJulian Elischer fprintf(stdout, "Status: %s [%#02x]\n", 140878ed226SJulian Elischer hci_status2str(ep->status), ep->status); 141878ed226SJulian Elischer return (FAILED); 142878ed226SJulian Elischer } 143878ed226SJulian Elischer 1440986ab12SMaksim Yevmenkin fprintf(stdout, "BD_ADDR: %s\n", hci_bdaddr2str(&ep->bdaddr)); 145878ed226SJulian Elischer fprintf(stdout, "Role: %s [%#x]\n", 146878ed226SJulian Elischer (ep->role == NG_HCI_ROLE_MASTER)? "Master" : "Slave", 147878ed226SJulian Elischer ep->role); 148878ed226SJulian Elischer } else 149878ed226SJulian Elischer goto again; 150878ed226SJulian Elischer 151878ed226SJulian Elischer return (OK); 152878ed226SJulian Elischer } /* hci_switch_role */ 153878ed226SJulian Elischer 154878ed226SJulian Elischer /* Send Read_Link_Policy_Settings command to the unit */ 155878ed226SJulian Elischer static int 156878ed226SJulian Elischer hci_read_link_policy_settings(int s, int argc, char **argv) 157878ed226SJulian Elischer { 158878ed226SJulian Elischer ng_hci_read_link_policy_settings_cp cp; 159878ed226SJulian Elischer ng_hci_read_link_policy_settings_rp rp; 160878ed226SJulian Elischer int n; 161878ed226SJulian Elischer 162878ed226SJulian Elischer /* parse command parameters */ 163878ed226SJulian Elischer switch (argc) { 164878ed226SJulian Elischer case 1: 165878ed226SJulian Elischer /* connection handle */ 166878ed226SJulian Elischer if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) 167878ed226SJulian Elischer return (USAGE); 168878ed226SJulian Elischer 169079a8a3eSMaksim Yevmenkin cp.con_handle = (uint16_t) (n & 0x0fff); 170878ed226SJulian Elischer cp.con_handle = htole16(cp.con_handle); 171878ed226SJulian Elischer break; 172878ed226SJulian Elischer 173878ed226SJulian Elischer default: 174878ed226SJulian Elischer return (USAGE); 175878ed226SJulian Elischer } 176878ed226SJulian Elischer 177878ed226SJulian Elischer /* send request */ 178878ed226SJulian Elischer n = sizeof(rp); 179878ed226SJulian Elischer if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 180878ed226SJulian Elischer NG_HCI_OCF_READ_LINK_POLICY_SETTINGS), 181878ed226SJulian Elischer (char const *) &cp, sizeof(cp), 182878ed226SJulian Elischer (char *) &rp, &n) == ERROR) 183878ed226SJulian Elischer return (ERROR); 184878ed226SJulian Elischer 185878ed226SJulian Elischer if (rp.status != 0x00) { 186878ed226SJulian Elischer fprintf(stdout, "Status: %s [%#02x]\n", 187878ed226SJulian Elischer hci_status2str(rp.status), rp.status); 188878ed226SJulian Elischer return (FAILED); 189878ed226SJulian Elischer } 190878ed226SJulian Elischer 191878ed226SJulian Elischer fprintf(stdout, "Connection handle: %d\n", le16toh(rp.con_handle)); 192878ed226SJulian Elischer fprintf(stdout, "Link policy settings: %#x\n", le16toh(rp.settings)); 193878ed226SJulian Elischer 194878ed226SJulian Elischer return (OK); 195878ed226SJulian Elischer } /* hci_read_link_policy_settings */ 196878ed226SJulian Elischer 197878ed226SJulian Elischer /* Send Write_Link_Policy_Settings command to the unit */ 198878ed226SJulian Elischer static int 199878ed226SJulian Elischer hci_write_link_policy_settings(int s, int argc, char **argv) 200878ed226SJulian Elischer { 201878ed226SJulian Elischer ng_hci_write_link_policy_settings_cp cp; 202878ed226SJulian Elischer ng_hci_write_link_policy_settings_rp rp; 203878ed226SJulian Elischer int n; 204878ed226SJulian Elischer 205878ed226SJulian Elischer /* parse command parameters */ 206878ed226SJulian Elischer switch (argc) { 207878ed226SJulian Elischer case 2: 208878ed226SJulian Elischer /* connection handle */ 209878ed226SJulian Elischer if (sscanf(argv[0], "%d", &n) != 1 || n <= 0 || n > 0x0eff) 210878ed226SJulian Elischer return (USAGE); 211878ed226SJulian Elischer 212079a8a3eSMaksim Yevmenkin cp.con_handle = (uint16_t) (n & 0x0fff); 213878ed226SJulian Elischer cp.con_handle = htole16(cp.con_handle); 214878ed226SJulian Elischer 215878ed226SJulian Elischer /* link policy settings */ 216878ed226SJulian Elischer if (sscanf(argv[1], "%x", &n) != 1) 217878ed226SJulian Elischer return (USAGE); 218878ed226SJulian Elischer 219079a8a3eSMaksim Yevmenkin cp.settings = (uint16_t) (n & 0x0ffff); 220878ed226SJulian Elischer cp.settings = htole16(cp.settings); 221878ed226SJulian Elischer break; 222878ed226SJulian Elischer 223878ed226SJulian Elischer default: 224878ed226SJulian Elischer return (USAGE); 225878ed226SJulian Elischer } 226878ed226SJulian Elischer 227878ed226SJulian Elischer /* send request */ 228878ed226SJulian Elischer n = sizeof(rp); 229878ed226SJulian Elischer if (hci_request(s, NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 230878ed226SJulian Elischer NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS), 231878ed226SJulian Elischer (char const *) &cp, sizeof(cp), 232878ed226SJulian Elischer (char *) &rp, &n) == ERROR) 233878ed226SJulian Elischer return (ERROR); 234878ed226SJulian Elischer 235878ed226SJulian Elischer if (rp.status != 0x00) { 236878ed226SJulian Elischer fprintf(stdout, "Status: %s [%#02x]\n", 237878ed226SJulian Elischer hci_status2str(rp.status), rp.status); 238878ed226SJulian Elischer return (FAILED); 239878ed226SJulian Elischer } 240878ed226SJulian Elischer 241878ed226SJulian Elischer return (OK); 242878ed226SJulian Elischer } /* hci_write_link_policy_settings */ 243878ed226SJulian Elischer 244878ed226SJulian Elischer struct hci_command link_policy_commands[] = { 245878ed226SJulian Elischer { 2460eff7205SMaksim Yevmenkin "role_discovery <connection_handle>", 247878ed226SJulian Elischer "\nThe Role_Discovery command is used for a Bluetooth device to determine\n" \ 248878ed226SJulian Elischer "which role the device is performing for a particular Connection Handle.\n" \ 249878ed226SJulian Elischer "The connection handle must be a connection handle for an ACL connection.\n\n" \ 250878ed226SJulian Elischer "\t<connection_handle> - dddd; connection handle", 251878ed226SJulian Elischer &hci_role_discovery 252878ed226SJulian Elischer }, 253878ed226SJulian Elischer { 2542aa65cf7SMaksim Yevmenkin "switch_role <BD_ADDR> <role>", 255878ed226SJulian Elischer "\nThe Switch_Role command is used for a Bluetooth device to switch the\n" \ 256878ed226SJulian Elischer "current role the device is performing for a particular connection with\n" \ 257878ed226SJulian Elischer "another specified Bluetooth device. The BD_ADDR command parameter indicates\n"\ 258878ed226SJulian Elischer "for which connection the role switch is to be performed. The Role indicates\n"\ 259878ed226SJulian Elischer "the requested new role that the local device performs. Note: the BD_ADDR\n" \ 260878ed226SJulian Elischer "command parameter must specify a Bluetooth device for which a connection\n" 261878ed226SJulian Elischer "already exists.\n\n" \ 2622aa65cf7SMaksim Yevmenkin "\t<BD_ADDR> - xx:xx:xx:xx:xx:xx BD_ADDR or name\n" \ 263878ed226SJulian Elischer "\t<role> - dd; role; 0 - Master, 1 - Slave", 264878ed226SJulian Elischer &hci_switch_role 265878ed226SJulian Elischer }, 266878ed226SJulian Elischer { 267878ed226SJulian Elischer "read_link_policy_settings <connection_handle>", 268878ed226SJulian Elischer "\nThis command will read the Link Policy setting for the specified connection\n"\ 269878ed226SJulian Elischer "handle. The link policy settings parameter determines the behavior of the\n" \ 270878ed226SJulian Elischer "local Link Manager when it receives a request from a remote device or it\n" \ 271878ed226SJulian Elischer "determines itself to change the master-slave role or to enter the hold,\n" \ 272878ed226SJulian Elischer "sniff, or park mode. The local Link Manager will automatically accept or\n" \ 273878ed226SJulian Elischer "reject such a request from the remote device, and may even autonomously\n" \ 274878ed226SJulian Elischer "request itself, depending on the value of the link policy settings parameter\n"\ 275878ed226SJulian Elischer "for the corresponding connection handle. The connection handle must be a\n" \ 276878ed226SJulian Elischer "connection handle for an ACL connection.\n\n" \ 277878ed226SJulian Elischer "\t<connection_handle> - dddd; connection handle", 278878ed226SJulian Elischer &hci_read_link_policy_settings 279878ed226SJulian Elischer }, 280878ed226SJulian Elischer { 281878ed226SJulian Elischer "write_link_policy_settings <connection_handle> <settings>", 282878ed226SJulian Elischer "\nThis command will write the Link Policy setting for the specified connection\n"\ 283878ed226SJulian Elischer "handle. The link policy settings parameter determines the behavior of the\n" \ 284878ed226SJulian Elischer "local Link Manager when it receives a request from a remote device or it\n" \ 285878ed226SJulian Elischer "determines itself to change the master-slave role or to enter the hold,\n" \ 286878ed226SJulian Elischer "sniff, or park mode. The local Link Manager will automatically accept or\n" \ 287878ed226SJulian Elischer "reject such a request from the remote device, and may even autonomously\n" \ 288878ed226SJulian Elischer "request itself, depending on the value of the link policy settings parameter\n"\ 289878ed226SJulian Elischer "for the corresponding connection handle. The connection handle must be a\n" \ 290878ed226SJulian Elischer "connection handle for an ACL connection. Multiple Link Manager policies may\n"\ 291878ed226SJulian Elischer "be specified for the link policy settings parameter by performing a bitwise\n"\ 292878ed226SJulian Elischer "OR operation of the different activity types.\n\n" \ 293878ed226SJulian Elischer "\t<connection_handle> - dddd; connection handle\n" \ 294878ed226SJulian Elischer "\t<settings> - xxxx; settings\n" \ 295878ed226SJulian Elischer "\t\t0x0000 - Disable All LM Modes (Default)\n" \ 296878ed226SJulian Elischer "\t\t0x0001 - Enable Master Slave Switch\n" \ 297878ed226SJulian Elischer "\t\t0x0002 - Enable Hold Mode\n" \ 298878ed226SJulian Elischer "\t\t0x0004 - Enable Sniff Mode\n" \ 299878ed226SJulian Elischer "\t\t0x0008 - Enable Park Mode\n", 300878ed226SJulian Elischer &hci_write_link_policy_settings 301878ed226SJulian Elischer }, 302878ed226SJulian Elischer { 303878ed226SJulian Elischer NULL, 304878ed226SJulian Elischer }}; 305878ed226SJulian Elischer 306